Path: utzoo!utgpu!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!mailrus!ncar!ames!elroy!jpl-devvax!lwall From: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Newsgroups: comp.sources.bugs Subject: perl 2.0 patch #17 Summary: This is an official patch for perl 2.0. Please apply it. Message-ID: <3558@jpl-devvax.JPL.NASA.GOV> Date: 19 Nov 88 09:42:30 GMT Organization: Jet Propulsion Laboratory, Pasadena, CA Lines: 1288 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 #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 APPEND OPEN WRITE SELECT CLOSE LOOPEX %token USING FORMAT DO SHIFT PUSH POP LVALFUN %token WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT SPRINTF ! %token FOR FEOF TELL SEEK STAT %token FUNC0 FUNC1 FUNC2 FUNC3 STABFUN %token JOIN SUB FILETEST LOCAL DELETE %token RELOP EQOP MULOP ADDOP --- 81,87 ---- %token APPEND OPEN WRITE SELECT CLOSE LOOPEX %token USING FORMAT DO SHIFT PUSH POP LVALFUN %token WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT SPRINTF ! %token FOR FILOP TELL SEEK STAT %token FUNC0 FUNC1 FUNC2 FUNC3 STABFUN %token JOIN SUB FILETEST LOCAL DELETE %token 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();