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:
(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.