THIS IS A PATCH FOR PERL 4.0. DO NOT APPLY THIS PATCH TO PERL 5.0. (See the corresponding Perl 5.0 patch instead.) Directions: cd your_perl4_source_directory patch -N c_filestab = fstab(origfilename); if (strEQ(origfilename,"-")) scriptname = ""; ! if (preprocess) { char *cpp = CPPSTDIN; if (strEQ(cpp,"cppstdin")) --- 346,372 ---- fdpid = anew(Nullstab); /* for remembering popen pids by fd */ pidstatus = hnew(COEFFSIZE);/* for remembering status of dead pids */ + if (strnEQ(scriptname, "/dev/fd/", 8) && isDIGIT(scriptname[8]) ) { + char *s = scriptname + 8; + fdscript = atoi(s); + while (isDIGIT(*s)) + s++; + if (*s) + scriptname = s + 1; + } + else + fdscript = -1; origfilename = savestr(scriptname); curcmd->c_filestab = fstab(origfilename); if (strEQ(origfilename,"-")) scriptname = ""; ! if (fdscript >= 0) { ! rsfp = fdopen(fdscript,"r"); ! #if defined(HAS_FCNTL) && defined(F_SETFD) ! fcntl(fileno(rsfp),F_SETFD,1); /* ensure close-on-exec */ ! #endif ! } ! else if (preprocess) { char *cpp = CPPSTDIN; if (strEQ(cpp,"cppstdin")) *************** *** 425,432 **** #endif rsfp = stdin; } ! else rsfp = fopen(scriptname,"r"); if ((FILE*)rsfp == Nullfp) { #ifdef DOSUID #ifndef IAMSUID /* in case script is not readable before setuid */ --- 443,454 ---- #endif rsfp = stdin; } ! else { rsfp = fopen(scriptname,"r"); + #if defined(HAS_FCNTL) && defined(F_SETFD) + fcntl(fileno(rsfp),F_SETFD,1); /* ensure close-on-exec */ + #endif + } if ((FILE*)rsfp == Nullfp) { #ifdef DOSUID #ifndef IAMSUID /* in case script is not readable before setuid */ *************** *** 474,480 **** #ifdef DOSUID if (fstat(fileno(rsfp),&statbuf) < 0) /* normal stat is insecure */ fatal("Can't stat script \"%s\"",origfilename); ! if (statbuf.st_mode & (S_ISUID|S_ISGID)) { int len; #ifdef IAMSUID --- 496,502 ---- #ifdef DOSUID if (fstat(fileno(rsfp),&statbuf) < 0) /* normal stat is insecure */ fatal("Can't stat script \"%s\"",origfilename); ! if (fdscript < 0 && statbuf.st_mode & (S_ISUID|S_ISGID)) { int len; #ifdef IAMSUID *************** *** 617,624 **** --- 639,666 ---- #ifdef IAMSUID else if (preprocess) fatal("-P not allowed for setuid/setgid script\n"); + else if (fdscript >= 0) + fatal("fd script not allowed in suidperl\n"); else fatal("Script is not setuid/setgid in suidperl\n"); + + /* We absolutely must clear out any saved ids here, so we */ + /* exec taintperl, substituting fd script for scriptname. */ + /* (We pass script name as "subdir" of fd, which taintperl will grok.) */ + rewind(rsfp); + for (which = 1; origargv[which] && origargv[which] != scriptname; which++) ; + if (!origargv[which]) + fatal("Permission denied"); + (void)sprintf(buf, "/dev/fd/%d/%.127s", fileno(rsfp), origargv[which]); + origargv[which] = buf; + + #if defined(HAS_FCNTL) && defined(F_SETFD) + fcntl(fileno(rsfp),F_SETFD,0); /* ensure no close-on-exec */ + #endif + + (void)sprintf(tokenbuf, "%s/tperl%s", BIN, patchlevel); + execv(tokenbuf, origargv); /* try again */ + fatal("Can't do setuid\n"); #else #ifndef TAINT /* we aren't taintperl or suidperl */ /* script has a wrapper--can't run suidperl or we lose euid */ *************** *** 1376,1381 **** --- 1418,1424 ---- case 'v': fputs("\nThis is perl, version 4.0\n\n",stdout); fputs(rcsid,stdout); + fputs("+ suidperl security patch\n", stdout); fputs("\nCopyright (c) 1989, 1990, 1991, Larry Wall\n",stdout); #ifdef MSDOS fputs("MS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n", *************** *** 1443,1446 **** #endif /* ! MSDOS */ #endif } - --- 1486,1488 ---- END OF PATCH