From marcolz@stack.nl  Wed Jan  9 11:29:03 2002
Return-Path: <marcolz@stack.nl>
Received: from skynet.stack.nl (insgate.stack.nl [131.155.140.2])
	by hub.freebsd.org (Postfix) with ESMTP id 78BCB37B405
	for <FreeBSD-gnats-submit@freebsd.org>; Wed,  9 Jan 2002 11:29:02 -0800 (PST)
Received: from turtle.stack.nl (turtle.stack.nl [2001:610:1108:5010:202:b3ff:fe17:a070])
	by skynet.stack.nl (Postfix) with ESMTP
	id 426059B15; Wed,  9 Jan 2002 20:28:54 +0100 (CET)
Received: by turtle.stack.nl (Postfix, from userid 333)
	id 7EF7D35B; Wed,  9 Jan 2002 20:28:52 +0100 (CET)
Message-Id: <20020109202852.A61938@stack.nl>
Date: Wed, 9 Jan 2002 20:28:52 +0100
From: Marc Olzheim <marcolz@stack.nl>,
	Serge van den Boom <svdb@stack.nl>
Reply-To: Marc Olzheim <marcolz@stack.nl>
To: FreeBSD-gnats-submit@freebsd.org
Cc: Marc Olzheim <marcolz@stack.nl>,
	Serge van den Boom <svdb@stack.nl>
Subject: [PATCH] empty argv
X-Send-Pr-Version: 3.113

>Number:         33738
>Category:       kern
>Synopsis:       [patch] argv == NULL is not handled correctly by programs.
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jan 09 11:30:01 PST 2002
>Closed-Date:    Wed Mar 16 16:56:02 GMT 2005
>Last-Modified:  Wed Mar 16 16:56:02 GMT 2005
>Originator:     Marc Olzheim and Serge van den Boom
>Release:        FreeBSD 4.5-PRERELEASE
>Organization:
M.C.G.V. Stack
>Environment:
FreeBSD 2, 3, 4, 5


>Description:
	FreeBSD's execve(2) does not check wether argv is NULL. This
	does not seem to pose an immediate threat, but programs like
	passwd and other setuid programs that use getopt(3) tend to use
	the example code from the getopt(3) manpage. This code does:
	argc -= optind; argv += optind;

	If argc was 0, getopt(3) returns -1 and does not modify optind,
	which is initialized at 1. Thus argc becomes -1 and argv skips
	over the NULL pointer into the environment, which is loaded
	right after the argv strings array in memory. Programs that do
	not check argc before or after getopt(3) then regard the
	environment strings as arguments to the program. A good example
	is ls(1).

	None of this poses any serious problems, besides from crashing
	setuid programs, which do not look good in your dmesg, but this
	could be a problem in programs that handle arguments like ls(1).

	OpenBSD does not allow empty argv, returning -1 and EFAULT in
	errno (the man page says it should return EINVAL, but it
	doesn't). I do not know wether this is a good option for FreeBSD
	as well, but I don't see any problems with the kernel patch
	right now. If this patch is not possible for some reason, I
	think some programs need to be checked for misuse of argv, like
	ls(1) does.

>How-To-Repeat:
	Attached are noargv.c, which takes a single argument and runs it
	with argv set to NULL, and 2 patches: one for the kernel and one
	for getopt(3), which does not do as is should according to the
	manual. Play around with noargv and see what happens...
>Fix:
	Attached.
	The getopt patch fixes ls, but not passwd and probably some more
	programs...

Marc

--LQksG6bCIzRHxTLp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="kern_exec.c.patch"

--- /usr/src/sys/kern/kern_exec.c.orig	Wed Jan  9 19:28:25 2002
+++ /usr/src/sys/kern/kern_exec.c	Wed Jan  9 19:30:33 2002
@@ -582,7 +582,8 @@
 				imgp->argc++;
 			} while ((argp = (caddr_t) (intptr_t) fuword(argv++)));
 		}
-	}	
+	} else
+		return(EFAULT);
 
 	imgp->endargs = imgp->stringp;
 

--LQksG6bCIzRHxTLp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="getopt.c.patch"

--- /usr/src/lib/libc/stdlib/getopt.c	Wed Jan  9 16:26:37 2002
+++ /usr/src/lib/libc/stdlib/getopt.c	Wed Jan  9 16:51:27 2002
@@ -66,6 +66,15 @@
 	static char *place = EMSG;		/* option letter processing */
 	char *oli;				/* option letter list index */
 
+	if (!nargc)
+	{
+		optind = 0;
+		if (optreset)
+			optreset = 0;
+
+		return (-1);
+	}
+
 	if (optreset || !*place) {		/* update scanning pointer */
 		optreset = 0;
 		if (optind >= nargc || *(place = nargv[optind]) != '-') {

--LQksG6bCIzRHxTLp--
>Release-Note:
>Audit-Trail:

From: Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
To: Marc Olzheim <marcolz@stack.nl>
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: kern/33738: [PATCH] empty argv
Date: Wed, 9 Jan 2002 19:11:33 -0500 (EST)

 <<On Thu, 10 Jan 2002 00:54:20 +0100, Marc Olzheim <marcolz@stack.nl> said:
 
 > Perhaps this should be caught as well in execve(2). One could also argue
 > that setuid programmers should expect the unexpected, but why not make
 > it easier on them...
 
 The POSIX specification is clear: calling execve() with zero arguments
 must be permitted (but no Strictly Conforming Application may do so),
 and programs must expect to be called without arguments.  The
 Rationale states this explicitly:
 
 # Early proposals required that the value of argc passed to main( ) be
 # ``one or greater''. This was driven by the same requirement in
 # drafts of the ISO C standard. In fact, historical implementations
 # have passed a value of zero when no arguments are supplied to the
 # caller of the exec functions. This requirement was removed from the
 # ISO C standard and subsequently removed from this volume of IEEE Std
 # 1003.1-200x as well. The wording, in particular the use of the word
 # should, requires a Strictly Conforming POSIX Application to pass at
 # least one argument to the exec function, thus guaranteeing that argc
 # be one or greater when invoked by such an application. In fact, this
 # is good practice, since many existing applications reference argv[0]
 # without first checking the value of argc.
 
 (XSHd7, p. 758)
 
 If the Standard does not say that a list must be non-empty, then it
 may be empty.
 
 -GAWollman
 

From: Marc Olzheim <marcolz@stack.nl>
To: Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
Cc: Marc Olzheim <marcolz@stack.nl>,
	freebsd-gnats-submit@FreeBSD.ORG, Serge van den Boom <svdb@stack.nl>
Subject: Re: kern/33738: [PATCH] empty argv
Date: Thu, 10 Jan 2002 09:16:36 +0100

 [snip]
 
 > If the Standard does not say that a list must be non-empty, then it
 > may be empty.
 
 Hmmm, then programs like passwd, lpr, etc. should probably be fixed, or
 checked for potential abuse of (argc == 0).
 
 Marc
 __
 /* noargv.c */
 #include	<stdio.h>
 #include	<unistd.h>
 
 int
 main(int argc, char *argv[])
 {
 	const char	*bar[] = { "/tmp/foo", NULL };
 	if (argc != 2)
 	{
 		fprintf(stderr, "Usage: %s <prog>\n", argv[0]);
 		return(1);
 	}
 
 	execve(argv[1], NULL, bar);
 	perror("execve");
 
 	return(0);
 }
 __

From: Sheldon Hearn <sheldonh@starjuice.net>
To: Marc Olzheim <marcolz@stack.nl>
Cc: bug-followup@freebsd.org
Subject: Re: kern/33738: [PATCH] empty argv 
Date: Thu, 10 Jan 2002 15:28:15 +0200

 On Thu, 10 Jan 2002 00:20:02 PST, Marc Olzheim wrote:
 
 >  > If the Standard does not say that a list must be non-empty, then it
 >  > may be empty.
 >  
 >  Hmmm, then programs like passwd, lpr, etc. should probably be fixed, or
 >  checked for potential abuse of (argc == 0).
 
 True, but that kind of audit can't be supported by a single PR.  Rather
 open distinct PRs for each program.
 
 Can we close this PR?
 
 Ciao,
 Sheldon.

From: Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
To: Marc Olzheim <marcolz@stack.nl>
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: kern/33738: [PATCH] empty argv
Date: Thu, 10 Jan 2002 11:50:30 -0500 (EST)

 <<On Thu, 10 Jan 2002 09:16:36 +0100, Marc Olzheim <marcolz@stack.nl> said:
 
 > 	execve(argv[1], NULL, bar);
 
 This, on the other hand, should probably return an error.  A null
 pointer is not an ``array of character pointers'' as required by the
 Standard.  The Standard does not require a particular error return for
 this case, so any error is permissible; [EFAULT] is probably the best.
 
 -GAWollman
 

From: Marc Olzheim <marcolz@stack.nl>
To: Sheldon Hearn <sheldonh@starjuice.net>
Cc: Marc Olzheim <marcolz@stack.nl>, bug-followup@freebsd.org,
	Serge van den Boom <svdb@stack.nl>
Subject: Re: kern/33738: [PATCH] empty argv
Date: Thu, 10 Jan 2002 19:43:25 +0100

 > Can we close this PR?
 
 Is the EFAULT patch going to be implemented then ?
 
 Marc

From: Marc Olzheim <marcolz@stack.nl>
To: Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
Cc: Marc Olzheim <marcolz@stack.nl>,
	freebsd-gnats-submit@FreeBSD.ORG, Serge van den Boom <svdb@stack.nl>
Subject: Re: kern/33738: [PATCH] empty argv
Date: Thu, 10 Jan 2002 21:19:18 +0100

 > > 	execve(argv[1], NULL, bar);
 > 
 > This, on the other hand, should probably return an error.  A null
 > pointer is not an ``array of character pointers'' as required by the
 > Standard.  The Standard does not require a particular error return for
 > this case, so any error is permissible; [EFAULT] is probably the best.
 
 Is this "the Standard" for execve(), or for argv ? Because alle the
 execve()-d prog sees _is_ an array of character pointers, because execve()
 reproduced the information onto the stack.
 
 Marc

From: Marc Olzheim <marcolz@stack.nl>
To: Sheldon Hearn <sheldonh@starjuice.net>
Cc: Marc Olzheim <marcolz@stack.nl>, bug-followup@freebsd.org,
	Serge van den Boom <svdb@stack.nl>
Subject: Re: kern/33738: [PATCH] empty argv
Date: Thu, 10 Jan 2002 21:31:12 +0100

 > >  > If the Standard does not say that a list must be non-empty, then it
 > >  > may be empty.
 > >  
 > >  Hmmm, then programs like passwd, lpr, etc. should probably be fixed, or
 > >  checked for potential abuse of (argc == 0).
 > 
 > True, but that kind of audit can't be supported by a single PR.  Rather
 > open distinct PRs for each program.
 
 And the getopt patch ? Should that be reposted in a different PR also ?
 It's behaviour seems according to what the man page dictates...
 
 Marc

From: Sheldon Hearn <sheldonh@starjuice.net>
To: Marc Olzheim <marcolz@stack.nl>
Cc: bug-followup@freebsd.org, Serge van den Boom <svdb@stack.nl>
Subject: Re: kern/33738: [PATCH] empty argv 
Date: Thu, 10 Jan 2002 23:06:08 +0200

 On Thu, 10 Jan 2002 19:43:25 +0100, Marc Olzheim wrote:
 
 > > Can we close this PR?
 > 
 > Is the EFAULT patch going to be implemented then ?
 
 I asked that before statements were made to the effect that POSIX does
 not allow a NULL pointer in place of a pointer to an array of character
 pointers. :-)
 
 Ciao,
 Sheldon.

From: "KAREN THODE" <thode12@msn.com>
To: <freebsd-gnats-submit@FreeBSD.org>, <marcolz@stack.nl>
Cc:  
Subject: Re: kern/33738: argv == NULL is not handled correctly by programs.
Date: Tue, 24 Dec 2002 07:47:53 -0600

 ------=_NextPart_001_0002_01C2AB20.C3B4BBA0
 Content-Type: text/plain; charset="iso-8859-1"
 
 Try enclosing suspect code in an "if(argv != NULL){...}" block.
 
 Lucas
 ------=_NextPart_001_0002_01C2AB20.C3B4BBA0
 Content-Type: text/html; charset="iso-8859-1"
 Content-Transfer-Encoding: quoted-printable
 
 <HTML><BODY STYLE=3D"font:10pt verdana; border:none;"><DIV>Try enclosing =
 suspect code in an "if(argv !=3D NULL){...}" block.</DIV> <DIV>&nbsp;</DI=
 V> <DIV>Lucas<BR><BR></DIV></BODY></HTML>
 
 ------=_NextPart_001_0002_01C2AB20.C3B4BBA0--

From: Marc Olzheim <marcolz@stack.nl>
To: bug-followup@freebsd.org
Cc:  
Subject: Re: kern/33738: [PATCH] empty argv
Date: Wed, 16 Mar 2005 17:47:10 +0100

 The kernel problem has been fixed in src/sys/kern/kern_exec.c:1.238
 Issues with getopt could be circumvented for instance by importing
 OpenBSD's getopt, or whatever. The problems this PR talks about are
 fixed anyhow, so this PR can be closed now.
 
 Marc
State-Changed-From-To: open->closed 
State-Changed-By: maxim 
State-Changed-When: Wed Mar 16 16:52:27 GMT 2005 
State-Changed-Why:  
Closed at the submitter's request (fixed in rev. 1.238 
sys/kern/kern_exec.c). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=33738 
>Unformatted:
 --LQksG6bCIzRHxTLp
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 
