lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (11/19/88)
System: perl version 2.0 Patch #: 17 Priority: MEDIUM Subject: patch 16 continued Description: See patch 16. Fix: From rn, say "| patch -p -N -d DIR", where DIR is your perl source directory. Outside of rn, say "cd DIR; patch -p -N <thisarticle". If you don't have the patch program, apply the following by hand, or get patch (version 2.0, latest patchlevel). After patching: Configure -d make depend make make test make install If patch indicates that patchlevel is the wrong version, you may need to apply one or more previous patches, or the patch may already have been applied. See the patchlevel.h file to find out what has or has not been applied. In any event, don't continue with the patch. If you are missing previous patches they can be obtained from me: Larry Wall lwall@jpl-devvax.jpl.nasa.gov If you send a mail message of the following form it will greatly speed processing: Subject: Command @SH mailpatch PATH perl 2.0 LIST ^ note the c where PATH is a return path FROM ME TO YOU either in Internet notation, or in bang notation from some well-known host, and LIST is the number of one or more patches you need, separated by spaces, commas, and/or hyphens. Saying 35- says everything from 35 to the end. You can also get the patches via anonymous FTP from jpl-devvax.jpl.nasa.gov (128.149.8.43). Index: patchlevel.h Prereq: 16 1c1 < #define PATCHLEVEL 16 --- > #define PATCHLEVEL 17 Index: perl.y Prereq: 2.0.1.5 *** perl.y.old Sat Nov 19 00:34:19 1988 --- perl.y Sat Nov 19 00:34:22 1988 *************** *** 1,6 **** ! /* $Header: perl.y,v 2.0.1.5 88/10/31 16:42:23 lwall Exp $ * * $Log: perl.y,v $ * Revision 2.0.1.5 88/10/31 16:42:23 lwall * patch15: printf "%%" is now more consistent * --- 1,9 ---- ! /* $Header: perl.y,v 2.0.1.6 88/11/19 00:04:01 lwall Locked $ * * $Log: perl.y,v $ + * Revision 2.0.1.6 88/11/19 00:04:01 lwall + * patch16: added getc function + * * Revision 2.0.1.5 88/10/31 16:42:23 lwall * patch15: printf "%%" is now more consistent * *************** *** 78,84 **** %token <ival> APPEND OPEN WRITE SELECT CLOSE LOOPEX %token <ival> USING FORMAT DO SHIFT PUSH POP LVALFUN %token <ival> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT SPRINTF ! %token <ival> FOR FEOF TELL SEEK STAT %token <ival> FUNC0 FUNC1 FUNC2 FUNC3 STABFUN %token <ival> JOIN SUB FILETEST LOCAL DELETE %token <ival> RELOP EQOP MULOP ADDOP --- 81,87 ---- %token <ival> APPEND OPEN WRITE SELECT CLOSE LOOPEX %token <ival> USING FORMAT DO SHIFT PUSH POP LVALFUN %token <ival> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT SPRINTF ! %token <ival> FOR FILOP TELL SEEK STAT %token <ival> FUNC0 FUNC1 FUNC2 FUNC3 STABFUN %token <ival> JOIN SUB FILETEST LOCAL DELETE %token <ival> RELOP EQOP MULOP ADDOP *************** *** 533,552 **** { $$ = make_op(O_CLOSE, 1, stab2arg(A_WORD,stabent($2,TRUE)), Nullarg, Nullarg,0); } ! | FEOF '(' WORD ')' ! { $$ = make_op(O_EOF, 1, stab2arg(A_WORD,stabent($3,TRUE)), Nullarg, Nullarg,0); } ! | FEOF '(' expr ')' ! { $$ = make_op(O_EOF, 1, $3, Nullarg, Nullarg,0); } ! | FEOF '(' ')' ! { $$ = make_op(O_EOF, 1, stab2arg(A_WORD,Nullstab), Nullarg, Nullarg,0); } ! | FEOF ! { $$ = make_op(O_EOF, 0, Nullarg, Nullarg, Nullarg,0); } | TELL '(' WORD ')' { $$ = make_op(O_TELL, 1, --- 536,555 ---- { $$ = make_op(O_CLOSE, 1, stab2arg(A_WORD,stabent($2,TRUE)), Nullarg, Nullarg,0); } ! | FILOP '(' WORD ')' ! { $$ = make_op($1, 1, stab2arg(A_WORD,stabent($3,TRUE)), Nullarg, Nullarg,0); } ! | FILOP '(' expr ')' ! { $$ = make_op($1, 1, $3, Nullarg, Nullarg,0); } ! | FILOP '(' ')' ! { $$ = make_op($1, 1, stab2arg(A_WORD,Nullstab), Nullarg, Nullarg,0); } ! | FILOP ! { $$ = make_op($1, 0, Nullarg, Nullarg, Nullarg,0); } | TELL '(' WORD ')' { $$ = make_op(O_TELL, 1, Index: perly.c Prereq: 2.0.1.8 *** perly.c.old Sat Nov 19 00:34:37 1988 --- perly.c Sat Nov 19 00:34:43 1988 *************** *** 1,6 **** ! char rcsid[] = "$Header: perly.c,v 2.0.1.8 88/10/31 16:44:49 lwall Exp $"; /* * $Log: perly.c,v $ * Revision 2.0.1.8 88/10/31 16:44:49 lwall * patch15: now suppresses -S if / is anywhere in script name. * patch15: some support for defective 286 compilers --- 1,15 ---- ! char rcsid[] = "$Header: perly.c,v 2.0.1.9 88/11/19 00:14:36 lwall Locked $\nPatch level: ###\n"; /* * $Log: perly.c,v $ + * Revision 2.0.1.9 88/11/19 00:14:36 lwall + * patch16: added $] to return rcsid and patchlevel + * patch16: added code to check for kernel setuid script bug + * patch16: "taint" checks for setuid scripts + * patch16: added redundant prohibitions on certain switches in setuid scripts + * patch16: now makes use of setre[ug]id() if available + * patch16: replaced insecure access() + * patch16: doesn't blow up finding suidperl on bad PATH now + * * Revision 2.0.1.8 88/10/31 16:44:49 lwall * patch15: now suppresses -S if / is anywhere in script name. * patch15: some support for defective 286 compilers *************** *** 60,65 **** --- 69,75 ---- #include "EXTERN.h" #include "perl.h" #include "perly.h" + #include "patchlevel.h" #ifdef IAMSUID #ifndef DOSUID *************** *** 67,72 **** --- 77,83 ---- #endif #endif + extern char *tokename[]; extern int yychar; *************** *** 76,81 **** --- 87,98 ---- static bool saw_return; + #ifdef SETUID_SCRIPTS_ARE_SECURE_NOW + #ifdef DOSUID + #undef DOSUID + #endif + #endif + main(argc,argv,env) register int argc; register char **argv; *************** *** 89,95 **** --- 106,123 ---- char **origargv = argv; char *validarg = ""; #endif + int gid = (int)getgid(); + int egid = (int)getegid(); + #ifdef SETUID_SCRIPTS_ARE_SECURE_NOW + #ifdef IAMSUID + #undef IAMSUID + fatal("suidperl is no longer needed since the kernel can now execute\n\ + setuid perl scripts securely.\n"); + #endif + #endif + + sprintf(index(rcsid,'#'), "%d\n", PATCHLEVEL); uid = (int)getuid(); euid = (int)geteuid(); linestr = str_new(80); *************** *** 114,119 **** --- 142,151 ---- goto reswitch; #ifdef DEBUGGING case 'D': + #ifdef TAINT + if (euid != uid || egid != gid) + fatal("No -D allowed in setuid scripts"); + #endif debug = atoi(s+1); #ifdef YYDEBUG yydebug = (debug & 1); *************** *** 121,126 **** --- 153,162 ---- break; #endif case 'e': + #ifdef TAINT + if (euid != uid || egid != gid) + fatal("No -e allowed in setuid scripts"); + #endif if (!e_fp) { e_tmpname = strcpy(safemalloc(sizeof(TMPPATH)),TMPPATH); mktemp(e_tmpname); *************** *** 136,141 **** --- 172,181 ---- argvoutstab = stabent("ARGVOUT",TRUE); break; case 'I': + #ifdef TAINT + if (euid != uid || egid != gid) + fatal("No -I allowed in setuid scripts"); + #endif str_cat(str,"-"); str_cat(str,s); str_cat(str," "); *************** *** 158,167 **** --- 198,215 ---- s++; goto reswitch; case 'P': + #ifdef TAINT + if (euid != uid || egid != gid) + fatal("No -P allowed in setuid scripts"); + #endif preprocess = TRUE; s++; goto reswitch; case 's': + #ifdef TAINT + if (euid != uid || egid != gid) + fatal("No -s allowed in setuid scripts"); + #endif doswitches = TRUE; s++; goto reswitch; *************** *** 174,180 **** s++; goto reswitch; case 'v': ! version(); exit(0); case 'w': dowarn = TRUE; --- 222,228 ---- s++; goto reswitch; case 'v': ! fputs(rcsid,stdout); exit(0); case 'w': dowarn = TRUE; *************** *** 257,270 **** -e 's/^#.*//' \ %s | %s -C %s %s", argv[0], CPPSTDIN, str_get(str), CPPMINUS); ! #ifdef IAMSUID if (euid != uid && !euid) /* if running suidperl */ #ifdef SETEUID seteuid(uid); /* musn't stay setuid root */ #else setuid(uid); #endif #endif rsfp = popen(buf,"r"); } else if (!*argv[0]) --- 305,322 ---- -e 's/^#.*//' \ %s | %s -C %s %s", argv[0], CPPSTDIN, str_get(str), CPPMINUS); ! #ifdef IAMSUID /* actually, this is caught earlier */ if (euid != uid && !euid) /* if running suidperl */ #ifdef SETEUID seteuid(uid); /* musn't stay setuid root */ #else + #ifdef SETREUID + setreuid(-1, uid); + #else setuid(uid); #endif #endif + #endif /* IAMSUID */ rsfp = popen(buf,"r"); } else if (!*argv[0]) *************** *** 273,282 **** rsfp = fopen(argv[0],"r"); if (rsfp == Nullfp) { #ifdef DOSUID ! #ifndef IAMSUID if (euid && stat(filename,&statbuf) >= 0 && statbuf.st_mode & (S_ISUID|S_ISGID)) { ! execvp("suidperl", origargv); /* try again */ fatal("Can't do setuid\n"); } #endif --- 325,335 ---- rsfp = fopen(argv[0],"r"); if (rsfp == Nullfp) { #ifdef DOSUID ! #ifndef IAMSUID /* in case script is not readable before setuid */ if (euid && stat(filename,&statbuf) >= 0 && statbuf.st_mode & (S_ISUID|S_ISGID)) { ! sprintf(buf, "%s/%s", BIN, "suidperl"); ! execv(buf, origargv); /* try again */ fatal("Can't do setuid\n"); } #endif *************** *** 302,308 **** --- 355,369 ---- * DOSUID must be defined in both perl and suidperl, and IAMSUID must * be defined in suidperl only. suidperl must be setuid root. The * Configure script will set this up for you if you want it. + * + * There is also the possibility of have a script which is running + * set-id due to a C wrapper. We want to do the TAINT checks + * on these set-id scripts, but don't want to have the overhead of + * them in normal perl, and can't use suidperl because it will lose + * the effective uid info, so we have an additional non-setuid root + * version called taintperl that just does the TAINT checks. */ + #ifdef DOSUID if (fstat(fileno(rsfp),&statbuf) < 0) /* normal stat is insecure */ fatal("Can't stat script \"%s\"",filename); *************** *** 309,318 **** --- 370,426 ---- if (statbuf.st_mode & (S_ISUID|S_ISGID)) { int len; + #ifdef IAMSUID + #ifndef SETREUID + /* On this access check to make sure the directories are readable, + * there is actually a small window that the user could use to make + * filename point to an accessible directory. So there is a faint + * chance that someone could execute a setuid script down in a + * non-accessible directory. I don't know what to do about that. + * But I don't think it's too important. The manual lies when + * it says access() is useful in setuid programs. + */ if (access(filename,1)) /* as a double check */ fatal("Permission denied"); + #else + /* If we can swap euid and uid, then we can determine access rights + * with a simple stat of the file, and then compare device and + * inode to make sure we did stat() on the same file we opened. + * Then we just have to make sure he or she can execute it. + */ + { + struct stat tmpstatbuf; + + if (setreuid(euid,uid) < 0 || getuid() != euid || geteuid() != uid) + fatal("Can't swap uid and euid"); /* really paranoid */ + if (stat(filename,&tmpstatbuf) < 0) /* testing full pathname here */ + fatal("Permission denied"); + if (tmpstatbuf.st_dev != statbuf.st_dev || + tmpstatbuf.st_ino != statbuf.st_ino) { + close(rsfp); + if (rsfp = popen("/bin/mail root","w")) { /* heh, heh */ + fprintf(rsfp, + "User %d tried to run dev %d ino %d in place of dev %d ino %d!\n\ + (Filename of set-id script was %s, uid %d gid %d.)\n\nSincerely,\nperl\n", + uid,tmpstatbuf.st_dev, tmpstatbuf.st_ino, + statbuf.st_dev, statbuf.st_ino, + filename, statbuf.st_uid, statbuf.st_gid); + fclose(rsfp); + } + fatal("Permission denied\n"); + } + if (setreuid(uid,euid) < 0 || getuid() != uid || geteuid() != euid) + fatal("Can't reswap uid and euid"); + if (!cando(S_IEXEC,FALSE)) /* can real uid exec? */ + fatal("Permission denied\n"); + } + #endif /* SETREUID */ + #endif /* IAMSUID */ + if ((statbuf.st_mode & S_IFMT) != S_IFREG) fatal("Permission denied"); + if ((statbuf.st_mode >> 6) & S_IWRITE) + fatal("Setuid/gid script is writable by world"); doswitches = FALSE; /* -s is insecure in suid */ line++; if (fgets(tokenbuf,sizeof tokenbuf, rsfp) == Nullch || *************** *** 332,341 **** strnNE(s,validarg,len) || !isspace(s[len])) fatal("Args must match #! line"); if (euid) { /* oops, we're not the setuid root perl */ fclose(rsfp); #ifndef IAMSUID ! execvp("suidperl", origargv); /* try again */ #endif fatal("Can't do setuid\n"); } --- 440,457 ---- strnNE(s,validarg,len) || !isspace(s[len])) fatal("Args must match #! line"); + #ifndef IAMSUID + if (euid != uid && (statbuf.st_mode & S_ISUID) && + euid == statbuf.st_uid) + fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\ + FIX YOUR KERNEL OR PUT A C WRAPPER AROUND THIS SCRIPT!\n"); + #endif /* IAMSUID */ + if (euid) { /* oops, we're not the setuid root perl */ fclose(rsfp); #ifndef IAMSUID ! sprintf(buf, "%s/%s", BIN, "suidperl"); ! execv(buf, origargv); /* try again */ #endif fatal("Can't do setuid\n"); } *************** *** 344,365 **** --- 460,493 ---- #ifdef SETEGID setegid(statbuf.st_gid); #else + #ifdef SETREGID + setregid(-1,statbuf.st_gid); + #else setgid(statbuf.st_gid); #endif + #endif if (statbuf.st_mode & S_ISUID) { if (statbuf.st_uid != euid) #ifdef SETEUID seteuid(statbuf.st_uid); /* all that for this */ #else + #ifdef SETREUID + setreuid(-1,statbuf.st_uid); + #else setuid(statbuf.st_uid); #endif + #endif } else if (uid) /* oops, mustn't run as root */ #ifdef SETEUID seteuid(uid); #else + #ifdef SETREUID + setreuid(-1,uid); + #else setuid(uid); #endif + #endif euid = (int)geteuid(); if (!cando(S_IEXEC,TRUE)) fatal("Permission denied\n"); /* they can't do this */ *************** *** 369,375 **** --- 497,532 ---- fatal("-P not allowed for setuid/setgid script\n"); else fatal("Script is not setuid/setgid in suidperl\n"); + #else + #ifndef TAINT /* we aren't taintperl or suidperl */ + /* script has a wrapper--can't run suidperl or we lose euid */ + else if (euid != uid || egid != gid) { + fclose(rsfp); + sprintf(buf, "%s/%s", BIN, "taintperl"); + execv(buf, origargv); /* try again */ + fatal("Can't run setuid script with taint checks"); + } + #endif /* TAINT */ #endif /* IAMSUID */ + #else /* !DOSUID */ + #ifndef TAINT /* we aren't taintperl or suidperl */ + if (euid != uid || egid != gid) { /* (suidperl doesn't exist, in fact) */ + #ifndef SETUID_SCRIPTS_ARE_SECURE_NOW + fstat(fileno(rsfp),&statbuf); /* may be either wrapped or real suid */ + if ((euid != uid && euid == statbuf.st_uid && statbuf.st_mode & S_ISUID) + || + (egid != gid && egid == statbuf.st_gid && statbuf.st_mode & S_ISGID) + ) + fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\ + FIX YOUR KERNEL OR PUT A C WRAPPER AROUND THIS SCRIPT!\n"); + #endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */ + /* not set-id, must be wrapped */ + fclose(rsfp); + sprintf(buf, "%s/%s", BIN, "taintperl"); + execv(buf, origargv); /* try again */ + fatal("Can't run setuid script with taint checks"); + } + #endif /* TAINT */ #endif /* DOSUID */ defstab = stabent("_",TRUE); *************** *** 378,384 **** bufptr = str_get(linestr); ! /* now parse the report spec */ if (yyparse()) fatal("Execution aborted due to compilation errors.\n"); --- 535,541 ---- bufptr = str_get(linestr); ! /* now parse the script */ if (yyparse()) fatal("Execution aborted due to compilation errors.\n"); *************** *** 403,408 **** --- 560,568 ---- str_numset(stabent(argv[0]+1,TRUE)->stab_val,(double)1.0); } } + #ifdef TAINT + tainted = 1; + #endif if (argvstab = stabent("ARGV",allstabs)) { aadd(argvstab); for (; argc > 0; argc--,argv++) { *************** *** 421,426 **** --- 581,589 ---- *--s = '='; } } + #ifdef TAINT + tainted = 0; + #endif if (sigstab = stabent("SIG",allstabs)) hadd(sigstab); *************** *** 434,443 **** --- 597,614 ---- /* these aren't necessarily magical */ if (tmpstab = stabent(";",allstabs)) str_set(STAB_STR(tmpstab),"\034"); + #ifdef TAINT + tainted = 1; + #endif if (tmpstab = stabent("0",allstabs)) str_set(STAB_STR(tmpstab),origfilename); + #ifdef TAINT + tainted = 0; + #endif if (tmpstab = stabent("$",allstabs)) str_numset(STAB_STR(tmpstab),(double)getpid()); + if (tmpstab = stabent("]",allstabs)) + str_set(STAB_STR(tmpstab),rcsid); tmpstab = stabent("stdin",TRUE); tmpstab->stab_io = stio_new(); Index: stab.c Prereq: 2.0.1.5 *** stab.c.old Sat Nov 19 00:34:52 1988 --- stab.c Sat Nov 19 00:34:54 1988 *************** *** 1,6 **** ! /* $Header: stab.c,v 2.0.1.5 88/09/07 17:03:28 lwall Exp $ * * $Log: stab.c,v $ * Revision 2.0.1.5 88/09/07 17:03:28 lwall * patch14: attempted fix for machines where $* = 1 was failing * --- 1,10 ---- ! /* $Header: stab.c,v 2.0.1.6 88/11/19 00:19:26 lwall Locked $ * * $Log: stab.c,v $ + * Revision 2.0.1.6 88/11/19 00:19:26 lwall + * patch16: $@ now reports correct error line after do EXPR + * patch16: now makes use of setre[ug]id() if available + * * Revision 2.0.1.5 88/09/07 17:03:28 lwall * patch14: attempted fix for machines where $* = 1 was failing * *************** *** 320,355 **** errno = (int)str_gnum(str); /* will anyone ever use this? */ break; case '<': - #ifdef SETRUID uid = (int)str_gnum(str); if (setruid(uid) < 0) uid = (int)getuid(); #else fatal("setruid() not implemented"); #endif break; case '>': - #ifdef SETEUID euid = (int)str_gnum(str); if (seteuid(euid) < 0) euid = (int)geteuid(); #else fatal("seteuid() not implemented"); #endif break; case '(': #ifdef SETRGID setrgid((int)str_gnum(str)); #else fatal("setrgid() not implemented"); #endif break; case ')': #ifdef SETEGID setegid((int)str_gnum(str)); #else fatal("setegid() not implemented"); #endif break; case '.': case '+': --- 324,377 ---- errno = (int)str_gnum(str); /* will anyone ever use this? */ break; case '<': uid = (int)str_gnum(str); + #ifdef SETRUID if (setruid(uid) < 0) uid = (int)getuid(); #else + #ifdef SETREUID + if (setreuid(uid, -1) < 0) + uid = (int)getuid(); + #else fatal("setruid() not implemented"); #endif + #endif break; case '>': euid = (int)str_gnum(str); + #ifdef SETEUID if (seteuid(euid) < 0) euid = (int)geteuid(); #else + #ifdef SETREUID + if (setreuid(-1, euid) < 0) + euid = (int)geteuid(); + #else fatal("seteuid() not implemented"); #endif + #endif break; case '(': #ifdef SETRGID setrgid((int)str_gnum(str)); #else + #ifdef SETREGID + setregid((int)str_gnum(str), -1); + #else fatal("setrgid() not implemented"); #endif + #endif break; case ')': #ifdef SETEGID setegid((int)str_gnum(str)); #else + #ifdef SETREGID + setregid(-1, (int)str_gnum(str)); + #else fatal("setegid() not implemented"); #endif + #endif break; case '.': case '+': *************** *** 513,518 **** --- 535,541 ---- stab->stab_name = savestr(name); stab->stab_val = str_new(0); stab->stab_next = stab_index[*name]; + stab->stab_line = line; stab_index[*name] = stab; return stab; } *************** *** 548,554 **** continue; if (i == 'I' && strEQ(stab->stab_name, "INC")) continue; ! warn("Possible typo: %s,", stab->stab_name); } } } --- 571,578 ---- continue; if (i == 'I' && strEQ(stab->stab_name, "INC")) continue; ! line = stab->stab_line; ! warn("Possible typo: \"%s\"", stab->stab_name); } } } Index: stab.h Prereq: 2.0 *** stab.h.old Sat Nov 19 00:34:58 1988 --- stab.h Sat Nov 19 00:34:59 1988 *************** *** 1,6 **** ! /* $Header: stab.h,v 2.0 88/06/05 00:11:05 root Exp $ * * $Log: stab.h,v $ * Revision 2.0 88/06/05 00:11:05 root * Baseline version 2.0. * --- 1,9 ---- ! /* $Header: stab.h,v 2.0.1.1 88/11/19 00:20:26 lwall Locked $ * * $Log: stab.h,v $ + * Revision 2.0.1.1 88/11/19 00:20:26 lwall + * patch16: added stab_line field + * * Revision 2.0 88/06/05 00:11:05 root * Baseline version 2.0. * *************** *** 7,20 **** */ struct stab { ! struct stab *stab_next; ! char *stab_name; ! STR *stab_val; ! struct stio *stab_io; ! FCMD *stab_form; ! ARRAY *stab_array; ! HASH *stab_hash; ! SUBR *stab_sub; char stab_flags; }; --- 10,24 ---- */ struct stab { ! struct stab *stab_next; /* next symbol table entry under this letter */ ! char *stab_name; /* name of symbol */ ! STR *stab_val; /* scalar value */ ! struct stio *stab_io; /* filehandle value */ ! FCMD *stab_form; /* format value */ ! ARRAY *stab_array; /* array value */ ! HASH *stab_hash; /* associative array value */ ! SUBR *stab_sub; /* subroutine value */ ! short stab_line; /* line first declared at (for -w) */ char stab_flags; }; *************** *** 23,37 **** struct stio { FILE *fp; ! long lines; ! long page; ! long page_len; ! long lines_left; ! char *top_name; ! STAB *top_stab; ! char *fmt_name; ! STAB *fmt_stab; ! short subprocess; char type; char flags; }; --- 27,41 ---- struct stio { FILE *fp; ! long lines; /* $. */ ! long page; /* $% */ ! long page_len; /* $= */ ! long lines_left; /* $- */ ! char *top_name; /* $^ */ ! STAB *top_stab; /* $^ */ ! char *fmt_name; /* $~ */ ! STAB *fmt_stab; /* $~ */ ! short subprocess; /* -| or |- */ char type; char flags; }; Index: str.c Prereq: 2.0.1.3 *** str.c.old Sat Nov 19 00:35:04 1988 --- str.c Sat Nov 19 00:35:05 1988 *************** *** 1,6 **** ! /* $Header: str.c,v 2.0.1.3 88/08/03 22:39:56 root Exp $ * * $Log: str.c,v $ * Revision 2.0.1.3 88/08/03 22:39:56 root * patch11: support for incompetent compilers that can't parse str_get macro * --- 1,9 ---- ! /* $Header: str.c,v 2.0.1.4 88/11/19 00:21:57 lwall Locked $ * * $Log: str.c,v $ + * Revision 2.0.1.4 88/11/19 00:21:57 lwall + * patch16: "taint" checks for setuid scripts + * * Revision 2.0.1.3 88/08/03 22:39:56 root * patch11: support for incompetent compilers that can't parse str_get macro * *************** *** 25,30 **** --- 28,36 ---- str_get(str) STR *str; { + #ifdef TAINT + tainted |= str->str_tainted; + #endif return str->str_pok ? str->str_ptr : str_2ptr(str); } #endif *************** *** 58,63 **** --- 64,72 ---- str = stab->stab_val; str->str_cur = 0; str->str_nok = 0; + #ifdef TAINT + str->str_tainted = tainted; + #endif if (str->str_ptr != Nullch) str->str_ptr[0] = '\0'; if (stab->stab_array) { *************** *** 80,85 **** --- 89,97 ---- str->str_nval = num; str->str_pok = 0; /* invalidate pointer */ str->str_nok = 1; /* validate number */ + #ifdef TAINT + str->str_tainted = tainted; + #endif } extern int errno; *************** *** 148,153 **** --- 160,168 ---- STR *dstr; register STR *sstr; { + #ifdef TAINT + tainted |= sstr->str_tainted; + #endif if (!sstr) str_nset(dstr,No,0); else if (sstr->str_nok) *************** *** 169,174 **** --- 184,192 ---- *(str->str_ptr+str->str_cur) = '\0'; str->str_nok = 0; /* invalidate number */ str->str_pok = 1; /* validate pointer */ + #ifdef TAINT + str->str_tainted = tainted; + #endif } str_set(str,ptr) *************** *** 185,190 **** --- 203,211 ---- str->str_cur = len; str->str_nok = 0; /* invalidate number */ str->str_pok = 1; /* validate pointer */ + #ifdef TAINT + str->str_tainted = tainted; + #endif } str_chop(str,ptr) /* like set but assuming ptr is in str */ *************** *** 212,217 **** --- 233,241 ---- *(str->str_ptr+str->str_cur) = '\0'; str->str_nok = 0; /* invalidate number */ str->str_pok = 1; /* validate pointer */ + #ifdef TAINT + str->str_tainted |= tainted; + #endif } str_scat(dstr,sstr) *************** *** 218,223 **** --- 242,250 ---- STR *dstr; register STR *sstr; { + #ifdef TAINT + tainted |= sstr->str_tainted; + #endif if (!sstr) return; if (!(sstr->str_pok)) *************** *** 242,247 **** --- 269,277 ---- str->str_cur += len; str->str_nok = 0; /* invalidate number */ str->str_pok = 1; /* validate pointer */ + #ifdef TAINT + str->str_tainted |= tainted; + #endif } char * *************** *** 326,331 **** --- 356,364 ---- str->str_pok = nstr->str_pok; if (str->str_nok = nstr->str_nok) str->str_nval = nstr->str_nval; + #ifdef TAINT + str->str_tainted = nstr->str_tainted; + #endif safefree((char*)nstr); } *************** *** 340,345 **** --- 373,381 ---- str->str_cur = 0; str->str_nok = 0; str->str_pok = 0; + #ifdef TAINT + str->str_tainted = 0; + #endif str->str_link.str_next = freestrroot; freestrroot = str; } *************** *** 587,589 **** --- 623,658 ---- str_numset(str,n); return str; } + + #ifdef TAINT + taintproper(s) + char *s; + { + #ifdef DEBUGGING + if (debug & 2048) + fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid); + #endif + if (tainted && (!euid || euid != uid)) { + if (!unsafe) + fatal("%s", s); + else if (dowarn) + warn("%s", s); + } + } + + taintenv() + { + register STR *envstr; + + envstr = hfetch(envstab->stab_hash,"PATH"); + if (!envstr || envstr->str_tainted) { + tainted = 1; + taintproper("Insecure PATH"); + } + envstr = hfetch(envstab->stab_hash,"IFS"); + if (envstr && envstr->str_tainted) { + tainted = 1; + taintproper("Insecure IFS"); + } + } + #endif /* TAINT */ Index: str.h Prereq: 2.0.1.2 *** str.h.old Sat Nov 19 00:35:09 1988 --- str.h Sat Nov 19 00:35:10 1988 *************** *** 1,6 **** ! /* $Header: str.h,v 2.0.1.2 88/09/07 17:04:00 lwall Exp $ * * $Log: str.h,v $ * Revision 2.0.1.2 88/09/07 17:04:00 lwall * patch14: searches should now work on chars with the 128 bit set * --- 1,9 ---- ! /* $Header: str.h,v 2.0.1.3 88/11/19 00:22:40 lwall Locked $ * * $Log: str.h,v $ + * Revision 2.0.1.3 88/11/19 00:22:40 lwall + * patch16: "taint" checks for setuid scripts + * * Revision 2.0.1.2 88/09/07 17:04:00 lwall * patch14: searches should now work on chars with the 128 bit set * *************** *** 25,30 **** --- 28,36 ---- char str_nok; /* state of str_nval */ unsigned char str_rare; /* used by search strings */ unsigned char str_prev; /* also used by search strings */ + #ifdef TAINT + bool str_tainted; /* 1 if possibly under control of $< */ + #endif }; #define Nullstr Null(STR*) *************** *** 31,39 **** --- 37,52 ---- /* the following macro updates any magic values this str is associated with */ + #ifdef TAINT #define STABSET(x) \ + (x)->str_tainted |= tainted; \ if ((x)->str_link.str_magic) \ stabset((x)->str_link.str_magic,(x)) + #else + #define STABSET(x) \ + if ((x)->str_link.str_magic) \ + stabset((x)->str_link.str_magic,(x)) + #endif EXT STR **tmps_list; EXT int tmps_max INIT(-1); Index: toke.c Prereq: 2.0.1.5 *** toke.c.old Sat Nov 19 00:35:18 1988 --- toke.c Sat Nov 19 00:35:21 1988 *************** *** 1,6 **** ! /* $Header: toke.c,v 2.0.1.5 88/09/07 17:09:52 lwall Exp $ * * $Log: toke.c,v $ * Revision 2.0.1.5 88/09/07 17:09:52 lwall * patch14: added detection of "sort" not used as keyword * patch14: case insensitive search speedup --- 1,10 ---- ! /* $Header: toke.c,v 2.0.1.6 88/11/19 00:25:21 lwall Locked $ * * $Log: toke.c,v $ + * Revision 2.0.1.6 88/11/19 00:25:21 lwall + * patch16: added getc function + * patch16: variables in patterns are no longer hidden from -w typo detection + * * Revision 2.0.1.5 88/09/07 17:09:52 lwall * patch14: added detection of "sort" not used as keyword * patch14: case insensitive search speedup *************** *** 46,51 **** --- 50,56 ---- #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP) #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP) #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP) + #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP) yylex() { *************** *** 140,146 **** s++; if (*s) s++; ! line++; } else *s = '\0'; --- 145,152 ---- s++; if (*s) s++; ! if (*s) ! line++; } else *s = '\0'; *************** *** 407,413 **** UNI(O_EVAL); /* we don't know what will be used */ } if (strEQ(d,"eof")) ! TERM(FEOF); if (strEQ(d,"exp")) FUN1(O_EXP); if (strEQ(d,"each")) --- 413,419 ---- UNI(O_EVAL); /* we don't know what will be used */ } if (strEQ(d,"eof")) ! FOP(O_EOF); if (strEQ(d,"exp")) FUN1(O_EXP); if (strEQ(d,"each")) *************** *** 442,447 **** --- 448,455 ---- LOOPX(O_GOTO); if (strEQ(d,"gmtime")) FUN1(O_GMTIME); + if (strEQ(d,"getc")) + FOP(O_GETC); yylval.cval = savestr(d); OPERATOR(WORD); case 'h': case 'H': *************** *** 825,830 **** --- 833,846 ---- arg->arg_type = O_ITEM; arg[1].arg_type = A_DOUBLE; arg[1].arg_ptr.arg_str = str_make(tokenbuf); + d = scanreg(d,buf); + stabent(buf,TRUE); /* make sure it's created */ + for (; *d; d++) { + if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') { + d = scanreg(d,buf); + stabent(buf,TRUE); + } + } goto got_pat; /* skip compiling for now */ } } *************** *** 895,900 **** --- 911,924 ---- arg->arg_type = O_ITEM; arg[1].arg_type = A_DOUBLE; arg[1].arg_ptr.arg_str = str_make(tokenbuf); + d = scanreg(d,buf); + stabent(buf,TRUE); /* make sure it's created */ + for (; *d; d++) { + if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') { + d = scanreg(d,buf); + stabent(buf,TRUE); + } + } goto get_repl; /* skip compiling for now */ } } Index: util.c Prereq: 2.0.1.5 *** util.c.old Sat Nov 19 00:35:28 1988 --- util.c Sat Nov 19 00:35:30 1988 *************** *** 1,6 **** ! /* $Header: util.c,v 2.0.1.5 88/10/31 16:51:04 lwall Exp $ * * $Log: util.c,v $ * Revision 2.0.1.5 88/10/31 16:51:04 lwall * patch15: some support for defective 286 compilers * patch15: support for varargs and vprintf --- 1,9 ---- ! /* $Header: util.c,v 2.0.1.6 88/11/19 00:31:02 lwall Locked $ * * $Log: util.c,v $ + * Revision 2.0.1.6 88/11/19 00:31:02 lwall + * patch16: return type of vsprintf() now depends on CHARSPRINTF + * * Revision 2.0.1.5 88/10/31 16:51:04 lwall * patch15: some support for defective 286 compilers * patch15: support for varargs and vprintf *************** *** 641,647 **** --- 644,654 ---- { char *pat; char *s; + #ifdef CHARSPRINTF char *vsprintf(); + #else + int vsprintf(); + #endif s = buf; pat = va_arg(args, char *); *************** *** 805,811 **** --- 812,822 ---- #ifdef VARARGS #ifndef VPRINTF + #ifdef CHARSPRINTF char * + #else + int + #endif vsprintf(dest, pat, args) char *dest, *pat, *args; { Index: util.h Prereq: 2.0 *** util.h.old Sat Nov 19 00:35:35 1988 --- util.h Sat Nov 19 00:35:36 1988 *************** *** 1,14 **** ! /* $Header: util.h,v 2.0 88/06/05 00:15:15 root Exp $ * * $Log: util.h,v $ * Revision 2.0 88/06/05 00:15:15 root * Baseline version 2.0. * */ ! int *screamfirst INIT(Null(int*)); ! int *screamnext INIT(Null(int*)); ! int *screamcount INIT(Null(int*)); char *safemalloc(); char *saferealloc(); --- 1,17 ---- ! /* $Header: util.h,v 2.0.1.1 88/11/19 00:32:02 lwall Locked $ * * $Log: util.h,v $ + * Revision 2.0.1.1 88/11/19 00:32:02 lwall + * patch16: several variables weren't declared EXT + * * Revision 2.0 88/06/05 00:15:15 root * Baseline version 2.0. * */ ! EXT int *screamfirst INIT(Null(int*)); ! EXT int *screamnext INIT(Null(int*)); ! EXT int *screamcount INIT(Null(int*)); char *safemalloc(); char *saferealloc();
mike@raven.BV.TEK.COM (Mike Ewan) (11/22/88)
Could someone repost Patch #13. -- Michael Ewan ucbvax...\ Tektronix Inc. decvax....\ (503) 627-6468 uw-beaver.... >!tektronix!nesa!raven!mike mike@raven.TELCOM.TEK.COM uunet..../