From: tinguely@plains.NoDak.edu (Mark Tinguely)
Newsgroups: comp.unix.bsd
Subject: Re: Fixed problem with long command lines
Date: 9 Apr 92 02:50:02 GMT
Article-I.D.: plains.16553
Organization: North Dakota State University, Fargo, ND


			Augggggh.

 I took a very close look at the patches that came across the network
 to fix the "big arguement list" problem that surfaced in the
 "make depend" of the kernel.

 The Halderman and Schorpbier fix did allow the arguements to be
 stored in the buffer, but they copyout() only one page and arguements
 can be lost. Because of a change to the suid stuff the initialization
 of limitonargs to NCARGS has to be in once above shell stuff.

 The Goh fix for the same problem (cutely) adjusted for multiple pages,
 but forgot the initial half page. If on the last page the arguements
 fill more than a half of a page, some are lost. To correct this, 
 NBPG/2 is added to the expression:
 	size = roundup(size + NBPG/2, NBPG);

 Finally there are soooooo many fixes to the kern_exceve.c. This patch
 is a complete diff from the original file including the "ps" fix, 
 the Willisson vfork fix. and suid/shells fix. This should bring the
 file up to date.

	------------------- Cut Here ----------------------
*** kern_execve-orig.c	Wed Apr  8 21:03:50 1992
--- kern_execve.c	Wed Apr  8 21:02:06 1992
***************
*** 95,101 ****
  	struct exec hdr;
  	char **kargbuf, **kargbufp, *kstringbuf, *kstringbufp;
  	char **org, **vectp, *ep;
! 	u_int	needsenv, limitonargs, stringlen;
  	int addr, size;
  	int argc;
  	char *cp;
--- 95,102 ----
  	struct exec hdr;
  	char **kargbuf, **kargbufp, *kstringbuf, *kstringbufp;
  	char **org, **vectp, *ep;
! 	int needsenv, limitonargs;
! 	u_int stringlen;
  	int addr, size;
  	int argc;
  	char *cp;
***************
*** 103,108 ****
--- 104,122 ----
  	struct vmspace *vs;
  	int tsize, dsize, bsize, cnt, foff;
  
+ 	int indir = 0;
+ 	register struct pcred *pcred = p->p_cred;
+ 	register struct ucred *cred ;
+ 	struct vnode *vp;
+ 	struct vattr vattr;
+ 	uid_t uid;
+ 	gid_t gid;
+ 	char *shellname;
+ 	union {
+ 		char	ex_shell[MAXINTERP];	/* #! and interpreter name */
+ 		struct	exec ex_exec;
+ 	} exdata;
+ 
  	/*
  	 * Step 1. Lookup filename to see if we have something to execute.
  	 */
***************
*** 115,166 ****
  	if (rv = namei(ndp, p))
  		return (rv);
  
  	/* is it a regular file? */
! 	if (ndp->ni_vp->v_type != VREG) {
! 		vput(ndp->ni_vp);
  		return(ENOEXEC);
  	}
  
  	/* is it executable? */
! 	rv = VOP_ACCESS(ndp->ni_vp, VEXEC, p->p_ucred, p);
  	if (rv)
  		goto exec_fail;
  	
! 	rv = vn_stat(ndp->ni_vp, &statb, p);
  	if (rv)
  		goto exec_fail;
  
  	/*
  	 * Step 2. Does the file contain a format we can
  	 * understand and execute
  	 */
! 	rv = vn_rdwr(UIO_READ, ndp->ni_vp, (caddr_t)&hdr, sizeof(hdr),
! 		0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &amt, p);
  
! 	/* big enough to hold a header? */
  	if (rv)
  		goto exec_fail;
! 	
  	/* that we recognize? */
  	rv = ENOEXEC;
! 	if (hdr.a_magic != ZMAGIC)
! 		goto exec_fail;
  
  	/* sanity check  "ain't not such thing as a sanity clause" -groucho */
! 	if (/*hdr.a_text == 0 || */ hdr.a_text > MAXTSIZ
! 		|| hdr.a_text % NBPG || hdr.a_text > statb.st_size)
  		goto exec_fail;
  
! 	if (hdr.a_data == 0 || hdr.a_data > DFLDSIZ
! 		|| hdr.a_data > statb.st_size
! 		|| hdr.a_data + hdr.a_text > statb.st_size)
  		goto exec_fail;
  
! 	if (hdr.a_bss > MAXDSIZ)
  		goto exec_fail;
  	
! 	if (hdr.a_text + hdr.a_data + hdr.a_bss > MAXTSIZ + MAXDSIZ)
  		goto exec_fail;
  	
  	/*
  	 * Step 3.  File and header are valid. Now, dig out the strings
--- 129,253 ----
  	if (rv = namei(ndp, p))
  		return (rv);
  
+ 	vp = ndp->ni_vp;
+ 	cred = pcred->pc_ucred;
+ 	uid = pcred->p_ruid;		/* get orginal uid/gid */
+ 	gid = pcred->p_rgid;
+         if (rv = VOP_GETATTR(vp, &vattr, cred, p))
+ 		goto exec_fail;
+         if (vp->v_mount->mnt_flag & MNT_NOEXEC) {	/* no exec on fs ? */
+ 		rv = EACCES;
+ 		goto exec_fail;
+ 	}
+         if ((vp->v_mount->mnt_flag & MNT_NOSUID) == 0) {
+ 		if (vattr.va_mode & VSUID)	/* check for SUID */
+ 			uid = vattr.va_uid;
+ 		if (vattr.va_mode & VSGID)	/* check for SGID */
+ 			gid = vattr.va_gid;
+ 	}
+ 
+ again:
  	/* is it a regular file? */
! 	if (vp->v_type != VREG) {
! 		vput(vp);
  		return(ENOEXEC);
  	}
  
  	/* is it executable? */
! 	rv = VOP_ACCESS(vp, VEXEC, cred, p);
  	if (rv)
  		goto exec_fail;
  	
! 	rv = vn_stat(vp, &statb, p);
  	if (rv)
  		goto exec_fail;
  
+ 
  	/*
  	 * Step 2. Does the file contain a format we can
  	 * understand and execute
  	 */
! 	/*
! 	 * Read in first few bytes of file for segment sizes, magic number:
! 	 *	ZMAGIC = demand paged RO text
! 	 * Also an ASCII line beginning with #! is
! 	 * the file name of a ``shell'' and arguments may be prepended
! 	 * to the argument list if given here.
! 	 */
! 	exdata.ex_shell[0] = '\0';	/* for zero length files */
  
! 	rv = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata),
! 	    (off_t)0, UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), cred, &amt, p);
  	if (rv)
  		goto exec_fail;
! #ifndef lint
! 	if (amt > sizeof(exdata) - sizeof(exdata.ex_exec) &&
! 	    exdata.ex_shell[0] != '#') {
! 		rv = ENOEXEC;
! 		goto exec_fail;
! 	}
! #endif
  	/* that we recognize? */
  	rv = ENOEXEC;
! 	if ((int)exdata.ex_exec.a_magic == ZMAGIC) {
  
  	/* sanity check  "ain't not such thing as a sanity clause" -groucho */
! 	if (/*exdata.ex_exec.a_text == 0 || */ exdata.ex_exec.a_text > MAXTSIZ
! 		|| exdata.ex_exec.a_text % NBPG || exdata.ex_exec.a_text > statb.st_size)
  		goto exec_fail;
  
! 	if (exdata.ex_exec.a_data == 0 || exdata.ex_exec.a_data > DFLDSIZ
! 		|| exdata.ex_exec.a_data > statb.st_size
! 		|| exdata.ex_exec.a_data + exdata.ex_exec.a_text > statb.st_size)
  		goto exec_fail;
  
! 	if (exdata.ex_exec.a_bss > MAXDSIZ)
  		goto exec_fail;
  	
! 	if (exdata.ex_exec.a_text + exdata.ex_exec.a_data + exdata.ex_exec.a_bss > MAXTSIZ + MAXDSIZ)
  		goto exec_fail;
+ 	}
+ 	else {
+ 		if (exdata.ex_shell[0] != '#' ||
+ 		    exdata.ex_shell[1] != '!' ||
+ 		    indir) {
+ 			rv = ENOEXEC;
+ 			goto exec_fail;
+ 		}
+ 		for (cp = &exdata.ex_shell[2];; ++cp) {
+ 			if (cp >= &exdata.ex_shell[MAXINTERP]) {
+ 				rv = ENOEXEC;
+ 				goto exec_fail;
+ 			}
+ 			if (*cp == '\n') {
+ 				*cp = '\0';
+ 				break;
+ 			}
+ 			if (*cp == '\t')
+ 				*cp = ' ';
+ 		}
+ 		cp = &exdata.ex_shell[2];	/* get shell interpreter name */
+ 		while (*cp == ' ')
+ 			cp++;
+ 		shellname = ndp->ni_dirp = cp;
+ 		while (*cp && *cp != ' ')
+ 			cp++;
+ 		if (*cp)
+ 			*cp++ = '\0';
+ 
+ 		indir = 1;	/* indicate this is a script file */
+ 		vput(vp);	/* find shell interpreter */
+ 		ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ 		ndp->ni_segflg = UIO_SYSSPACE;
+ 		if (rv = namei(ndp, p))
+ 			return (rv);
+ 		vp = ndp->ni_vp;
+ 		if (rv = VOP_GETATTR(vp, &vattr, cred, p))
+ 			goto exec_fail;
+ 		uid = pcred->p_ruid;	/* shell scripts can't be setuid */
+ 		gid = pcred->p_rgid;
+ 		goto again;
+ 	}
  	
  	/*
  	 * Step 3.  File and header are valid. Now, dig out the strings
***************
*** 187,210 ****
  	 */
  
  	/* allocate string buffer and arg buffer */
! 	org = kargbuf = (char **) kmem_alloc_wait(exec_map,
! 		(NCARGS + PAGE_SIZE)/PAGE_SIZE);
  	kstringbuf = kstringbufp = ((char *)kargbuf) + NBPG/2;
  	kargbuf += NBPG/(4*sizeof(int));
  	kargbufp = kargbuf;
  
! 	/* first, do args */
  	needsenv = 1;
! 	vectp = uap->argp;
  
  do_env_as_well:
! 	cnt = 0;
! 	/* for each envp, copy in string */
! 	limitonargs = NCARGS;
! 	if(vectp == 0) goto dont_bother;
  	do {
  		/* did we outgrow initial argbuf, if so, die */
! 		if (kargbufp == (char **)kstringbuf)
  			goto exec_fail;
  	
  		/* get an string pointer */
--- 274,324 ----
  	 */
  
  	/* allocate string buffer and arg buffer */
! 	org = kargbuf = (char **) kmem_alloc_wait(exec_map, NCARGS + PAGE_SIZE);
  	kstringbuf = kstringbufp = ((char *)kargbuf) + NBPG/2;
  	kargbuf += NBPG/(4*sizeof(int));
  	kargbufp = kargbuf;
+ 				/* for each envp, copy in string */
+ 	limitonargs = NCARGS;
+ 	cnt = 0;
  
! 	/* first, do (shell name if any then) args */
  	needsenv = 1;
! 	if (indir)  {
! 		ep = shellname ;
! twice:
! 	    if (ep) {
! 		/* did we outgrow initial argbuf, if so, die */
! 		if (kargbufp >= (char **)kstringbuf)
! 			goto exec_fail;
! 	
! 		if (rv = copyinstr(ep, kstringbufp, limitonargs,
! 			&stringlen)) goto exec_fail;
! 		*kargbufp = (char *)(kstringbufp - kstringbuf
! 			+ USRSTACK + NBPG/2);
! 		kargbufp++;
! 		cnt++;
! 		kstringbufp += stringlen;
! 		limitonargs -= stringlen + sizeof(long);
! 	    }
  
+ 		if (indir) {
+ 			indir = 0;
+ 			ep = uap->fname;	/* orginal executable is 1st
+ 						   arguement with scripts */
+ 			goto twice;
+ 		}
+ 		if (vectp = uap->argp) vectp++;	/* manually doing the first
+ 						   arguement with scripts */
+ 	}
+ 	else
+ 		vectp = uap->argp;	/* normal executable */
+ 
  do_env_as_well:
! 	if (vectp == 0) goto dont_bother;
  	do {
  		/* did we outgrow initial argbuf, if so, die */
! 		if (kargbufp >= (char **)kstringbuf)
  			goto exec_fail;
  	
  		/* get an string pointer */
***************
*** 220,226 ****
  				&stringlen)) goto exec_fail;
  			/* assume that strings usually all fit in last page */
  			*kargbufp = (char *)(kstringbufp - kstringbuf
! 				+ USRSTACK - NBPG + NBPG/2);
  			kargbufp++;
  			cnt++;
  			kstringbufp += stringlen;
--- 334,340 ----
  				&stringlen)) goto exec_fail;
  			/* assume that strings usually all fit in last page */
  			*kargbufp = (char *)(kstringbufp - kstringbuf
! 				+ USRSTACK + NBPG/2);
  			kargbufp++;
  			cnt++;
  			kstringbufp += stringlen;
***************
*** 252,257 ****
--- 366,372 ----
  	 */
  
  	/* At this point, we are committed -- destroy old executable */
+ 	strncpy(p->p_comm,uap->fname,MAXCOMLEN);
  	vs = p->p_vmspace;
  	addr = 0;
  	size = USRSTACK - addr;
***************
*** 262,277 ****
  
  	/* build a new address space */
  	addr = 0;
! 	if (hdr.a_text == 0) {
  		/* screwball mode */
  		foff = tsize = 0;
! 		hdr.a_data += hdr.a_text;
  	} else {
! 		tsize = roundup(hdr.a_text, NBPG);
  		foff = NBPG;
  	}
! 	dsize = roundup(hdr.a_data, NBPG);
! 	bsize = roundup(hdr.a_bss + dsize, NBPG);
  	bsize -= dsize;
  
  	/* map text & data*/
--- 377,392 ----
  
  	/* build a new address space */
  	addr = 0;
! 	if (exdata.ex_exec.a_text == 0) {
  		/* screwball mode */
  		foff = tsize = 0;
! 		exdata.ex_exec.a_data += exdata.ex_exec.a_text;
  	} else {
! 		tsize = roundup(exdata.ex_exec.a_text, NBPG);
  		foff = NBPG;
  	}
! 	dsize = roundup(exdata.ex_exec.a_data, NBPG);
! 	bsize = roundup(exdata.ex_exec.a_bss + dsize, NBPG);
  	bsize -= dsize;
  
  	/* map text & data*/
***************
*** 315,321 ****
  
  	/* everything fits in a single page, no fixups, no more work */
  	/* (groan) due to bug in vm_map_copy, can't remap. copy for now. */
! 	rv = copyout((caddr_t)org, (caddr_t)USRSTACK - NBPG, NBPG);
  	if(rv)
  		goto exec_abort;
  
--- 430,441 ----
  
  	/* everything fits in a single page, no fixups, no more work */
  	/* (groan) due to bug in vm_map_copy, can't remap. copy for now. */
! 	size = kstringbufp + 1 - kstringbuf;
! 	size = roundup(size + NBPG/2, NBPG);
! 	for (; kargbuf < kargbufp; kargbuf++)
! 		if (*kargbuf)
! 			*kargbuf -= size;
! 	rv = copyout((caddr_t)org, (caddr_t)USRSTACK - size, size);
  	if(rv)
  		goto exec_abort;
  
***************
*** 323,333 ****
  	fdcloseexec(p);
  	execsigs(p);
  
! 	p->p_regs[SP] = USRSTACK - NBPG + NBPG/4 - 4;
! 	vs->vm_ssize = 1;	/* stack size (pages) */
! 	setregs(p, hdr.a_entry);
! 	kmem_free_wakeup(exec_map, org, (NCARGS + PAGE_SIZE)/PAGE_SIZE);
  	vput(ndp->ni_vp);
  	return (0);
  
  exec_fail:
--- 443,463 ----
  	fdcloseexec(p);
  	execsigs(p);
  
! 	p->p_regs[SP] = USRSTACK - size + NBPG/4 - 4;
! 	vs->vm_ssize = size / NBPG;	/* stack size (pages) */
! 	setregs(p, exdata.ex_exec.a_entry);
! 	kmem_free_wakeup(exec_map, org, NCARGS + PAGE_SIZE);
  	vput(ndp->ni_vp);
+ 
+ 	if (p && p->p_cred) {
+ 	 p->p_ucred->cr_uid = p->p_cred->p_svuid = uid;
+ 	 p->p_ucred->cr_gid = p->p_cred->p_svgid = gid;
+ 	}
+ 		/* wake up the vfork parent */
+ 	if (p->p_flag & SPPWAIT) {
+ 		p->p_flag &= ~(SPPWAIT);
+ 		wakeup((caddr_t) p ->p_pptr);
+ 	}
  	return (0);
  
  exec_fail:
***************
*** 336,342 ****
  
  exec_abort:
  	/* untested and probably bogus */
! 	kmem_free_wakeup(exec_map, org, (NCARGS + PAGE_SIZE)/PAGE_SIZE);
  	vput(ndp->ni_vp);
  	exit(p, W_EXITCODE(0, SIGABRT));
  	return(0);
--- 466,472 ----
  
  exec_abort:
  	/* untested and probably bogus */
! 	kmem_free_wakeup(exec_map, org, NCARGS + PAGE_SIZE);
  	vput(ndp->ni_vp);
  	exit(p, W_EXITCODE(0, SIGABRT));
  	return(0);