[comp.os.minix] Maybe a easy solution for the --x--x--x won't exec problem ?

schlut@oski.toppoint.de (Olaf Schlueter) (04/22/91)

Recently someone else reported, that the change of about 3 lines
in both fs and mm sources would solve the problem, that read
permission is a prerequisite for execution in minix.

I want suggest, that just deleting a line in fs/stadir.c would
suffice. During an exec call, permissions are checked twice:
once by fs during an open, next by mm after sucessfully opening
the file.

mm calls fs to open the file to be executed for reading. Before
doing so, it tells fs to change to the working dir of the user
doing the exec call. There is a special check in fs/stadir.c
in the routine do_chdir(), that looks whether the caller is mm.
if so, it sets the eff. uid of mm's fproc entry to the caller
which caused the exec call. mm's normal uid/gid is root/root.

This temporary eff. uid change causes the open call on the
file to be executed to fail. If mm's eff uid would remain
root, the open would succeed even on files without any read
permissions, since fs tries to validate the OPEN call not
the exec call (it does not know anything about an exec call
pending). The check for execution permissions against the
callers uid/gid is done by mm.

I decided to remove the change of the eff uid of mm in
do_chdir. This allows files without read permission to
be executed. 

There is another problem related to the creation of core
files. core files are now dumped with uid/gid root/root.
In original minix they are dumped with uid/gid <actual user>/root.
Since write permissions on dirs or existing core files are
again validated by mm, this is only a small problem.


-- 
Olaf Schlueter, Sandkuhle 4-6, 2300 Kiel 1, Germany, Toppoint Mailbox e.V.
schlut@oski.toppoint.de, olaf@tpki.toppoint.de, ...!unido!tpki!olaf

hp@vmars.tuwien.ac.at (Peter Holzer) (05/01/91)

schlut@oski.toppoint.de (Olaf Schlueter) writes:

>[Proposes that FS should open files to be exec'ed with euid of mm
>instead of user so that non-readable files can be executed]

There is a security problem with this approach (If you care about
security). Under Minix and Unix, to execute a program you do not only
need execute-permissions for the file, but also search-permissions for
all the directories leading to it. If FS opens the file with MMs
permissions instead of that of the user, you can execute any program if
it is world-executable and you know its full pathname. If I write
programs I don't want other users to use, I just turn off the x-bit of
the directory and can still work with my normal umask (022). I couldn't
do that anymore with your `fix'.

--
|    _  | Peter J. Holzer                       | Think of it   |
| |_|_) | Technical University Vienna           | as evolution  |
| | |   | Dept. for Real-Time Systems           | in action!    |
| __/   | hp@vmars.tuwien.ac.at                 |     Tony Rand |

tonyg@cs.uq.oz.au (Tony Gedge) (05/02/91)

In <1991Apr30.185457.29113@email.tuwien.ac.at> hp@vmars.tuwien.ac.at (Peter Holzer) writes:
>programs I don't want other users to use, I just turn off the x-bit of
>the directory and can still work with my normal umask (022). I couldn't
>do that anymore with your `fix'.

As an aside, I got the `--x--x--x' behavior in my kernel by adding an if
condition in fs/open.c.  It is inserted just before the file permission
checking switch statement.  Basically, what I do it say:

if (calling-proc != MM) {
	check-file-permission-switch-statements
	}

Is there a security bug/something not nice in doing it this way?

Tony Gedge.

--
 -------------------------------------------------------------------------
| Computer Science Department,        | tonyg@cs.uq.oz.au   (Tony Gedge)  |
| University of Queensland, Australia.| "cc stands for Cryptic Crossword" |
 -------------------------------------------------------------------------

evans@syd.dit.CSIRO.AU (Bruce.Evans) (05/03/91)

In article <1991Apr30.185457.29113@email.tuwien.ac.at> hp@vmars.tuwien.ac.at (Peter Holzer) writes:
>schlut@oski.toppoint.de (Olaf Schlueter) writes:
>
>>[Proposes that FS should open files to be exec'ed with euid of mm
>>instead of user so that non-readable files can be executed]
>
>There is a security problem with this approach (If you care about
>security). Under Minix and Unix, to execute a program you do not only
>need execute-permissions for the file, but also search-permissions for
>all the directories leading to it. If FS opens the file with MMs

The original proposal depends on MM checking the permission bits on the
file itself. But as Peter points out, this doesn't check the permissions
for the rest of the path.

I have already fixed the bug for 1.6, so further discussion is mostly
academic. Wait to find the bugs in my fix :-).

I used the trick of opening the file with MM as root. Actually, this is
the natural way - switching to the user's context is tricky and had
other bugs. I rejected MM's checking of permissions on aesthetic grounds -
only FS really knows how to do it. Also, it saves code, and I wanted to
exercise the fix for another 'x' permissions bug in FS (at least one 'x'
bit was required to search directories even for root, because 'x' for
execute and 'x' for search-directory were confused).

I called access() from MM to check the permissions. Since access() checks
the whole path, the new bug is avoided. There are 2 problems with access()
that make it useless for applications but don't matter here:

1) It uses the real ids and not the effective ids. Fixed by making the
real ids = the effective ids in the partial switch to the users context.

2) Races. One user might access() a file and then open() it while another
user might change the file permissions in the middle. But a user can never
win such a race with MM. Oops, maybe it can:

    MM:    access("/fd/foo", ...);	/* floppy mounted on /fd */
    MM:    waits for FS
    FS:    waits for floppy
    USER:  unlink("/fd/foo");
    USER:  waits for FS
    FS:    finishes access() and replies to MM
    FS:    either it returns to MM here or it does the unlink
    MM:    [actually it would do some tell_fs() calls here]
    MM:    open("/fd/foo", ...) after access() succeeded
    MM:    waits for FS
    FS:    do the unlink if not already
    FS:    do the open. It fails!
    MM:    panics

Doing the open before the access may be a good enough fix. The open is done
as root so it will succeed if the file exists. Too bad if the permissions
changed just after the file was opened; the new permissions are just as valid.

What about other races between MM and FS? It's unfortunate for them to get
tangled up like this just because they are separate. FS has complete
information about the permissions when it does the open, but the open()
interface does not provide a way to return it.
-- 
Bruce Evans		evans@syd.dit.csiro.au