NetBSD Problem Report #19209

Received: (qmail 23815 invoked by uid 605); 30 Nov 2002 01:16:55 -0000
Message-Id: <20021130011652.7E215A@proven.weird.com>
Date: Fri, 29 Nov 2002 20:16:52 -0500 (EST)
From: woods@weird.com (Greg A. Woods)
Sender: gnats-bugs-owner@netbsd.org
Reply-To: woods@planix.com (Greg A. Woods)
To: gnats-bugs@gnats.netbsd.org
Subject: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
X-Send-Pr-Version: 3.95

>Number:         19209
>Category:       standards
>Synopsis:       test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    standards-manager
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Nov 30 01:17:00 +0000 2002
>Closed-Date:    Fri Sep 14 03:18:21 +0000 2018
>Last-Modified:  Fri Sep 14 03:18:21 +0000 2018
>Originator:     Greg A. Woods
>Release:        netbsd-1.6
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Environment:
System: NetBSD 1.6
>Description:

	I've wanted to fix this for a while, but finally got perturbed
	into doing it due to frustrations with a small script I was
	porting -- one that has to run as root.

	For the nitty gritty details see the comment included in the
	patch below....

>How-To-Repeat:

	try the following as root:

	# chmod a-w /bin/sh	# just in case....
	# if [ -w /bin/sh ] ; then echo "OOPS!  /bin/sh is writable!" ; fi

>Fix:

Index: test.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/basesrc/bin/test/test.c,v
retrieving revision 1.24
diff -c -c -r1.24 test.c
*** test.c	16 Sep 2001 19:03:26 -0000	1.24
--- test.c	30 Nov 2002 01:02:09 -0000
***************
*** 353,371 ****
  filstat(char *nm, enum token mode)
  {
  	struct stat s;

  	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
  		return 0;

  	switch (mode) {
  	case FILRD:
! 		return access(nm, R_OK) == 0;
  	case FILWR:
! 		return access(nm, W_OK) == 0;
  	case FILEX:
! 		return access(nm, X_OK) == 0;
  	case FILEXIST:
! 		return access(nm, F_OK) == 0;
  	case FILREG:
  		return S_ISREG(s.st_mode);
  	case FILDIR:
--- 353,433 ----
  filstat(char *nm, enum token mode)
  {
  	struct stat s;
+ 	u_int16_t i;

  	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
  		return 0;

+ 	/*
+ 	 * The manual, and IEEE POSIX 1003.2, suggests these should check the
+ 	 * mode bits, not use access().  For example for '-w':
+ 	 *
+ 	 *	True shall indicate only that the write flag is on.  The file
+ 	 *	is not writable on a read-only file system even if this test
+ 	 *	indicates true.
+ 	 *
+ 	 * On the other hand IEEE POSIX 1003.1-2001, as quoted in SuSv3, says:
+ 	 *
+ 	 *	True shall indicate that permission to write from[sic] file
+ 	 *	will be granted, as defined in File Read, Write, and Creation.
+ 	 *
+ 	 * However that section says only:
+ 	 *
+ 	 *	When a file is to be read or written, the file shall be opened
+ 	 *	with an access mode corresponding to the operation to be
+ 	 *	performed.  If file access permissions deny access, the
+ 	 *	requested operation shall fail.
+ 	 *
+ 	 * and when I first read this I though surely we can't go about using
+ 	 * open(O_WRITE) to try this test!  However the POSIX 1003.1-2001
+ 	 * Rationale section for test does in fact say:
+ 	 *
+ 	 *	On historical BSD systems, test -w directory always returned
+ 	 *	false because test tried to open the directory for writing,
+ 	 *	which always fails.
+ 	 *
+ 	 * and indeed this is in fact true for Seventh Edition UNIX, UNIX 32V,
+ 	 * and UNIX System III, and thus presumably also for BSD up to and
+ 	 * including 4.3.
+ 	 *
+ 	 * Oddly the SysV implementation (at least in the 'test' builtin in
+ 	 * /bin/sh) also uses access(name, 2) even though it goes to much
+ 	 * greater lengths to test for execute permissions (like pdksh does).
+ 	 *
+ 	 * Interestingly the 4.4BSD was correct and it was implemented
+ 	 * "intelligently" with stat() instead of open().
+ 	 *
+ 	 * This was apparently broken in NetBSD around about 1994/06/30 when
+ 	 * the old 4.4BSD implementation was replaced with a (arguably much
+ 	 * better coded) implementation derived from pdksh.
+ 	 *
+ 	 * Note that modern pdksh is yet different again, but still not
+ 	 * correct, at least not w.r.t. POSIX as I interpret it.
+ 	 */
  	switch (mode) {
  	case FILRD:
! 		i = S_IROTH;
! 		if (s.st_uid == geteuid())
! 			i = S_IRUSR;
! 		else if (s.st_gid == getegid())
! 			i = S_IRGRP;
! 		return (s.st_mode & i);
  	case FILWR:
! 		i = S_IWOTH;
! 		if (s.st_uid == geteuid())
! 			i = S_IWUSR;
! 		else if (s.st_gid == getegid())
! 			i = S_IWGRP;
! 		return (s.st_mode & i);
  	case FILEX:
! 		i = S_IXOTH;
! 		if (s.st_uid == geteuid())
! 			i = S_IXUSR;
! 		else if (s.st_gid == getegid())
! 			i = S_IXGRP;
! 		return (s.st_mode & i);
  	case FILEXIST:
! 		return 1;	/* the successful lstat()/stat() is good enough */
  	case FILREG:
  		return S_ISREG(s.st_mode);
  	case FILDIR:
>Release-Note:
>Audit-Trail:

From: christos@zoulas.com (Christos Zoulas)
To: woods@planix.com (Greg A. Woods), gnats-bugs@gnats.netbsd.org
Cc:  
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Fri, 29 Nov 2002 21:37:28 -0500

 On Nov 29,  8:16pm, woods@weird.com (Greg A. Woods) wrote:
 -- Subject: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for r

 | 	I've wanted to fix this for a while, but finally got perturbed
 | 	into doing it due to frustrations with a small script I was
 | 	porting -- one that has to run as root.
 | 
 | 	For the nitty gritty details see the comment included in the
 | 	patch below....

 You are right, but that is broken slightly too. Look in tcsh's sh.exp.c

 christos

From: woods@weird.com (Greg A. Woods)
To: christos@zoulas.com (Christos Zoulas)
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Fri, 29 Nov 2002 22:56:10 -0500 (EST)

 [ On Friday, November 29, 2002 at 21:37:28 (-0500), Christos Zoulas wrote: ]
 > Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
 >
 > On Nov 29,  8:16pm, woods@weird.com (Greg A. Woods) wrote:
 > -- Subject: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for r
 > 
 > | 	I've wanted to fix this for a while, but finally got perturbed
 > | 	into doing it due to frustrations with a small script I was
 > | 	porting -- one that has to run as root.
 > | 
 > | 	For the nitty gritty details see the comment included in the
 > | 	patch below....
 > 
 > You are right, but that is broken slightly too. Look in tcsh's sh.exp.c

 hmmmm. perhaps the clues in pkgsrc/shells/ast-ksh/src/cmd/ksh93/bltins/test.c
 tell me what to do to make it better....  getgroups().

 I think that much code really does make it worthwhile to create another
 subroutine to do the check....

 If I can work this out right (without violating KSH copyright :-) I'll
 post a followup patch....

 -- 
 								Greg A. Woods

 +1 416 218-0098;            <g.a.woods@ieee.org>;           <woods@robohack.ca>
 Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>

From: christos@zoulas.com (Christos Zoulas)
To: woods@weird.com (Greg A. Woods)
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Fri, 29 Nov 2002 23:06:28 -0500

 On Nov 29, 10:56pm, woods@weird.com (Greg A. Woods) wrote:
 -- Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX f

 correct!

 christos

 | hmmmm. perhaps the clues in pkgsrc/shells/ast-ksh/src/cmd/ksh93/bltins/test.c
 | tell me what to do to make it better....  getgroups().
 | 
 | I think that much code really does make it worthwhile to create another
 | subroutine to do the check....
 | 
 | If I can work this out right (without violating KSH copyright :-) I'll
 | post a followup patch....

From: woods@weird.com (Greg A. Woods)
To: netbsd-bugs@NetBSD.ORG (NetBSD Bugs and PR posting List)
Cc: gnats-bugs@gnats.netbsd.org (NetBSD GNATS submissions and followups)
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Sat, 30 Nov 2002 01:21:30 -0500 (EST)

 Here's an updated patch, with updated comment, that takes into account
 multiple group memebership and also fixes the logic in my previous patch
 so that any relevant permission bit (user, group, or other) will do if
 geteuid()==0 (as per 1003.2-1992, I believe).

 # ls -l /root/foo 
 -r--r--r--  1 root  wheel  0 Nov 29 23:28 /root/foo
 # if /bin/ksh -c '[ -w /root/foo ]' ; then echo is writable ; fi
 is writable
 # if /bin/sh -c '[ -w /root/foo ]' ; then echo is writable ; fi
 is writable
 # if /usr/pkg/bin/ksh93 -c '[ -w /root/foo ]' ; then echo is writable ; fi
 is writable
 # if ./test -w /root/foo ; then echo is writable ; fi
 # if ../sh/sh -c '[ -w /root/foo ]' ; then echo is writable; fi
 #

 (I haven't compiled the 4.4BSD-Lite2 version but I'm reasonably certain
 it would behave as my patched version does.)


 Index: test.c
 ===================================================================
 RCS file: /cvs/master/m-NetBSD/main/basesrc/bin/test/test.c,v
 retrieving revision 1.24
 diff -c -c -r1.24 test.c
 *** test.c	16 Sep 2001 19:03:26 -0000	1.24
 --- test.c	30 Nov 2002 06:16:41 -0000
 ***************
 *** 21,26 ****
 --- 21,27 ----
   #include <ctype.h>
   #include <err.h>
   #include <errno.h>
 + #include <limits.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
 ***************
 *** 154,159 ****
 --- 155,161 ----
   static int nexpr(enum token);
   static int primary(enum token);
   static int binop(void);
 + static int test_access(struct stat *, u_int16_t);
   static int filstat(char *, enum token);
   static enum token t_lex(char *);
   static int isoperand(void);
 ***************
 *** 190,195 ****
 --- 192,214 ----
   }
   #endif

 + #if defined(SHELL)
 + extern void * ckmalloc(size_t);
 + #else
 + 
 + static void * ckmalloc(size_t);
 + 
 + static void *
 + ckmalloc(size_t nbytes)
 + {
 + 	void *p = malloc(nbytes);
 + 
 + 	if (!p)
 + 		error("Not enough memory!");
 + 	return p;
 + }
 + #endif
 + 
   #ifdef SHELL
   int testcmd(int, char **);

 ***************
 *** 349,354 ****
 --- 368,538 ----
   	}
   }

 + /*
 +  * The manual, and IEEE POSIX 1003.2, suggests this should check the mode bits,
 +  * not use access():
 +  *
 +  *	True shall indicate only that the write flag is on.  The file is not
 +  *	writable on a read-only file system even if this test indicates true.
 +  *
 +  * Unfortunately IEEE POSIX 1003.1-2001, as quoted in SuSv3, says only:
 +  *
 +  *	True shall indicate that permission to read from file will be granted,
 +  *	as defined in "File Read, Write, and Creation".
 +  *
 +  * and that section says:
 +  *
 +  *	When a file is to be read or written, the file shall be opened with an
 +  *	access mode corresponding to the operation to be performed.  If file
 +  *	access permissions deny access, the requested operation shall fail.
 +  *
 +  * and of course access permissions are described as one might expect:
 +  *
 +  *     * If a process has the appropriate privilege:
 +  *
 +  *        * If read, write, or directory search permission is requested,
 +  *          access shall be granted.
 +  *
 +  *        * If execute permission is requested, access shall be granted if
 +  *          execute permission is granted to at least one user by the file
 +  *          permission bits or by an alternate access control mechanism;
 +  *          otherwise, access shall be denied.
 +  *
 +  *   * Otherwise:
 +  *
 +  *        * The file permission bits of a file contain read, write, and
 +  *          execute/search permissions for the file owner class, file group
 +  *          class, and file other class.
 +  *
 +  *        * Access shall be granted if an alternate access control mechanism
 +  *          is not enabled and the requested access permission bit is set for
 +  *          the class (file owner class, file group class, or file other class)
 +  *          to which the process belongs, or if an alternate access control
 +  *          mechanism is enabled and it allows the requested access; otherwise,
 +  *          access shall be denied.
 +  *
 +  * and when I first read this I thought:  surely we can't go about using
 +  * open(O_WRONLY) to try this test!  However the POSIX 1003.1-2001 Rationale
 +  * section for test does in fact say:
 +  *
 +  *	On historical BSD systems, test -w directory always returned false
 +  *	because test tried to open the directory for writing, which always
 +  *	fails.
 +  *
 +  * and indeed this is in fact true for Seventh Edition UNIX, UNIX 32V, and UNIX
 +  * System III, and thus presumably also for BSD up to and including 4.3.
 +  *
 +  * Secondly I remembered why using open() and/or access() are bogus.  They
 +  * don't work right for detecting read and write permissions bits when called
 +  * by root.
 +  *
 +  * Interestingly the 'test' in 4.4BSD was closer to correct (as per
 +  * 1003.2-1992) and it was implemented efficiently with stat() instead of
 +  * open().
 +  *
 +  * This was apparently broken in NetBSD around about 1994/06/30 when the old
 +  * 4.4BSD implementation was replaced with a (arguably much better coded)
 +  * implementation derived from pdksh.
 +  *
 +  * Note that modern pdksh is yet different again, but still not correct, at
 +  * least not w.r.t. 1003.2-1992.
 +  *
 +  * As I think more about it and read more of the related IEEE docs I don't like
 +  * that wording about 'test -r' and 'test -w' in 1003.1-2001 at all.  I very
 +  * much prefer the original wording in 1003.2-1992.  It is much more useful,
 +  * and so that's what I've implemented.
 +  *
 +  * (Note that a strictly conforming implementation of 1003.1-2001 is in fact
 +  * totally useless for the case in question since its 'test -w' and 'test -r'
 +  * can never fail for root for any existing files, i.e. files for which 'test
 +  * -e' succeeds.)
 +  * 
 +  * The rationale for 1003.1-2001 suggests that the wording was "clarified" in
 +  * 1003.1-2001 to align with the 1003.2b draft.  1003.2b Draft 12 (July 1999),
 +  * which is the latest copy I have, does carry the same suggested wording as is
 +  * in 1003.1-2001, with its rationale saying:
 +  * 
 +  * 	This change is a clarification and is the result of interpretation
 +  * 	request PASC 1003.2-92 #23 submitted for IEEE Std 1003.2-1992.
 +  * 
 +  * That interpretation can be found here:
 +  * 
 +  *   http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-23.html
 +  * 
 +  * Not terribly helpful, unfortunately.  I wonder who that fence sitter was.
 +  * 
 +  * Worse, IMVNSHO, I think the authors of 1003.2b-D12 have mis-interpreted the
 +  * PASC interpretation and appear to be gone against at least one widely used
 +  * implementation (namely 4.4BSD).  The problem is that for file access by root
 +  * this means that if test '-r' and '-w' are to behave as if open() were called
 +  * then there's no way for a shell script running as root to check if a file
 +  * has certain access bits set other than by the grotty means of interpreting
 +  * the output of 'ls -l'.  This was widely considered to be a bug in V7's
 +  * "test" and is, I believe, one of the reasons why direct use of access() was
 +  * avoided in some more recent implementations!
 +  * 
 +  * I have always interpreted '-r' to match '-w' and '-x' as per the original
 +  * wording in 1003.2-1992, not the other way around.  I think 1003.2b goes much
 +  * too far the wrong way without any valid rationale and that it's best if we
 +  * stick with 1003.2-1992 and test the flags, and not mimic the behaviour of
 +  * open() since we already know very well how it will work -- existance of the
 +  * file is all that matters to open() for root.
 +  * 
 +  * Unfortunately the SVID is no help at all (which is, I guess, partly why
 +  * we're in this mess in the first place :-).
 +  * 
 +  * The SysV implementation (at least in the 'test' builtin in /bin/sh) does use
 +  * access(name, 2) even though it also goes to much greater lengths for '-x'
 +  * matching the 1003.2-1992 definition (which is no doubt where that definition
 +  * came from).
 +  *
 +  * The ksh93 implementation uses access() for '-r' and '-w' if
 +  * (euid==uid&&egid==gid), but uses st_mode for '-x' iff running as root.
 +  * i.e. it does strictly conform to 1003.1-2001 (and presumably 1003.2b).
 +  */
 + 
 + static int maxgroups = 0;
 + 
 + static int
 + test_access(struct stat *sp, u_int16_t stmode)	/* GHOD I HATE STD C!!!! */
 + {
 + 	gid_t *groups; 
 + 	register int n;
 + 	uid_t euid;
 + 
 + 	/*
 + 	 * I suppose we could use access() if not running as root and if we are
 + 	 * running with ((euid == uid) && (egid == gid)), but we've already
 + 	 * done the stat() so we might as well just test the permissions
 + 	 * directly instead of asking the kernel to do it....
 + 	 */
 + 	euid = geteuid();
 + 	if (euid == 0)				/* any bit is good enough */
 + 		stmode = ((stmode << 6) | (stmode << 3) | stmode);
 +  	else if (sp->st_uid == euid)
 + 		stmode <<= 6;
 + 	else if (sp->st_gid == getegid())
 + 		stmode <<= 3;
 + 	else {
 + 		/* XXX stolen almost verbatim from ksh93.... */
 + 		/* on some systems you can be in several groups */
 + 		if ((maxgroups = getgroups(0, (gid_t *) NULL)) <= 0)
 + 			maxgroups = NGROUPS_MAX;	/* pre-POSIX system? */
 + 		groups = (gid_t *) ckmalloc((maxgroups + 1) * sizeof(gid_t));
 + 		n = getgroups(maxgroups, groups);
 + 		while (--n >= 0) {
 + 			if (groups[n] == sp->st_gid) {
 + 				stmode <<= 3;
 + 				break;
 + 			}
 + 		}
 + 		free(groups);
 + 	}
 + 
 + 	return (sp->st_mode & stmode);
 + }
 + 
 + 
   static int
   filstat(char *nm, enum token mode)
   {
 ***************
 *** 359,371 ****

   	switch (mode) {
   	case FILRD:
 ! 		return access(nm, R_OK) == 0;
   	case FILWR:
 ! 		return access(nm, W_OK) == 0;
   	case FILEX:
 ! 		return access(nm, X_OK) == 0;
   	case FILEXIST:
 ! 		return access(nm, F_OK) == 0;
   	case FILREG:
   		return S_ISREG(s.st_mode);
   	case FILDIR:
 --- 543,555 ----

   	switch (mode) {
   	case FILRD:
 ! 		return test_access(&s, S_IROTH);
   	case FILWR:
 ! 		return test_access(&s, S_IWOTH);
   	case FILEX:
 ! 		return test_access(&s, S_IXOTH);
   	case FILEXIST:
 ! 		return 1;	/* the successful lstat()/stat() is good enough */
   	case FILREG:
   		return S_ISREG(s.st_mode);
   	case FILDIR:

 -- 
 								Greg A. Woods

 +1 416 218-0098;            <g.a.woods@ieee.org>;           <woods@robohack.ca>
 Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>

From: David Laight <david@l8s.co.uk>
To: NetBSD Bugs and PR posting List <netbsd-bugs@NetBSD.ORG>,
  NetBSD GNATS submissions and followups <gnats-bugs@gnats.netbsd.org>
Cc:  
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Sat, 30 Nov 2002 09:06:36 +0000

 > + #if defined(SHELL)
 > + extern void * ckmalloc(size_t);
 > + #else

 Bung that in bltin.h

 > + static void * ckmalloc(size_t);

 Not needed for static function

 > + static void *
 > + ckmalloc(size_t nbytes)
 > + {
 > + 	void *p = malloc(nbytes);
 > + 
 > + 	if (!p)
 > + 		error("Not enough memory!");
 > + 	return p;
 > + }
 > + #endif

 It would be traditional to let the test program core dump
 if malloc fails!
 So bltin.h should probably #define malloc chmalloc, although
 making it use the shells 'stack' memory allocater might save
 memory leaks...

 > + 	euid = geteuid();
 > + 	if (euid == 0)

 I don't think userspace ought to be checking for 'appropriate
 privileges' by checking uid == 0.  It is currently true for
 netbsd but isn't portably true.

 I haven't considered what 'test -r/w/x' should return!

 You certainly can't use open(), it doesn't do the correct
 thing for devices (the driver gets to see the open....).

 Maybe the code should check that access() gives permission
 and that one of the relevant rwx flags is set?

 access() certainly 'does what you want' for -x.

 	David

 -- 
 David Laight: david@l8s.co.uk

From: David Laight <david@l8s.co.uk>
To: NetBSD Bugs and PR posting List <netbsd-bugs@NetBSD.ORG>,
  NetBSD GNATS submissions and followups <gnats-bugs@gnats.netbsd.org>
Cc:  
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Sat, 30 Nov 2002 10:17:20 +0000

 > > + 	euid = geteuid();
 > > + 	if (euid == 0)
 > 
 > I don't think userspace ought to be checking for 'appropriate
 > privileges' by checking uid == 0.  It is currently true for
 > netbsd but isn't portably true.

 It isn't true for NFS!

 Additionally you have to use access() in order to detect
 readonly file systems.

 It is also possible that a volume (eg a CD) might be mounted
 with global read permissions (useful if not supported at the
 moment).  This wouldn't be covered by a simple check on the
 mode bits.

 So you definitely need to call access(),  whether it is
 appropriate to return false when the access call succeeds
 is another matter, but you can't return true if access would
 fail.

 FWIW if a shell wants to know the file permission bits
 it can use $(stat -f '%p' file).

 	David

 -- 
 David Laight: david@l8s.co.uk

From: woods@weird.com (Greg A. Woods)
To: David Laight <david@l8s.co.uk>
Cc: NetBSD Bugs and PR posting List <netbsd-bugs@NetBSD.ORG>,
  NetBSD GNATS submissions and followups <gnats-bugs@gnats.netbsd.org>
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Sat, 30 Nov 2002 16:26:19 -0500 (EST)

 [ On Saturday, November 30, 2002 at 09:06:36 (+0000), David Laight wrote: ]
 > Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
 >
 > > + #if defined(SHELL)
 > > + extern void * ckmalloc(size_t);
 > > + #else
 > 
 > Bung that in bltin.h

 Go for it!  ;-)  (if you do you'll see it's not quite that simple)

 (FYI the changes for -DSHELL are in the style of previous changes, not
 in the ideal way I would have done them -- in the end they are
 reasonably unobtrusive while still being viable.)

 > > + static void * ckmalloc(size_t);
 > 
 > Not needed for static function

 Tell that to the compiler -- i.e. to GCC in particular, and more
 specifically the version used by various NetBSDs, not me.  If I were to
 rule on this I'd say prototypes are not necessary or even allowed:  use
 lint!  (C prototypes are a bad implementation of a poorly concieved idea
 that does not have the desired effect unless it's so stringently forced
 that people baulk at it in the way you have.  In the mean while the
 standard parameter promotion rules of traditional C are violated and old
 code cannot just be recompiled with new compilers.  but that's a whole
 other debate... :-)

 > > + static void *
 > > + ckmalloc(size_t nbytes)
 > > + {
 > > + 	void *p = malloc(nbytes);
 > > + 
 > > + 	if (!p)
 > > + 		error("Not enough memory!");
 > > + 	return p;
 > > + }
 > > + #endif
 > 
 > It would be traditional to let the test program core dump
 > if malloc fails!

 Hah.  You're no help!   ;-)

 (what's most important here though is to be compatible with use in
 /bin/sh as a built-in function, and if my login shell dies a horrible
 death when I run it out of memory, instead of just reporting an error
 and giving me my prompt back, all because you deem error checking
 unnecessary, then you're in very big trouble!  :-))

 > So bltin.h should probably #define malloc chmalloc, although
 > making it use the shells 'stack' memory allocater might save
 > memory leaks...

 "Not my concern."  This is test/test.c, not sh/bltin/test.c after all.
 It seems the rule for this program is to only cater as much as necessary
 to the APIs used by src/bin/sh/* so that this code can be shared as a
 built-in function for /bin/sh.

 > > + 	euid = geteuid();
 > > + 	if (euid == 0)
 > 
 > I don't think userspace ought to be checking for 'appropriate
 > privileges' by checking uid == 0.  It is currently true for
 > netbsd but isn't portably true.

 Huh!?!?!?  We _are_ talking specifically and only about the NetBSD
 implementation of 'test' here, not some portable one.  POSIX explicitly
 allows the implementation to define how "privilege" is tested.  In UNIX
 this has always been done, in both userland and in the kernel, by
 testing for euid==0 -- there is no other possible way in unix since
 there is no other definition of "privilege".

 > I haven't considered what 'test -r/w/x' should return!

 I have -- that was the _entire_ point here after all.

 > access() certainly 'does what you want' for -x.

 "does NOT" -- especially not for root.  (and _never_ did -- which is, I
 believe, the entire point behind the wording in 1003.2-1992, though the
 rationale is "incomplete" and does not explain this difference with the
 original SVID Issue #1)

 -- 
 								Greg A. Woods

 +1 416 218-0098;            <g.a.woods@ieee.org>;           <woods@robohack.ca>
 Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>

From: woods@weird.com (Greg A. Woods)
To: David Laight <david@l8s.co.uk>
Cc: NetBSD Bugs and PR posting List <netbsd-bugs@NetBSD.ORG>,
  NetBSD GNATS submissions and followups <gnats-bugs@gnats.netbsd.org>
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Sat, 30 Nov 2002 16:34:26 -0500 (EST)

 [ On Saturday, November 30, 2002 at 10:17:20 (+0000), David Laight wrote: ]
 > Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
 >
 > > > + 	euid = geteuid();
 > > > + 	if (euid == 0)
 > > 
 > > I don't think userspace ought to be checking for 'appropriate
 > > privileges' by checking uid == 0.  It is currently true for
 > > netbsd but isn't portably true.
 > 
 > It isn't true for NFS!

 What does NFS have to do with the privileges of a program running on a
 given host?  Just because you're "root" on some host doesn't mean you'll
 be "root" on some other NFS server.  Except for a few very special cases
 the effect of root accesses to an NFS volume that's exported with client
 UID==0 mapped to UID=-2 (or whatever) is effectively the same, from
 'test's point of view, as it is for filesystems mounted read-only.  Test
 does not, and should not, care about the filesystem mount options here.

 > Additionally you have to use access() in order to detect
 > readonly file systems.

 No, you don't.  Please re-read again the text describing '-w' (and '-x')
 which I've quoted twice now from IEEE POSIX 1003.2-1992.


 > FWIW if a shell wants to know the file permission bits
 > it can use $(stat -f '%p' file).

 which standard is 'stat' in again?

 A portable shell script can only use 'test' -- even one that requires a
 specific 1003.2-1992 conformant runtime environment.

 -- 
 								Greg A. Woods

 +1 416 218-0098;            <g.a.woods@ieee.org>;           <woods@robohack.ca>
 Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>

From: David Laight <david@l8s.co.uk>
To: NetBSD Bugs and PR posting List <netbsd-bugs@NetBSD.ORG>,
  NetBSD GNATS submissions and followups <gnats-bugs@gnats.netbsd.org>
Cc:  
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Sun, 1 Dec 2002 20:02:11 +0000

 On Sat, Nov 30, 2002 at 04:34:26PM -0500, Greg A. Woods wrote:
 > [ On Saturday, November 30, 2002 at 10:17:20 (+0000), David Laight wrote: ]
 > > Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
 > >
 > > > > + 	euid = geteuid();
 > > > > + 	if (euid == 0)
 > > > 
 > > > I don't think userspace ought to be checking for 'appropriate
 > > > privileges' by checking uid == 0.  It is currently true for
 > > > netbsd but isn't portably true.
 > > 
 > > It isn't true for NFS!
 > 
 > What does NFS have to do with the privileges of a program running on a
 > given host?  Just because you're "root" on some host doesn't mean you'll
 > be "root" on some other NFS server.

 My point exactly! So the test program cannot use the euid to determine
 whether you have 'appropriate privileges' to access the file in question.
 Your version of test will incorrectly say that root has permission
 when in fact it does not.

 > Except for a few very special cases
 > the effect of root accesses to an NFS volume that's exported with client
 > UID==0 mapped to UID=-2 (or whatever) is effectively the same, from
 > 'test's point of view, as it is for filesystems mounted read-only.  Test
 > does not, and should not, care about the filesystem mount options here.

 The posix spec explicitly states that a test -w should fail if
 the filesystem is mounted readonly.


 	David

 -- 
 David Laight: david@l8s.co.uk

From: woods@weird.com (Greg A. Woods)
To: David Laight <david@l8s.co.uk>
Cc: NetBSD Bugs and PR posting List <netbsd-bugs@NetBSD.ORG>,
  NetBSD GNATS submissions and followups <gnats-bugs@gnats.netbsd.org>
Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
Date: Sun,  1 Dec 2002 19:24:26 -0500 (EST)

 [ On Sunday, December 1, 2002 at 20:02:11 (+0000), David Laight wrote: ]
 > Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
 >
 > On Sat, Nov 30, 2002 at 04:34:26PM -0500, Greg A. Woods wrote:
 > > [ On Saturday, November 30, 2002 at 10:17:20 (+0000), David Laight wrote: ]
 > > > Subject: Re: standards/19209: test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7)
 > > >
 > > > > > + 	euid = geteuid();
 > > > > > + 	if (euid == 0)
 > > > > 
 > > > > I don't think userspace ought to be checking for 'appropriate
 > > > > privileges' by checking uid == 0.  It is currently true for
 > > > > netbsd but isn't portably true.
 > > > 
 > > > It isn't true for NFS!
 > > 
 > > What does NFS have to do with the privileges of a program running on a
 > > given host?  Just because you're "root" on some host doesn't mean you'll
 > > be "root" on some other NFS server.
 > 
 > My point exactly! So the test program cannot use the euid to determine
 > whether you have 'appropriate privileges' to access the file in question.

 but that's not what POSIX says 'test' should be reporting.....

 > Your version of test will incorrectly say that root has permission
 > when in fact it does not.

 Yes, because this is is exactly what it should do, as per POSIX.

 > > Except for a few very special cases
 > > the effect of root accesses to an NFS volume that's exported with client
 > > UID==0 mapped to UID=-2 (or whatever) is effectively the same, from
 > > 'test's point of view, as it is for filesystems mounted read-only.  Test
 > > does not, and should not, care about the filesystem mount options here.
 > 
 > The posix spec explicitly states that a test -w should fail if
 > the filesystem is mounted readonly.

 Ah, no, it does not.  Here it is again:

     -w file      True if file exists and is writable.  True shall indicate
                  only that the write flag is on.  The file shall not be
                  writable on a read-only file system even if this test
                  indicates true.

 It's trivial to find out if a script running as root (or any other user,
 for that matter) can actually write to, or read from, a file or not.
 The intent here is to find out what the permissions bits are without
 having to use non standard utilities and without having to parse the
 output of 'ls -l'.

 This intent is made much more clear when it comes to 'execute'
 permission.  One obviously does not wish to try to execute a program
 just to find out what the state the relevant execute bits are in.  I
 believe, though there's no rationale given to confirm, that's why the
 POSIX wording was clarified over the original SVID wording in the first
 place:

     -x file      True if file exists and is executable.  True shall
                  indicate only that the execute flag is on.  If file is a
                  directory, true indicates that file can be searched.

 It only follows that '-w' and '-r' must behave the same way.
 Unfortunately for all concerned only the '-w' wording was clarified, and
 no rationale was given for why '-r' was left alone, however even the
 PASC interpretation of this issue makes it quite clear that it's OK for
 an implementation to do '-r' in the same way as '-w' and '-x', as in
 "any behaviour is allowed":

  IEEE Interpretation for 1003.2-1992                                            
  -----------------------------------                                            

  The standard does not state that -r checks the read bit, so it does not        
  have that restriction the way the -w and -x flags do.  The question of         
  which flags are checked (and the order) is unspecified by the standard,        
  and thus any behavior is allowed.  Concern over the wording of this            
  section of the standard has been forwarded to the sponsors of the              
  standard.                                                                      

  Rationale for Interpretation:                                                  
  -----------------------------                                                  
  None.                                                                          


 -- 
 								Greg A. Woods

 +1 416 218-0098;            <g.a.woods@ieee.org>;           <woods@robohack.ca>
 Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>
State-Changed-From-To: open->feedback
State-Changed-By: kre@NetBSD.org
State-Changed-When: Wed, 12 Sep 2018 18:19:55 +0000
State-Changed-Why:
I believe that the changes requested have been made, and that the
-r -w -x operators in /bin/test are now correct...   Agree?


From: "Greg A. Woods" <woods@planix.ca>
To: NetBSD GNATS <gnats-bugs@NetBSD.org>
Cc: 
Subject: Re: standards/19209 (test(1)'s -r, -w, and -x don't match POSIX for root (or 4.4BSD, or even V7))
Date: Thu, 13 Sep 2018 18:30:17 -0700

 --pgp-sign-Multipart_Thu_Sep_13_18:30:17_2018-1
 Content-Type: text/plain; charset=ISO-8859-1
 Content-Transfer-Encoding: quoted-printable

 At Wed, 12 Sep 2018 18:19:55 +0000 (UTC), kre@NetBSD.org wrote:
 Subject: Re: standards/19209 (test(1)'s -r, -w, and -x don't match POSIX fo=
 r root (or 4.4BSD, or even V7))
 >=20
 > I believe that the changes requested have been made, and that the
 > -r -w -x operators in /bin/test are now correct...   Agree?

 Yes, let's close this one!

 --=20
 						Greg A. Woods
 						Planix, Inc.

 <woods@planix.com>       +1 250 762-7675        http://www.planix.com/

 --pgp-sign-Multipart_Thu_Sep_13_18:30:17_2018-1
 Content-Type: application/pgp-signature
 Content-Transfer-Encoding: 7bit

 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.10 (NetBSD)

 iEYEABECAAYFAlubDykACgkQZn1xt3i/9H+ssQCcDEbPNf9GaII/GxEM4JZCS5zF
 6UsAoIc+q4gzaNkwNmrwLYgnt6lHjUUl
 =fO90
 -----END PGP SIGNATURE-----

 --pgp-sign-Multipart_Thu_Sep_13_18:30:17_2018-1--

State-Changed-From-To: feedback->closed
State-Changed-By: kre@NetBSD.org
State-Changed-When: Fri, 14 Sep 2018 03:18:21 +0000
State-Changed-Why:
Confirmed fixed (long ago...)


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.