perl 2.0 patch #17
Larry Wall
lwall at jpl-devvax.JPL.NASA.GOV
Sat Nov 19 19:42:30 AEST 1988
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 at 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();
More information about the Comp.sources.bugs
mailing list