2008-12-02 23:55:58

by Geoffrey McRae

[permalink] [raw]
Subject: New Security Features, Please Comment

This is my first patch to the linux kernel, so please forgive me if I
have broken any posting rules. Also, I am not on the mailing list, so
please CC me on any replies to this.

A side note before I start, the links to the linux howtos on the mailing
list info page are broken, someone might want to fix that.

I posted a message in linux-api yesterday regarding this, but had no
responses. At this point I am looking for comments regarding these new
syscalls and the likelyhood of having this patch applied.

As the engineer for a web hosting company I have seen the need for
grater control over a processes uid/gid. Currently with shared virtual
hosting solutions, if for security we wish to run a shared CGI language
(such as PHP) as the user that owns the website we are forced to fork a
new process per request, then call setuid/gid and then launch the script
language. This ofcource is resource intensive, but at present there is
no other solution.

My patch adds four new syscalls to the kernel that allows this issue to
be overcome, and I am sure that it could find application in many other
programs. The syscalls are:

* long enable_setpresuid(uid_t start, uid_t end);

This function enables the use of the setpresuid call for the calling
process, the calling process has to have CAP_SETUID permission to call
this function. The start and end parameters specify the uid range that
the setpresuid must be called with.

* long enable_setpresgid(gid_t start, gid_t end);

This function is the same as above, except it enables the setpresgid
call for the specified gid range.

* long setpresuid(pid_t pid, uid_t ruid, uid_t euid, uid_t suid);

This function changes the specified IMMEDIATE child pid's real, saved
and effective uid to the specified uid. Returns -EPERM if the
enable_setpresuid call has not been made first.

* long setpresgid(pid_t pid, gid_t rgid, gid_t egid, gid_t sgid);

This function does the same as above, except it applies to the group of
the IMMEDIATE child.

The reason for the enable functions is so that the calling app can drop
root privlages after enabling the setpresuid/setpresgid for a certian
range of uid/gid numbers. This allows the parent process to change its
child processes (forked) uid/gid at any time without needing root access
while being secure so that it can not set its child processes to users
such as root.

An example of its usage follows...

int main()
{
pid_t child;

/* enable the setpres* functions for ids 1000-9999 */
enable_setpresuid(1000, 9999);
enable_setpresgid(1000, 9999);

/* drop to an un-privlaged user */
setresuid(65534, 65534, 65534);

/* fork a useless child for example sake */
child = fork();
if (child == 0) {
sleep(10);
return 0;
}

/* change the childs uid/gid to 1000 */
setpresuid(child, 1000, 1000, 1000);
setpresgid(child, 1000, 1000, 1000);

/* wait for the child to terminate */
wait(NULL);
return 0;
}

For the patch and a bit more information please goto:
http://www.spacevs.com/rambles/setuid2.php

Even though not stated on the website, this code is released under
whatever licence is needed to get it into the kernel.

-Geoffrey McRae


2008-12-03 00:53:45

by Alan

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

> (such as PHP) as the user that owns the website we are forced to fork a
> new process per request, then call setuid/gid and then launch the script
> language. This ofcource is resource intensive, but at present there is
> no other solution.

It's pretty much the minimal requirement for any kind of security because
you need the separate process/file environment. It's not helped by the
fact some of the scripting languages don't support an internal fork/exec
that preserves bootstrapped interpreter state but that is a different
problem.

> child processes (forked) uid/gid at any time without needing root access
> while being secure so that it can not set its child processes to users
> such as root.

You then need locking to handle all the horrible corner cases such as
changing uid during a file open. You really really want a process to
change its own uid somehow, even if that is done by some method other
than setuid.

Models that have been talked about but not implemented have included
things like passing 'authority' of some kind by file handles, so the
child receives an authority and then uses it.

Alan

2008-12-03 01:04:14

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

Sorry all, there is a bug in the patch that causes the compile to
fail... typo in the defines for ia32. I will upload a new patch as soon
as I test compile my new changes.

On Wed, 2008-12-03 at 10:28 +1100, Geoffrey McRae wrote:
> This is my first patch to the linux kernel, so please forgive me if I
> have broken any posting rules. Also, I am not on the mailing list, so
> please CC me on any replies to this.
>
> A side note before I start, the links to the linux howtos on the mailing
> list info page are broken, someone might want to fix that.
>
> I posted a message in linux-api yesterday regarding this, but had no
> responses. At this point I am looking for comments regarding these new
> syscalls and the likelyhood of having this patch applied.
>
> As the engineer for a web hosting company I have seen the need for
> grater control over a processes uid/gid. Currently with shared virtual
> hosting solutions, if for security we wish to run a shared CGI language
> (such as PHP) as the user that owns the website we are forced to fork a
> new process per request, then call setuid/gid and then launch the script
> language. This ofcource is resource intensive, but at present there is
> no other solution.
>
> My patch adds four new syscalls to the kernel that allows this issue to
> be overcome, and I am sure that it could find application in many other
> programs. The syscalls are:
>
> * long enable_setpresuid(uid_t start, uid_t end);
>
> This function enables the use of the setpresuid call for the calling
> process, the calling process has to have CAP_SETUID permission to call
> this function. The start and end parameters specify the uid range that
> the setpresuid must be called with.
>
> * long enable_setpresgid(gid_t start, gid_t end);
>
> This function is the same as above, except it enables the setpresgid
> call for the specified gid range.
>
> * long setpresuid(pid_t pid, uid_t ruid, uid_t euid, uid_t suid);
>
> This function changes the specified IMMEDIATE child pid's real, saved
> and effective uid to the specified uid. Returns -EPERM if the
> enable_setpresuid call has not been made first.
>
> * long setpresgid(pid_t pid, gid_t rgid, gid_t egid, gid_t sgid);
>
> This function does the same as above, except it applies to the group of
> the IMMEDIATE child.
>
> The reason for the enable functions is so that the calling app can drop
> root privlages after enabling the setpresuid/setpresgid for a certian
> range of uid/gid numbers. This allows the parent process to change its
> child processes (forked) uid/gid at any time without needing root access
> while being secure so that it can not set its child processes to users
> such as root.
>
> An example of its usage follows...
>
> int main()
> {
> pid_t child;
>
> /* enable the setpres* functions for ids 1000-9999 */
> enable_setpresuid(1000, 9999);
> enable_setpresgid(1000, 9999);
>
> /* drop to an un-privlaged user */
> setresuid(65534, 65534, 65534);
>
> /* fork a useless child for example sake */
> child = fork();
> if (child == 0) {
> sleep(10);
> return 0;
> }
>
> /* change the childs uid/gid to 1000 */
> setpresuid(child, 1000, 1000, 1000);
> setpresgid(child, 1000, 1000, 1000);
>
> /* wait for the child to terminate */
> wait(NULL);
> return 0;
> }
>
> For the patch and a bit more information please goto:
> http://www.spacevs.com/rambles/setuid2.php
>
> Even though not stated on the website, this code is released under
> whatever licence is needed to get it into the kernel.
>
> -Geoffrey McRae
>

2008-12-03 01:44:32

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Wed, 2008-12-03 at 00:53 +0000, Alan Cox wrote:
> > (such as PHP) as the user that owns the website we are forced to fork a
> > new process per request, then call setuid/gid and then launch the script
> > language. This ofcource is resource intensive, but at present there is
> > no other solution.
>
> It's pretty much the minimal requirement for any kind of security because
> you need the separate process/file environment. It's not helped by the
> fact some of the scripting languages don't support an internal fork/exec
> that preserves bootstrapped interpreter state but that is a different
> problem.
>

But once this set is introduced a HTTP server could be written that uses
forked children to handle requests, that have their identity swtiched
before doing any work, including parsing CGI scripts.

This does not only apply to HTTP servers though, there are many cases
where it is nessacary to become a user, ie, to deliver email to the
user's home directory.

> > child processes (forked) uid/gid at any time without needing root access
> > while being secure so that it can not set its child processes to users
> > such as root.
>
> You then need locking to handle all the horrible corner cases such as
> changing uid during a file open. You really really want a process to
> change its own uid somehow, even if that is done by some method other
> than setuid.

The idea is to not allow the child to change its own uid, or give the
child any elevated privlages so that should the child be compromised via
buffer overflow or some other bug, it cant be abused.

>
> Models that have been talked about but not implemented have included
> things like passing 'authority' of some kind by file handles, so the
> child receives an authority and then uses it.
>
> Alan

I would welcome more information as to how this can break applications
as I am very new to kernel hacking and would like to solve this
performance vs security problem once and for all.

-Geoff.

2008-12-03 02:12:38

by David Newall

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

Geoffrey McRae wrote:
> But once this set is introduced a HTTP server could be written that uses
> forked children to handle requests, that have their identity swtiched
> before doing any work, including parsing CGI scripts.

But a child could be one user the first time it does work, and another
user the next time. What prevents the child from opening a file while
the first user, and reading or writing it while the second? That's
exactly what you don't want to permit.

2008-12-03 02:55:51

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Wed, 03 Dec 2008 12:44:17 +1100, Geoffrey McRae said:

> I would welcome more information as to how this can break applications
> as I am very new to kernel hacking and would like to solve this
> performance vs security problem once and for all.

A *lot* of software has implicit assumptions - for instance, that your process
UID remains constant unless you intentionally did a setuid() call.

Read Henry Spencer's (now ancient but still educational) write-up on *some* of
the things that can happen to set-UID programs:

http://www.daemon-systems.org/man/setuid.7.html

Now consider that *any* program that gets its UID suddenly changed on it
just became vulnerable to all that stuff that Henry writes about.

News flash - most programmers who wrote code thinking it would run as the
same userid the whole time don't do checks for all the sort of stuff that
Henry warns about when programs suddenly get invoked with more privilege
than they were designed to handle.

Then there's the opposite case - somebody manages to trick you into nuking the
permissions on the right process-ID but wrong executable. Hilarity ensues when
the process is running with *less* privilege than it expected. Go and read up
on how Sendmail failed back around 2000, and understand *why* it failed. Just
google for 'sendmail CAP_SETUID' and start reading. Then think what happens if
somebody manages to get PHP to exec() some other binary (a set-UID one) and
it's busy running when you whack its UID.

That's just off the top of my head.

Then go look at kernel/sys.c and read the comments just before the functions
sys_setpgid(), sys_setregid(), and sys_setuid(), and figure out how the
saved uid enters into things....

There be serious and nasty dragons in there...


Attachments:
(No filename) (226.00 B)

2008-12-03 04:02:55

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Tue, 2008-12-02 at 21:55 -0500, [email protected] wrote:
> On Wed, 03 Dec 2008 12:44:17 +1100, Geoffrey McRae said:
>
> > I would welcome more information as to how this can break applications
> > as I am very new to kernel hacking and would like to solve this
> > performance vs security problem once and for all.
>
> A *lot* of software has implicit assumptions - for instance, that your process
> UID remains constant unless you intentionally did a setuid() call.
>
> Read Henry Spencer's (now ancient but still educational) write-up on *some* of
> the things that can happen to set-UID programs:
>
> http://www.daemon-systems.org/man/setuid.7.html
>
> Now consider that *any* program that gets its UID suddenly changed on it
> just became vulnerable to all that stuff that Henry writes about.
>
> News flash - most programmers who wrote code thinking it would run as the
> same userid the whole time don't do checks for all the sort of stuff that
> Henry warns about when programs suddenly get invoked with more privilege
> than they were designed to handle.
>

This is with the assumption that you are forking a child an calling
execv, if the program is written in the first place to take advantage of
this, and the issues with having a uid changed all of a sudden, there
should be little impact.

My initial concept is to implement a HTTP server that is designed from
the ground up to use this new functionallity. Each server that has been
pre-forked will just sit there until the parent sets its uid/gid and
hands it the request to handle.

> Then there's the opposite case - somebody manages to trick you into nuking the
> permissions on the right process-ID but wrong executable. Hilarity ensues when
> the process is running with *less* privilege than it expected. Go and read up
> on how Sendmail failed back around 2000, and understand *why* it failed. Just
> google for 'sendmail CAP_SETUID' and start reading. Then think what happens if
> somebody manages to get PHP to exec() some other binary (a set-UID one) and
> it's busy running when you whack its UID.

It is impossible to change the uid of a process that is not the
immediate child of the parent with these functions as a security
precaution, and even if a process manages to get its uid/gid changed,
the enable_setpresuid function limits the uid/gids that it can be set
to, so when implemented properly, the worst that can happen is another
users files get nuked on the machine, which is the exact problem I am
trying to stop from occuring.

Because the parent app drops all its privlages after enabling the
setpresuid, it can not be abused to gain root access either.

>
> That's just off the top of my head.
>
> Then go look at kernel/sys.c and read the comments just before the functions
> sys_setpgid(), sys_setregid(), and sys_setuid(), and figure out how the
> saved uid enters into things....
>
> There be serious and nasty dragons in there...
>

I knew there would be implications of implementing this, thats why I put
the code, and the question out there.

I know there is still the issue of the process holding open a file
descriptor that was owned by the old user, but I am sure that could be
solved by itterating the processes file descriptors and closing any that
the process will no longer have access to.

If the program crashes because it expects the fd to still be open, then
too bad, it should not have held it open, and IMHO is a bug as the
process should not have held it open when it is going to be re-used.

I am determined to not just add these calls to the kernel, but to make
them secure, and write programs that use them safely.

If there are concerns with things, please suggest fixes to make it
secure, or point out where the concerns are so I can investigate
possible solutions to the problem. I am sure the overhead of doing extra
security checks in the new functions will not be anywhere near that of
re-forking a process.

-geoff

2008-12-03 04:35:56

by Peter Teoh

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Wed, Dec 3, 2008 at 12:02 PM, Geoffrey McRae <[email protected]> wrote:
>
> My initial concept is to implement a HTTP server that is designed from
> the ground up to use this new functionallity. Each server that has been
> pre-forked will just sit there until the parent sets its uid/gid and
> hands it the request to handle.
>

I think the above is the core issue - you have something privileged to
be executed. So why not execute it in a small, code-verifiable
implementation, just like the Privilege Separation idea of SSH?

http://www.citi.umich.edu/u/provos/papers/privsep.pdf

Everything is done in userspace. SInce the privileged component is
small, it is easy to verify for correctness. The rest execute with
lesser privilege.

Recently, the hypervisor has been used to implement this verifiable
source code concept: see:

http://www.ghs.com/news/20081117_integrity_EAL6plus_security.html

where GreenHill achieved EAL6 certification - as it built its entire
kernel on top of the hypervisor. (called Separation Kernel,
conceptually similar to that of Privilege Separation in SSH).

Just my 2cts :-).

--
Regards,
Peter Teoh

Ernest Hemingway - "Never mistake motion for action."

2008-12-03 05:02:46

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Wed, 2008-12-03 at 12:35 +0800, Peter Teoh wrote:
> On Wed, Dec 3, 2008 at 12:02 PM, Geoffrey McRae <[email protected]> wrote:
> >
> > My initial concept is to implement a HTTP server that is designed from
> > the ground up to use this new functionallity. Each server that has been
> > pre-forked will just sit there until the parent sets its uid/gid and
> > hands it the request to handle.
> >
>
> I think the above is the core issue - you have something privileged to
> be executed. So why not execute it in a small, code-verifiable
> implementation, just like the Privilege Separation idea of SSH?
>
> http://www.citi.umich.edu/u/provos/papers/privsep.pdf

This would incur that any dependant programs such as PHP would need to
be re-written to talk to the privlaged process for privlaged operations,
thus increasing the complexness of the application. Also, if there is a
exploitable bug in the communication between the parent and child, the
parent with superuser access could be compromised.

The method I am suggesting fills these gaps, the parent cant be
compromised since the children can not talk to it, and it does not have
elevated privlages once it has started up, so even if it was compomised
somehow, the worst it could do is screw up unprivlaged user's files
within the uid/gids specified in the enable_setpresuid function.

So there are two advantages here:

* The parent is much harder to compromise as the child cant talk to it.
* The child does not have high enough privlages to change its own
uid/gid, but has enough access to perform all required tasks without
needing any special privlages.

>
> Everything is done in userspace. SInce the privileged component is
> small, it is easy to verify for correctness. The rest execute with
> lesser privilege.
>
> Recently, the hypervisor has been used to implement this verifiable
> source code concept: see:
>
> http://www.ghs.com/news/20081117_integrity_EAL6plus_security.html
>
> where GreenHill achieved EAL6 certification - as it built its entire
> kernel on top of the hypervisor. (called Separation Kernel,
> conceptually similar to that of Privilege Separation in SSH).
>
> Just my 2cts :-).
>

Again, this is alot of overhead and complexaty that for the kind of task
that I am trying to accomplish.

Right now the only forseeable problem is that if a process holds a fd
open when the parent app changes its uid/gid, which still, the worst
that it can do is read/write another user's file. But the solution to
this should be trivial, just close all fds the process should not have
access to in the kernel when the uid/gid is changed.

If a program crashes because it did not expect its uid to change, it
should either be updated to handle being used in this manner, or not be
used at all. Most programs, including PHP in my initial testing perform
flawlessly when their uid/gid is changed before they are handed a new
script to parse.

-Geoff

2008-12-03 06:54:38

by David Newall

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

Geoffrey McRae wrote:
> Right now the only forseeable problem is that if a process holds a fd
> open when the parent app changes its uid/gid, which still, the worst
> that it can do is read/write another user's file.

Well, no, there are more problems than open file descriptors; and the
worst is much worse than reading or writing another user's file.
Suppose you're changing the ids of the Perl, Python or PHP interpreter:
the first user could install a SIGCLD handler and fork and exec sleep.
When sleep dies, the handler gets executed as another user - hopefully a
user with access to credit card details, or other financially valuable
information.

2008-12-03 10:29:34

by Alan

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

> The idea is to not allow the child to change its own uid, or give the
> child any elevated privlages so that should the child be compromised via
> buffer overflow or some other bug, it cant be abused.

But the child process can modify itself, it can open files etc.

So as uid 1 I patch my own code to add a function call to a private
function that will be called regularly. Now as the other uids are
selected I am able to attack all those users file stores.

I don't think your model actually works.

2008-12-03 12:46:57

by Alan

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

> 300,000 processes each with a different uid. But if you had 300,000
> users and 200,000 different CGI scripts, you also have no choice but
> to fork and exec at request time, because there are too many different
> scripts.

You would normally maintain a pool then because you'd expect an uneven
loading and groups of requests to a given id. The number of scripts
shouldn't matter for a properly designed interpreter - you have a fastcgi
interpreter instance or similar which has the interpreter state ready and
just forks itself to handle the scripts (or does them threaded itself) for
that user.

Alan

2008-12-03 12:49:46

by Nick Andrew

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Wed, Dec 03, 2008 at 12:44:17PM +1100, Geoffrey McRae wrote:
> On Wed, 2008-12-03 at 00:53 +0000, Alan Cox wrote:
> > > (such as PHP) as the user that owns the website we are forced to fork a
> > > new process per request, then call setuid/gid and then launch the script
> > > language. This ofcource is resource intensive, but at present there is
> > > no other solution.

[...]

> But once this set is introduced a HTTP server could be written that uses
> forked children to handle requests, that have their identity swtiched
> before doing any work, including parsing CGI scripts.

I think we can do that already, using FastCGI.

As I understand it, the traditional CGI server system call flow is:

accept
fork
\ setuid(user)
exec(cgi script)

And I don't see how your 4 extra system calls would improve that flow.

The FastCGI flow is:

setuid(user)
exec(fastcgi script)
loop receiving requests over a pipe and processing

In this case the handling process has already been forked and exec'ed
so the time-consuming work is done once and the script can then get
on with the business of processing requests as quickly as possible.

I'm sure there are other execution models where the CGI processors
are pre-forked. Executing the CGI script (e.g. through a scripting
language) is presumably the most expensive operation, and doing that
in advance won't be useful if you have large numbers of distinct users
but they won't all be running CGIs all the time. In other words, if you
had 300,000 users and 1 CGI script being run, you won't want to pre-fork
300,000 processes each with a different uid. But if you had 300,000
users and 200,000 different CGI scripts, you also have no choice but
to fork and exec at request time, because there are too many different
scripts.

Nick.

2008-12-03 22:45:24

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Wed, 2008-12-03 at 23:42 +1100, Nick Andrew wrote:
> On Wed, Dec 03, 2008 at 12:44:17PM +1100, Geoffrey McRae wrote:
> > On Wed, 2008-12-03 at 00:53 +0000, Alan Cox wrote:
> > > > (such as PHP) as the user that owns the website we are forced to fork a
> > > > new process per request, then call setuid/gid and then launch the script
> > > > language. This ofcource is resource intensive, but at present there is
> > > > no other solution.
>
> [...]
>
> > But once this set is introduced a HTTP server could be written that uses
> > forked children to handle requests, that have their identity swtiched
> > before doing any work, including parsing CGI scripts.
>
> I think we can do that already, using FastCGI.
>
> As I understand it, the traditional CGI server system call flow is:
>
> accept
> fork
> \ setuid(user)
> exec(cgi script)
>
> And I don't see how your 4 extra system calls would improve that flow.

The four extra calls would improve that flow like so...

enable_setpresuid
setuid

pre-fork child processes
\ setuid
exec

accept request
choose free child
setpresuid(child, website user)
pass request to child

The children are pre-forked, so the overhead is in the setup... then
when the app recieves a request, it sets the child's uid to the uid of
the website, and then passes the request to the child, which, now, the
child is running as the website owner.

I know there are still loopholes in this methodology, like using the sig
handlers, but it is more secure then just doing nothing, there is no
fastCGI way to run each process as seperate users without the fork
overhead, which means every website can access every other websites data
without having to find any loop holes or write any special code.

It is more secure then just doing nothing.

2008-12-03 23:08:27

by Alan

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

> The children are pre-forked, so the overhead is in the setup... then
> when the app recieves a request, it sets the child's uid to the uid of
> the website, and then passes the request to the child, which, now, the
> child is running as the website owner.

But the child process may already have been trojanned by a previous user
so it gains you nothing.

> It is more secure then just doing nothing.

I'm not convinced. Not remotely.

2008-12-03 23:27:51

by Peter Teoh

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Thu, Dec 4, 2008 at 7:08 AM, Alan Cox <[email protected]> wrote:
>> The children are pre-forked, so the overhead is in the setup... then
>> when the app recieves a request, it sets the child's uid to the uid of
>> the website, and then passes the request to the child, which, now, the
>> child is running as the website owner.
>
> But the child process may already have been trojanned by a previous user
> so it gains you nothing.
>

Yes, I thought so too. The trojanized child, even though most of the
time unprivileged, can wait for that window of opportunity when its
privilege is escalated, by polling, and when it received the
privilege, immediate jump into action.

Thanks.

--
Regards,
Peter Teoh

Ernest Hemingway - "Never mistake motion for action."

2008-12-03 23:41:23

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Thu, 2008-12-04 at 07:27 +0800, Peter Teoh wrote:
> On Thu, Dec 4, 2008 at 7:08 AM, Alan Cox <[email protected]> wrote:
> >> The children are pre-forked, so the overhead is in the setup... then
> >> when the app recieves a request, it sets the child's uid to the uid of
> >> the website, and then passes the request to the child, which, now, the
> >> child is running as the website owner.
> >
> > But the child process may already have been trojanned by a previous user
> > so it gains you nothing.
> >
>
> Yes, I thought so too. The trojanized child, even though most of the
> time unprivileged, can wait for that window of opportunity when its
> privilege is escalated, by polling, and when it received the
> privilege, immediate jump into action.
>
> Thanks.
>

Ok, so this is a pretty major flaw of the idea, thats why I put this
concept out there, any suggestions as to how to get around this?
Possibly add some checking to disable certain functions in the child
when the enable_setpresuid function has been called?.

Or save the signal handlers the first time setpresuid is called, and the
next time, restore them so if the child has changed them, they get
re-set back to their initial state?

I know many people are against the idea of adding new functions at will
to the kernel, thats why I am trying to flesh out all the potential
problems and find solutions to them first.

2008-12-03 23:53:18

by Miquel van Smoorenburg

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Wed, 2008-12-03 at 23:08 +0000, Alan Cox wrote:
> > The children are pre-forked, so the overhead is in the setup... then
> > when the app recieves a request, it sets the child's uid to the uid of
> > the website, and then passes the request to the child, which, now, the
> > child is running as the website owner.
>
> But the child process may already have been trojanned by a previous user
> so it gains you nothing.
>
> > It is more secure then just doing nothing.
>
> I'm not convinced. Not remotely.

Well, in this particular case, and with this API, perhaps not.

But there really is something to be said for being able to limit the
setuid range of a process.

Right now, applications that want to switch to several different
UIDs/GIDs must be setuid root themself or at least have the right
capability. But once an app has that it can switch to any uid, including
root or other system users.

It would be great if you could say 'limit setuid() to saved-uid + uids
1000-2000' or something like that.

If then the userlevel NFS server gets owned you can at least be sure
none of the files in /bin have been modified ..

Note that there are patches on the net for linux, freebsd and probably
other OSes that do exactly this, so there definately is a need.

It could even be used to give normal users a range of uids to use for
sandboxes. Just an idea, I haven't really thought that through.

Mike.

2008-12-04 00:01:20

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

> It would be great if you could say 'limit setuid() to saved-uid + uids
> 1000-2000' or something like that.
>
> If then the userlevel NFS server gets owned you can at least be sure
> none of the files in /bin have been modified ..
>
> Note that there are patches on the net for linux, freebsd and probably
> other OSes that do exactly this, so there definately is a need.
>
> It could even be used to give normal users a range of uids to use for
> sandboxes. Just an idea, I haven't really thought that through.
>
> Mike.
>

Nice to hear that someone does not think my concept is completly
idiodic. I think the main issue here is that everyone is assuming that
this is only for use with CGI scripts, which could be abused, but as
Mike has mentioned, this is not the only use case. I am sure that with
some hacking and idea bouncing, this problem can be solved, and solved
in a very neat and clean way.

My concept is just that, a concept, build on it, expand it, fill the
gaps, and it will eventually become a working concept worth implementing
(I hope), dont just shoot it to hell.

The setuid/gid concept in linux is very limited, it would be nice to be
able to grant programs limited use of setuid, and even go one step
further, grant programs limited ability to set child uids.

To be completly honest, this is the kind of functionallity I expected to
already be there, and I was hopeing someone would tell me to RTFM on
function X that already does this...

2008-12-04 00:13:44

by Alan

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

> Well, in this particular case, and with this API, perhaps not.

ptrace, patching your own binary, kill etc.

> It would be great if you could say 'limit setuid() to saved-uid + uids
> 1000-2000' or something like that.

For the fsuid

> If then the userlevel NFS server gets owned you can at least be sure
> none of the files in /bin have been modified ..

The userland nfsd uses fsuid.. thats important. Acting on behalf of
another user for file purposes does make sense. I can see a
"setfsuidlist()" call making sense too, but uid/euid/saved uid don't make
sense in this context.

Alan

2008-12-04 00:22:21

by Peter Teoh

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Thu, Dec 4, 2008 at 8:00 AM, Geoffrey McRae <[email protected]> wrote:
>
> The setuid/gid concept in linux is very limited, it would be nice to be
> able to grant programs limited use of setuid, and even go one step
> further, grant programs limited ability to set child uids.

Yes, there can be many other variation on what u have just said, eg,
adding conditions whereby the grant can be used, etc. If u have a
chance to learn a little bit of SELinux, u will know the whole thing
can be very complex, especially the rules and policies configuration.
It is a fine balance between overheads vs performance and usability.

>
> To be completly honest, this is the kind of functionallity I expected to
> already be there, and I was hopeing someone would tell me to RTFM on
> function X that already does this...
>

Yes, I am sure it exists...and more likely than not, it can be very
application specific, and therefore, will be done by the higher-end
application in userspace.

But looking beyond, is there any other OS that may have something
similar? (Windows, or OpenBSD etc?) Not sure for me.

--
Regards,
Peter Teoh

Ernest Hemingway - "Never mistake motion for action."

2008-12-04 21:56:37

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Thu, 04 Dec 2008 10:40:56 +1100, Geoffrey McRae said:

> Ok, so this is a pretty major flaw of the idea, thats why I put this
> concept out there, any suggestions as to how to get around this?
> Possibly add some checking to disable certain functions in the child
> when the enable_setpresuid function has been called?.

Or just deploy SELinux instead.

> Or save the signal handlers the first time setpresuid is called, and the
> next time, restore them so if the child has changed them, they get
> re-set back to their initial state?

It's not just signal handlers.

while (getpid()) msleep(1);
/* malicious code here */

Just loop, pop up every few milliseconds and check if you're root,
and fall out of the loop and go into attack mode if you are.

If you're using it to toggle between various non-root userids, just adjust
the while accordingly: 'while ((me = getpid()) != 497) ...' or whatever
you need.

And if you try to disable getpid to prevent that attack, consider something
that does this:

while (open("only_creatable_by_target_uid",O_CREAT) < 0)

You can hardly take open() away from processes. ;)

> I know many people are against the idea of adding new functions at will
> to the kernel, thats why I am trying to flesh out all the potential
> problems and find solutions to them first.

We don't mind adding functions. We just hate broken-by-design functions.


Attachments:
(No filename) (226.00 B)

2008-12-04 22:31:20

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Thu, 2008-12-04 at 16:56 -0500, [email protected] wrote:
> On Thu, 04 Dec 2008 10:40:56 +1100, Geoffrey McRae said:
>
> > Ok, so this is a pretty major flaw of the idea, thats why I put this
> > concept out there, any suggestions as to how to get around this?
> > Possibly add some checking to disable certain functions in the child
> > when the enable_setpresuid function has been called?.
>
> Or just deploy SELinux instead.

SELinux is insanely complicated, and is sort of a blanket fix, it does
not fix the problem at the root, in the target application.

>
> > Or save the signal handlers the first time setpresuid is called, and the
> > next time, restore them so if the child has changed them, they get
> > re-set back to their initial state?
>
> It's not just signal handlers.
>
> while (getpid()) msleep(1);
> /* malicious code here */
>

This would only be dangerous if the parent did not wait for the child to
finish its task before changing its uid, which for a FastCGI app, it has
to as it needs the response to send back to the client. All that would
happen here is the CGI script would sleep forever, or until the HTTP
server killed the process.

> Just loop, pop up every few milliseconds and check if you're root,
> and fall out of the loop and go into attack mode if you are.
>
> If you're using it to toggle between various non-root userids, just adjust
> the while accordingly: 'while ((me = getpid()) != 497) ...' or whatever
> you need.

Same as above, it would just sleep forever.

>
> And if you try to disable getpid to prevent that attack, consider something
> that does this:
>
> while (open("only_creatable_by_target_uid",O_CREAT) < 0)
>
> You can hardly take open() away from processes. ;)

I dont exactly like the idea of disabling system functions, its more of
a hack then a solution, it was just a suggestion.

>
> > I know many people are against the idea of adding new functions at will
> > to the kernel, thats why I am trying to flesh out all the potential
> > problems and find solutions to them first.
>
> We don't mind adding functions. We just hate broken-by-design functions.

Thats fine, I dont want to make things less secure, bear in mind that
this is my first kernel patch, and I am still learning how things are
written in the kernel.

2008-12-05 03:35:51

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Fri, 05 Dec 2008 09:30:54 +1100, Geoffrey McRae said:
> On Thu, 2008-12-04 at 16:56 -0500, [email protected] wrote:

> > while (getpid()) msleep(1);
> > /* malicious code here */
> >
>
> This would only be dangerous if the parent did not wait for the child to
> finish its task before changing its uid, which for a FastCGI app, it has
> to as it needs the response to send back to the client. All that would
> happen here is the CGI script would sleep forever, or until the HTTP
> server killed the process.

Thus providing me with a way to DoS your webserver by sticking all your
server processes into a sleep-forever... :)

You're also overlooking the fact that the malicious code could do something
like this:

/* send the parent something that makes it *think* the request finished */
printf("We're all done now\n");
while (getpid()) msleep (1);

Remember - whatever the child is doing to signal that it's done, can *also*
be done by the exploit code. There's only one real exception - the child
can call exit() - if the exploit exits so a SIGCHLD is generated, then
it can't run anymore. However, since the whole *point* here is avoiding
the usual exit/fork/exec overhead...


Attachments:
(No filename) (226.00 B)

2008-12-05 03:44:18

by Nick Andrew

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Thu, Dec 04, 2008 at 10:35:27PM -0500, [email protected] wrote:
> You're also overlooking the fact that the malicious code could do something
> like this:
>
> /* send the parent something that makes it *think* the request finished */
> printf("We're all done now\n");
> while (getpid()) msleep (1);

I think it's pretty basic that setgid/setuid needs to be done _before_
exec'ing untrusted code.

On the other hand, if a trusted process gets its uid changed _and_
expects this to happen then I suppose it can be secure. But if a
process's uid gets changed unexpectedly then nasty things already
pointed out by Alan and others can occur.

Nick.
--
PGP Key ID = 0x418487E7 http://www.nick-andrew.net/
PGP Key fingerprint = B3ED 6894 8E49 1770 C24A 67E3 6266 6EB9 4184 87E7

2008-12-05 03:51:09

by Geoffrey McRae

[permalink] [raw]
Subject: Re: New Security Features, Please Comment


> Thus providing me with a way to DoS your webserver by sticking all your
> server processes into a sleep-forever... :)

Yeah, I realise that, its not the problem I am trying to solve though.

>
> You're also overlooking the fact that the malicious code could do something
> like this:
>
> /* send the parent something that makes it *think* the request finished */
> printf("We're all done now\n");
> while (getpid()) msleep (1);
>

Hmm, your right, there has to be a way to overcome all these issues
without having the fork overhead.

I have been toying with an alternate solution of allowing the parent
process to chroot & re-chroot it's children, but even that has the same
problem.

A hack to stop that would be to make getuid... etc, fudge their values
by always returning a constant value to the child, but it is an ugly way
to do this and would involve making stat lie about the ownership of
files too, and anything else that could be used to determine the real
uid or gid.

It seems that solving this issue is alot more complex then I first
envisioned.

Anyone else have any ideas of a fast, efficient and secure way to
accomplish this?

2008-12-05 04:03:38

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: New Security Features, Please Comment

On Fri, 05 Dec 2008 14:50:40 +1100, Geoffrey McRae said:
> Anyone else have any ideas of a fast, efficient and secure way to
> accomplish this?

Hint: There's a *reason* that after almost 40 years of Unix-oid and Linux-oid
operating systems, the syscall for which you search still doesn't exist. :)


Attachments:
(No filename) (226.00 B)