Skip to contentSkip to conversation

setpeuid(pid_t, uid_t) proposal

DISCUSSION Jerry Haltom 4 participants 6 messages Aug 24, 2004 – Aug 28, 2004

lore
Share & tools
lore
#0 lore raw

Please CC me on any responses.

Now... this is my first post to the LKML concerning anything useful or practical, so bear with me. I'm trying my best to explain my idea. :) Also, I'm new (very new) to kernel hacking, so I may have missed something extremely important.

I want to propose a new base system function (and cooresponding syscall). I am tentivly calling this function setpeuid(). The function will be fairly simple:

Only a process with uid 0 may call it. The first argument is a process id. The second argument is a uid. The function is effictivly the exact same as seteuid() except that it operates on another process. Very simple explanation, now here's why.

One of the problems that I've been presented with regularly when working with Linux (and Unix in particular) is the lack of what other operating systems call "impersonation". The ability of one process not running as root to assume the identity (for a limited time) of another user ID. Securely.

My most recent experience I've been confronted with involving this is with Apache hosting a WebDAV server. WebDAV is sort of a remote file system hosted through HTTP. Apache sends and receives HTTP posts, to alter remote files. Most of you probably know this.

The problem is when accessing a multiuser WebDAV file system over HTTP, Apache on the server must either a) run as root, or b) do some really weird suid stuff. This is because it must have access to all files that the requesting user would have access to. This causing a number of
problems: Apache has more access than it needs. Files are edited as root, sometimes this doesn't work such as if those files are available over NFS or another similar situation. Files are created as root, probably with the wrong umask. There are a lot of problems. ;)

These problems would be solved if Apache could run as the user that was requesting access on the server: given shared user accounts. It would only have access to what it needs to have access to.

So, that's what's broken now. Here's the situation I'd like to be able to put myself into.

Apache runs as a low privledge user, but can obtain the permissions of the user that requested the service. Apache can't give itself access, so it relies on a seperate process to do so. A request is received to Apache. The request comes with authentication information (in a number of forms, Basic, Kerberos (GSSAPI), CRAM, NTLM, whatever). The authentication information is received by the Apache module that handles the specific authentication type. This module passes the security information to a seperate stand alone daemon, which is running as root. This daemon is highly audited and does one purpose, and does it well. The daemon processes the security crediantials, validates them, uses whatever policy is neccassary to determine if the user is authorized, and then setpeuid's the calling process (Apache). The apache module now returns, the request proceeds. When the request is over, the process goes back to the user it was previously (either by signaling the daemon it is done, or calling yet another new function: resetpeuid()).

That's just one use case... there are a number of others. Such as a secure "Run As" feature for desktop users... FTP servers, SSH could even use it to totally remove the need for any root presence. There are a number of possibilities. Too many to list. Use your imagination.

Anyways, the function required is pretty simple. I'd like some of you wizzes to tell me what's wrong with my thinking.

In the mean time, I'm working on implementing this right now to see how it goes. But this is my first actual kernel hacking, so we'll see. ;)

Thanks for your time.

Jerry Haltom <[email protected]>

#1 lore raw
Quoted 9 lines · Jerry Haltom

Apache runs as a low privledge user, but can obtain the permissions of the user that requested the service. Apache can't give itself access, so it relies on a seperate process to do so. A request is received to Apache. The request comes with authentication information (in a number of forms, Basic, Kerberos (GSSAPI), CRAM, NTLM, whatever). The authentication information is received by the Apache module that handles the specific authentication type. This module passes the security information to a seperate stand alone daemon, which is running as root. This daemon is highly audited and does one purpose, and does it well.

What does this buy you that having the separate daemon just do a fork/seteuid/exec to do the work, and passing the results back via a Unix socket or shared mem or what-have-you?

Alternatively, what would this give you that isn't already done by the SELinux support for cron, or Apache suexec, which already allow "run the following in another context" functionality?

#2 lore raw
Quoted 3 lines

What does this buy you that having the separate daemon just do a fork/seteuid/exec to do the work, and passing the results back via a Unix socket or shared mem or what-have-you?

To do a seteuid the daemon would need to be root. This means it would be processing remote information of a sensitive nature, such as Kerberos ticket acquisition, SASL stuff, etc, as root. Something I'm trying to avoid. It has to first determine what uid before it can call setuid and the process of determining this uid is very sensitive in many situations.

Quoted 3 lines

Alternatively, what would this give you that isn't already done by the SELinux support for cron, or Apache suexec, which already allow "run the following in another context" functionality?

I don't know about this SELinux thing you speak of yet, I'll look into it. Apache suexec spawns a seperate process for each individual request. It cannot function properly with in process modules, such as mod_webdav, mod_php, and... all the others. Being able to function in process is the main idea behind this.

Jerry Haltom <[email protected]>

#3 lore raw
Quoted 5 lines · Jerry Haltom
Quoted 3 lines

What does this buy you that having the separate daemon just do a fork/seteuid/exec to do the work, and passing the results back via a Unix socket or shared mem or what-have-you?

To do a seteuid the daemon would need to be root.

And how is this different from:

Quoted 4 lines

Only a process with uid 0 may call it. The first argument is a process id. The second argument is a uid. The function is effictivly the exact same as seteuid() except that it operates on another process. Very simple explanation, now here's why.

.....

Quoted 3 lines

Apache runs as a low privledge user, but can obtain the permissions of the user that requested the service. Apache can't give itself access, so it relies on a seperate process to do so. A request is received to

You've already stated that the separate process has to be running as root....

#4 lore raw
In reply to Jerry Haltom
Quoted 8 lines · Jerry Haltom

I want to propose a new base system function (and cooresponding syscall). I am tentivly calling this function setpeuid(). The function will be fairly simple:

Only a process with uid 0 may call it. The first argument is a process id. The second argument is a uid. The function is effictivly the exact same as seteuid() except that it operates on another process. Very simple explanation, now here's why.

LOL pid_t? What if task calling the server dies before the server calls setpeuid()? Some other users task may now get new credentials.

Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk)
lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import
8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
#5 lore raw
In reply to Jerry Haltom
Quoted 5 lines · Jerry Haltom

One of the problems that I've been presented with regularly when working with Linux (and Unix in particular) is the lack of what other operating systems call "impersonation". The ability of one process not running as root to assume the identity (for a limited time) of another user ID. Securely.

For the file system case there is setfsuid. You can also make use of seperate effective/real/saved uids through setreuid() and friends. setfsuid() also addresses the other problem - if a process switches fully to my ID then I can play with it - kill it etc.

Quoted 3 lines

These problems would be solved if Apache could run as the user that was requesting access on the server: given shared user accounts. It would only have access to what it needs to have access to.

This is actually not hard to do if your server is designed to be a little smarter. The apache model doesn't fit it well although apache could make some use of setfsuid() as unfsd (user mode nfsd does) and it does support doing this through suexec.

One little non-obvious trick that might make this work faster would be to keep track of running webdav servers for each active user and use a redirect from the main server to communicate with it, and when the client has idled out to reclaim it and hand the port back to the main server instance so that users get redirected again

Quoted 4 lines

That's just one use case... there are a number of others. Such as a secure "Run As" feature for desktop users... FTP servers, SSH could even use it to totally remove the need for any root presence. There are a number of possibilities. Too many to list. Use your imagination.

sshd can already do this. The "run as root" desktop feature already exists using the existing auth functionality (see "usermode")

Quoted 2 lines

Anyways, the function required is pretty simple. I'd like some of you wizzes to tell me what's wrong with my thinking.

Actually its easy to implement and horrible to get right - there is no locking on uid changes. When a task is in a syscall the entire syscall knows that the security for the process will not be changing.

Quoted 2 lines

In the mean time, I'm working on implementing this right now to see how it goes. But this is my first actual kernel hacking, so we'll see. ;)

Have fun - the security stuff is hard but getting something working as you describe for learning purposes and armwaving that issue should be nice little project.

Alan