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

henry strickland strick at stratus.UUCP
Wed Mar 2 09:42:50 AEST 1988


In article <59 at vsi.UUCP> friedl at vsi.UUCP (Stephen J. Friedl) writes:
>
> ....
>
>     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.

(*
	The question was kind of vague (if it was a question: it's more
	of a proclamation:  "Access(2) should almost never be used.")
	I think the following answers some aspect of your problem;
	particularly the 
		{ setuid(geteuid()) ; setgid(getegid()) }
	line may be what you need.
*)


I also feel that access() should almost never be used, but for
quite different reasons.

First (and I think you realized it) you're not using access()
for what it was intended.  

/*	Like you explained, it was intended for programs such as "mail"
	to make sure the REAL user/group has permission
	to write/read stuff from where the user has said to write/read
	the stuff from.      

	*** There are security holes in this approach. ***
	These holes are why I say one should rarely use access().

	The correct thing to do is 
		{ setuid(getuid()) ; getgid(getgid()) }
	before doing the i/o.   This allows the real unix permission
	checking to do its job.   This is the safe approach.

	( Even as we speak there are major UNIX
	  "supermicros" being sold that run mail as root and
	  don't use EITHER the flawed access() or the better
	  setuid,setgid approach.       I've told them about
	  it, but they haven't fixed it, to my knowledge.
	  But unless you're a real hack-unix
	  guru and think you know ALL the tricks, don't
	  ever assume your machine doesn't have one of these real
	  nasty rootholes.  BTW, I think berkeley /bin/mail is an example
	  of setuid-root code done correctly. )

	If you later will need the capabilities of your effective
	uid and gid, fork a child to do the job, and wait for it
	to die.   Then continue.
*/


But back to your problem.

How you should be doing things is also with the real unix permission
checking.

If you want to know if your effective uid/gid has permission
to read a file or directory, you can just try opening it.

But if you want to be using access(), do
		{ setuid(geteuid()) ; setgid(getegid()) }
(and then, if you like, use access).   It seems to me that your entire program
could work by doing this at the top of the program and then just
forgetting about it.  Or if you do need to open/creat some of the real
user's files, do all of that open/creating BEFORE doing the above line.
Be sure the program has no shell escapes, etc!
Opening the real user's files early and eliminating shell escapes seems 
far less drastic than any of the things you enumerated in your posting.

If your program is going to be needing a combination of real and
effective permissions at many points throughout, you can either

	-- keep the origional process with the different real/effective
		 permissions and do a lot of forking when the real permits
		are needed (or when you give the user a shell escape, etc.)

or else
	-- fork off a child with a pipe to it so that you can give it 
		commands, and let the child run as the real userid:
			{ setuid(getuid()) ; getgid(getgid()) }
		Then the parent can run as the effective id:
			{ setuid(geteuid()) ; setgid(getegid()) }
		and you've got either when you need it.
		Depending on how complex your application is, 
		this could get really ugly.

I'm sure that there is a real solution to your problem, without resorting
to any of the things your enumerated, or else it would have been fixed
already.   

I think that access() is a late addition to unix (when did it come?).
You're right, anything can be done without it, but using stat() as
you suggested may be as bad as access().



-- 
Henry Strickland     <strick at gatech.edu>     gatech!strick   404-676-1313



More information about the Comp.unix.wizards mailing list