[comp.os.minix] SETUID problems with mkdir & rmdir

ESC1332@ESOC.bitnet (K.Keyte) (07/14/87)

Of course everyone noticed, after a short time, that the 'cp' command
doesn't maintain the SETUID bit. This is clearly for security. Setting the
bit with chmod is no problem. There is another problem, however, with the
mkdir and rmdir. They are not normally SETUID (at least, not on UNIX). The
SETUID bit is needed on MINIX because they call the mknod system service
which is reserved for super-user only. To check that the user actually has
the required access to the parent directory, mkdir performs an 'access' call.
This is almost entirely useless because the setting of the SETUID means that
the caller automatically gets a protection mode permission of 07 (meaning that
all access modes are granted). So, the overall effect is that mkdir and rmdir
can be used by anyone to create and remove directories anywhere! This isn't
right, and there are a number of possibilities.

Has anyone tried anything, or got any ideas? I made an initial attempt by
removing the effective super-user uid before the access call, but of course
this means that real AND effective uids are then non super-user, i.e. you
can't re-enable the super-user uid with setuid, and the subsequent mknod
call fails! The access call makes a further call to 'forbidden' with a flag
set to indicate that it should check the REAL uid and not the EFFECTIVE uid.
This is ignored, since the file system 'init' program automatically sets the
super-user flag for any caller having an effective uid of the super-user.
It seems that the solution might be to steal access and modify it a bit,
and use the new version inside mkdir and rmdir. Please give me your comments.
Perhaps I'm overlooking a more obvious solution, but if I'm not I'm quite
prepared to make the changes and post them out.

PS: Are we actually allowed to mail Minix electronically (not the original
    source of course, but changes such as the one I've outlined above)?

Karl Keyte

henry@utzoo.UUCP (Henry Spencer) (07/16/87)

> Of course everyone noticed, after a short time, that the 'cp' command
> doesn't maintain the SETUID bit...

The finger of shame points at whoever wrote cp, then.  V7 cp preserves the
setuid bit.

> ... There is another problem, however, with the
> mkdir and rmdir. They are not normally SETUID (at least, not on UNIX).

Sorry, they *are* on Unixes (like V7) which do not have mkdir() and rmdir()
system calls.  Believe me -- utzoo is a V7.


> ... To check that the user actually has
> the required access to the parent directory, mkdir performs an 'access' call.
> This is almost entirely useless because the setting of the SETUID means that
> the caller automatically gets a protection mode permission of 07 (meaning that
> all access modes are granted). So, the overall effect is that mkdir and rmdir
> can be used by anyone to create and remove directories anywhere! ...

Sorry, no, you have misunderstood the fine points of setuid bits and the
access() system call.  The access() call checks permissions against the
"real" userid and groupid, which are *not* changed by the setuid bit.
This is the way it works in V7 and true V7-compatible systems, anyway.

Making mkdir and rmdir owned by root with the setuid bit on is precisely
the right thing to do, unless Minix has done something bizarre.
-- 
Support sustained spaceflight: fight |  Henry Spencer @ U of Toronto Zoology
the soi-disant "Planetary Society"!  | {allegra,ihnp4,decvax,utai}!utzoo!henry

ESC1332%ESOC.BITNET@wiscvm.wisc.edu (K.Keyte) (07/22/87)

Let me straighten this mess out with regards to SETUID and mkdir/rmdir...

MINIX WAS doing something wrong with the access() system call. The error
itself was in forbidden() where it checks the permissions. It's supposed
to allow the option to check REAL or EFFECTIVE uids, and access() always
asks to check the REAL uid. HOWEVER, forbidden() looks at the global variable
super_user (which is set TRUE iff the EFFECTIVE uid is that of the super-user)
and grants FULL access if this is set. This is incorrect, the code in
forbidden() should be changed FROM:

     if (super_user)
           perm_bits = 07;

TO:  if (test_uid == SU_UID)
           perm_bits = 07;

I hope this stops the barrage of mis-understandings, and we can close the
matter.

Point 2
-------

I've written a noddy routine to load the MINIX clock from the CMOS battery-
backed RAM on an AT. If anyone's interested in the code, let me know and I'll
either send them out individually or back to the list depending on the
response.

Karl

rmtodd@uokmax.UUCP (Richard Michael Todd) (07/22/87)

In article <8308@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes:
>Sorry, no, you have misunderstood the fine points of setuid bits and the
>access() system call.  The access() call checks permissions against the
>"real" userid and groupid, which are *not* changed by the setuid bit.
>This is the way it works in V7 and true V7-compatible systems, anyway.
Alas, MINIX access() is broke in a couple of ways.  The problems lie in the
forbidden() routine in the file server, which is supposed to check for given
types of access against either real or effective uid, depending on a flag
passed to the function.  It is called by do_access to check against real
uid, and everywhere else to check against euid.
  Problem 1:  forbidden() should grant all access to the file if the uid
being checked against (real or effective, depending on the flag) is 0.
Alas, the code to do this takes the easy way out,testing a global flag:
	if (super_user) { 		(line 11800 of the book)
		perm_bits = 07;
	} else {...
and this flag is set whenever euid==0.  Since mkdir and rmdir always run
as euid==0, this allows them access to everything.
  Problem 2:  forbidden, to check if a file is accessible in a certain mode,
has to have access to the inode data for the file.  (Forbidden's first
arg. is a pointer to the inode struct for the file being checked).  To get
the inode pointer for a given filename, the caller has to first call eat_path.
Eat_path has to look in the various directories specified in the pathname,
checking each step of the way if the directory is searchable.  The checks
are always done against effective uid.  This is not quite correct.  If
we do an access("/foo/bar",2), our real uid is not root and our euid is,
if our real uid won't allow us execute (search) permission for /foo, the
access call should fail.  It will succeed.  (Admittedly these circumstances
are rather unusual, but it is nonetheless a bug, and one that would be a bit
tricky to fix.)
>Making mkdir and rmdir owned by root with the setuid bit on is precisely
>the right thing to do, unless Minix has done something bizarre.
Not bizarre, just broken.
--------------------------------------------------------------------------
Richard Todd
USSnail:820 Annie Court,Norman OK 73069
UUCP: {allegra!cbosgd|ihnp4}!okstate!uokmax!rmtodd