[braindamaged?] use of access(2) -- long note

Stephen J. Friedl friedl at vsi.UUCP
Mon Feb 29 17:32:38 AEST 1988


Netlanders,

     This comes up all the time and it has been very frustrating.
I want to get this off my chest, see if anybody else has seen
this problem, get some suggestions, and plea for people not to
misuse the access(2) system call.

     First, a little background.  We develop business-type
applications using a commercial database package.  We use a 3B2
but I have seen this problem all over.  We like to set these
systems up in a secure manner with protected project areas and
limited entry points (say, just a single "inventory" command that
calls up a menu).

     To do this, we provide a front-end program (the "inventory"
program mentioned above) and make it set-group-id to the project.
Here, assume that the group is "inv" and only the project uses it
(everybody else is "staff" or whatever).  All the project
directories are rwxrwx--- and this effectively keeps everybody
else out.  It keeps the inventory package out too.

     The problem is with the access(2) system call.  Reading the
manual page of this function makes you think that this is a
handy-dandy "does the file exist?" function and it is used this
way by a lot of programs.  The curious/insighful person might
wonder why they would make a system call like this when stat(2)
can trivially do the same job -- access(2) should be access(3).
I wondered for a long time too.

      Access(2) should almost never be used.  It does what
stat(2) does except it uses the REAL userid and not the EFFECTIVE
userid like every other system call uses.  It is designed for use
by setuid/setgid programs to verify the permissions of the
"underlying" user.

     To illustrate, let's say that the uucp Systems or L.sys file
on your machine is unreadable by anybody other than uucp but you
want to see it.  So, you run /usr/bin/cu, which is setuid "uucp"
and call another system.  You figure that

        ~%put /usr/lib/uucp/Systems /tmp/Systems.stolen

will write the file over there.  Uucp clearly has permission to
access this file, and the open(2) call will work just fine, but
cu won't do this for you, probably because of access(2) [note:
several other methods come to mind but this is a pretty good demo
of access].  When you are running cu, your permissions might be
as follows:

        real uid      = friedl (that's me)
        effective uid = uucp   (that's him/her/it)

     When cu does an access("/usr/lib/uucp/Systems, READ), it is
asking "does the real uid (friedl) have READ access to this
file?" Access says no so cu tells me to get lost.

     It is possible to implement access(2) yourself with stat and
getuid/getgid but it is a little tricky and error prone.
Presumably the original Unix guys decided to put it in the kernel
to keep it safe and easy.

     "OK", you say, "so we have this handy function that does a
useful task.  If I'm not running setuid or setgid then it doesn't
matter".  You're right, your program may not be setuid but I
might want to run it that way as part of a larger system.  This
messes me up.

    [Disclaimer: I don't *know* that the shell is doing things
this way but it sure looks like it].  When the shell is asked to
execute a command without a full pathname, it searches along the
$PATH for the program you've requested.  For each component in
$PATH, it constructs the full pathname and runs access(2) on it.
If access says OK then it does an actual exec.  I would guess
this is done because access(2) is a lot quicker than trying a lot
of execs and having them fail, but I'm not sure.

     The problem comes about when the directory is open to the
group but closed to other.  Say I have a program:

  10 -rwxr-x---   1 inv   inv    4724 Feb 26 22:57 /usr/acct/report

and "/usr/acct" is in my search path.  In a shell script called
from a menu I try to execute "report" without a full pathname.
The shell looks in the $PATH, does access("/usr/acct/report") but
it fails because *my* personal group (staff) has no permissions
and I get a message to that effect from the shell.  If I type the
command so $PATH is not used, it works fine, presumably because
the shell believes you know where it is and just does an exec
directly without the access.  This problem occurs whether setuid
or setgid is used: if the effective user/group has permission but
the underlying (real) user/group does not, access(2) fails even
though exec(2) would not.

     There are a number of possible solutions to this:

(1)  Forget setuid/setgid.  I really don't like this because it
     requires full access for everybody.  I have a little sign on
     my wall:         _____
	             /   //\
	       	   /    //   \
	          | chmod 777 |
	           \  //     /
	             \/____/

     (imagine the sign being red and round).  I think 777 is
     sloppy.

(2)  Make all the commands open.  This is what we usually do but
     I don't like it: I make the main project directory rwxrwx--x
     and give the minimum permissions possible.  I have to really
     keep on my toes to have a secure system but not forget a
     chmod a+x somewhere.

(3)  Use full pathnames.  Sigh, that is really a lot of work.
     For the really secure systems it is the only way to really
     do it but it sure makes scripts messy and hard to maintain.

(4)  Make all the users in the same group.  This is not a bad
     idea but it gets messy if we develop more than one unrelated
     system on a machine -- this happens a lot.

(5)  Fix the shell ha ha ha.

(6)  Something I haven't thought of.  Anybody?

     If the shell were the only place it would not be so tough
but it is not.  The test(1) command uses access(2) for some of
its queries, so

     if [ -r $filename ] ; then
          ...

says "not readable" for the same reasons, so $filename must be
readable by everybody.  Note: I understand that System V Release
3 fixed test(1) but the $PATH search still seems to be broken.

     There are others: The tmpnam(3) function call uses
access(2), the Informix screen manager (sperform) uses it when
looking for forms to run, etc., etc.

     [coming down to the wire]  Am I correct that the majority of
uses of access(2) are incorrect?  What can be done about this?
Anybody have any thoughts?

     Sigh,
     Steve

P.S. - sorry this is so long...
-- 
Life : Stephen J. Friedl @ V-Systems, Inc/Santa Ana, CA    *Hi Mom*
CSNet: friedl%vsi.uucp at kent.edu  ARPA: friedl%vsi.uucp at uunet.uu.net
uucp : {kentvax, uunet, attmail, ihnp4!amdcad!uport}!vsi!friedl



More information about the Comp.unix.wizards mailing list