Re: [PATCH v3] Implement /proc/pid/kill

2018-11-11 Thread Eric W. Biederman
David Laight  writes:

> From: Daniel Colascione
>> Sent: 31 October 2018 19:33
> ...
>> You can't do it today with kill. The idea that keeping a open file
>> descriptor to a /proc/pid or a file within it prevents PID reuse is
>> widespread, but incorrect.
>
> Is there a real good reason why that shouldn't be the case?
> ie Holding a reference on the 'struct pid' being enough to stop reuse.
>
> A patch to do that would be more generally useful.

Holding an open file descriptor to /proc/pid is enough to prevent pid
reuse problems.  If a pid number is reused a new 'struct pid' is
generated.  There is not 'struct pid' reuse.

So in solving this the kernel data structure you would need to hold onto
is a 'struct pid'.  It is just necessary to add an interface to sending
signals to that 'struct pid' and not looking up the 'struct pid' again
by number.

Eric


Re: [PATCH v3] Implement /proc/pid/kill

2018-11-11 Thread Eric W. Biederman
David Laight  writes:

> From: Daniel Colascione
>> Sent: 31 October 2018 19:33
> ...
>> You can't do it today with kill. The idea that keeping a open file
>> descriptor to a /proc/pid or a file within it prevents PID reuse is
>> widespread, but incorrect.
>
> Is there a real good reason why that shouldn't be the case?
> ie Holding a reference on the 'struct pid' being enough to stop reuse.
>
> A patch to do that would be more generally useful.

Holding an open file descriptor to /proc/pid is enough to prevent pid
reuse problems.  If a pid number is reused a new 'struct pid' is
generated.  There is not 'struct pid' reuse.

So in solving this the kernel data structure you would need to hold onto
is a 'struct pid'.  It is just necessary to add an interface to sending
signals to that 'struct pid' and not looking up the 'struct pid' again
by number.

Eric


RE: [PATCH v3] Implement /proc/pid/kill

2018-11-01 Thread David Laight
From: Daniel Colascione
> Sent: 31 October 2018 19:33
...
> You can't do it today with kill. The idea that keeping a open file
> descriptor to a /proc/pid or a file within it prevents PID reuse is
> widespread, but incorrect.

Is there a real good reason why that shouldn't be the case?
ie Holding a reference on the 'struct pid' being enough to stop reuse.

A patch to do that would be more generally useful.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, 
UK
Registration No: 1397386 (Wales)


RE: [PATCH v3] Implement /proc/pid/kill

2018-11-01 Thread David Laight
From: Daniel Colascione
> Sent: 31 October 2018 19:33
...
> You can't do it today with kill. The idea that keeping a open file
> descriptor to a /proc/pid or a file within it prevents PID reuse is
> widespread, but incorrect.

Is there a real good reason why that shouldn't be the case?
ie Holding a reference on the 'struct pid' being enough to stop reuse.

A patch to do that would be more generally useful.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, 
UK
Registration No: 1397386 (Wales)


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Tycho Andersen
On Wed, Oct 31, 2018 at 07:33:06PM +, Daniel Colascione wrote:
> On Wed, Oct 31, 2018 at 6:17 PM, Tycho Andersen  wrote:
> > On Wed, Oct 31, 2018 at 06:00:49PM +, Daniel Colascione wrote:
> >> On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
> >> > Why not just use an ioctl() like Jann suggested instead of this big
> >> > security check? Then we avoid the whole setuid writer thing entirely,
> >>
> >> Don't you think a system call would be better than a new ioctl?
> >
> > We already have a kill() system call :)
> 
> kill(2) is useless this purpose: it accepts a numeric PID, but we'd
> need it to accept a process file descriptor instead. It's true that
> the existing kill(1) binary might be the vehicle for using a
> hypothetical new system call, but that's a separate matter.
> 
> >> With either an ioctl or a new system call, though, the shell would
> >> need a helper program to use the facility, whereas with the existing
> >> approach, the shell can use the new facility without any additional
> >> binaries.
> >
> > ...and a binary to use it!
> >
> > The nice thing about an ioctl is that it avoids this class of attacks
> > entirely.
> 
> Let's stop talking about adding an ioctl. Ioctls have problems with
> namespacing of the request argument; it's not safe, in general, to
> issue an ioctl against a file descriptor of an unknown type.

So don't lose track of the fd type. I'm not sure I see this as a big
problem.

> You don't know how that FD will interpret your request code. The two
> good options before us are a write(2) interface and a new system
> call. I think both are defensible. But I don't see a good reason to
> consider adding an ioctl instead of a system call.

https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1729911.html
https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1729921.html

maybe? :)

> All of this is moot if the new comprehensive process interface that
> comes out of LPC ends up being better anyway.

+1, I think a way to do all of this sort of thing would be nice.

> > either. Using this from the shell is still racy, because if I do
> > something like:
> >
> > echo 9 > /proc/$pid/kill
> >
> > There's exactly the same race that there is with kill, that $pid might
> > be something else.
> 
> > Of course I could do some magic with bind mounts or
> > my pwd or something to keep it alive, but I can already do that today
> > with kill.
> 
> You can't do it today with kill. The idea that keeping a open file
> descriptor to a /proc/pid or a file within it prevents PID reuse is
> widespread, but incorrect.

Good to know :)

Tycho


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Tycho Andersen
On Wed, Oct 31, 2018 at 07:33:06PM +, Daniel Colascione wrote:
> On Wed, Oct 31, 2018 at 6:17 PM, Tycho Andersen  wrote:
> > On Wed, Oct 31, 2018 at 06:00:49PM +, Daniel Colascione wrote:
> >> On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
> >> > Why not just use an ioctl() like Jann suggested instead of this big
> >> > security check? Then we avoid the whole setuid writer thing entirely,
> >>
> >> Don't you think a system call would be better than a new ioctl?
> >
> > We already have a kill() system call :)
> 
> kill(2) is useless this purpose: it accepts a numeric PID, but we'd
> need it to accept a process file descriptor instead. It's true that
> the existing kill(1) binary might be the vehicle for using a
> hypothetical new system call, but that's a separate matter.
> 
> >> With either an ioctl or a new system call, though, the shell would
> >> need a helper program to use the facility, whereas with the existing
> >> approach, the shell can use the new facility without any additional
> >> binaries.
> >
> > ...and a binary to use it!
> >
> > The nice thing about an ioctl is that it avoids this class of attacks
> > entirely.
> 
> Let's stop talking about adding an ioctl. Ioctls have problems with
> namespacing of the request argument; it's not safe, in general, to
> issue an ioctl against a file descriptor of an unknown type.

So don't lose track of the fd type. I'm not sure I see this as a big
problem.

> You don't know how that FD will interpret your request code. The two
> good options before us are a write(2) interface and a new system
> call. I think both are defensible. But I don't see a good reason to
> consider adding an ioctl instead of a system call.

https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1729911.html
https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1729921.html

maybe? :)

> All of this is moot if the new comprehensive process interface that
> comes out of LPC ends up being better anyway.

+1, I think a way to do all of this sort of thing would be nice.

> > either. Using this from the shell is still racy, because if I do
> > something like:
> >
> > echo 9 > /proc/$pid/kill
> >
> > There's exactly the same race that there is with kill, that $pid might
> > be something else.
> 
> > Of course I could do some magic with bind mounts or
> > my pwd or something to keep it alive, but I can already do that today
> > with kill.
> 
> You can't do it today with kill. The idea that keeping a open file
> descriptor to a /proc/pid or a file within it prevents PID reuse is
> widespread, but incorrect.

Good to know :)

Tycho


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Daniel Colascione
On Wed, Oct 31, 2018 at 6:17 PM, Tycho Andersen  wrote:
> On Wed, Oct 31, 2018 at 06:00:49PM +, Daniel Colascione wrote:
>> On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
>> > Why not just use an ioctl() like Jann suggested instead of this big
>> > security check? Then we avoid the whole setuid writer thing entirely,
>>
>> Don't you think a system call would be better than a new ioctl?
>
> We already have a kill() system call :)

kill(2) is useless this purpose: it accepts a numeric PID, but we'd
need it to accept a process file descriptor instead. It's true that
the existing kill(1) binary might be the vehicle for using a
hypothetical new system call, but that's a separate matter.

>> With either an ioctl or a new system call, though, the shell would
>> need a helper program to use the facility, whereas with the existing
>> approach, the shell can use the new facility without any additional
>> binaries.
>
> ...and a binary to use it!
>
> The nice thing about an ioctl is that it avoids this class of attacks
> entirely.

Let's stop talking about adding an ioctl. Ioctls have problems with
namespacing of the request argument; it's not safe, in general, to
issue an ioctl against a file descriptor of an unknown type. You don't
know how that FD will interpret your request code. The two good
options before us are a write(2) interface and a new system call. I
think both are defensible. But I don't see a good reason to consider
adding an ioctl instead of a system call.

>> > and we can pass the fd around if we want to.
>>
>> You can pass the FD around today --- specifically, you just pass the
>> /proc/pid directory FD, not the /proc/pid/kill FD. The /proc/pid
>> directory FD acts as a process handle. (It's literally a reference to
>> a struct pid.) Anyone who receives one of these process handle FDs and
>> who wants to use the corresponding kill file can open the kill fd with
>> openat(2). What you can't do is pass the /proc/pid/kill FD to another
>> security context and use it, but when would you ever want to do that?
>
> Perhaps I don't have a good imagination, because it's not clear to me
> when I'd ever use this from a shell instead of the kill binary,

I'm not against a new system call per se; I'd just prefer a write(2)
interface if we can get away with it. The trouble with a system call
is that it would have to accept a /proc/pid file descriptor, and file
descriptor management in the shell is awkward. I imagine the interface
would look something like kill -f PATH, where PATH is a PATH to a
/proc/pid directory. You'd be able to cd into /proc/$SOMETHING,
inspect state, and then, if you wanted to kill the process, you'd run
kill -f . 9 (or whatever signal number you want). It seems to be about
as ergonomic as 'echo 9 > ./kill'. But a new system call means new
kernel headers, coordination with procps, and bash, and every other
shell that has a kill builtin. You could provide a different, non-kill
binary, but then who'd distribute it? A new proc file, OTOH, would
Just Work. I agree that a system call interface would avoid the need
for the security check thing in the patch, but is avoiding this check
worth the coordination flowing from adding a new system call? I don't
know.

All of this is moot if the new comprehensive process interface that
comes out of LPC ends up being better anyway.

> either. Using this from the shell is still racy, because if I do
> something like:
>
> echo 9 > /proc/$pid/kill
>
> There's exactly the same race that there is with kill, that $pid might
> be something else.

> Of course I could do some magic with bind mounts or
> my pwd or something to keep it alive, but I can already do that today
> with kill.

You can't do it today with kill. The idea that keeping a open file
descriptor to a /proc/pid or a file within it prevents PID reuse is
widespread, but incorrect.


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Daniel Colascione
On Wed, Oct 31, 2018 at 6:17 PM, Tycho Andersen  wrote:
> On Wed, Oct 31, 2018 at 06:00:49PM +, Daniel Colascione wrote:
>> On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
>> > Why not just use an ioctl() like Jann suggested instead of this big
>> > security check? Then we avoid the whole setuid writer thing entirely,
>>
>> Don't you think a system call would be better than a new ioctl?
>
> We already have a kill() system call :)

kill(2) is useless this purpose: it accepts a numeric PID, but we'd
need it to accept a process file descriptor instead. It's true that
the existing kill(1) binary might be the vehicle for using a
hypothetical new system call, but that's a separate matter.

>> With either an ioctl or a new system call, though, the shell would
>> need a helper program to use the facility, whereas with the existing
>> approach, the shell can use the new facility without any additional
>> binaries.
>
> ...and a binary to use it!
>
> The nice thing about an ioctl is that it avoids this class of attacks
> entirely.

Let's stop talking about adding an ioctl. Ioctls have problems with
namespacing of the request argument; it's not safe, in general, to
issue an ioctl against a file descriptor of an unknown type. You don't
know how that FD will interpret your request code. The two good
options before us are a write(2) interface and a new system call. I
think both are defensible. But I don't see a good reason to consider
adding an ioctl instead of a system call.

>> > and we can pass the fd around if we want to.
>>
>> You can pass the FD around today --- specifically, you just pass the
>> /proc/pid directory FD, not the /proc/pid/kill FD. The /proc/pid
>> directory FD acts as a process handle. (It's literally a reference to
>> a struct pid.) Anyone who receives one of these process handle FDs and
>> who wants to use the corresponding kill file can open the kill fd with
>> openat(2). What you can't do is pass the /proc/pid/kill FD to another
>> security context and use it, but when would you ever want to do that?
>
> Perhaps I don't have a good imagination, because it's not clear to me
> when I'd ever use this from a shell instead of the kill binary,

I'm not against a new system call per se; I'd just prefer a write(2)
interface if we can get away with it. The trouble with a system call
is that it would have to accept a /proc/pid file descriptor, and file
descriptor management in the shell is awkward. I imagine the interface
would look something like kill -f PATH, where PATH is a PATH to a
/proc/pid directory. You'd be able to cd into /proc/$SOMETHING,
inspect state, and then, if you wanted to kill the process, you'd run
kill -f . 9 (or whatever signal number you want). It seems to be about
as ergonomic as 'echo 9 > ./kill'. But a new system call means new
kernel headers, coordination with procps, and bash, and every other
shell that has a kill builtin. You could provide a different, non-kill
binary, but then who'd distribute it? A new proc file, OTOH, would
Just Work. I agree that a system call interface would avoid the need
for the security check thing in the patch, but is avoiding this check
worth the coordination flowing from adding a new system call? I don't
know.

All of this is moot if the new comprehensive process interface that
comes out of LPC ends up being better anyway.

> either. Using this from the shell is still racy, because if I do
> something like:
>
> echo 9 > /proc/$pid/kill
>
> There's exactly the same race that there is with kill, that $pid might
> be something else.

> Of course I could do some magic with bind mounts or
> my pwd or something to keep it alive, but I can already do that today
> with kill.

You can't do it today with kill. The idea that keeping a open file
descriptor to a /proc/pid or a file within it prevents PID reuse is
widespread, but incorrect.


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Tycho Andersen
On Wed, Oct 31, 2018 at 06:00:49PM +, Daniel Colascione wrote:
> On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
> > Why not just use an ioctl() like Jann suggested instead of this big
> > security check? Then we avoid the whole setuid writer thing entirely,
> 
> Don't you think a system call would be better than a new ioctl?

We already have a kill() system call :)

> With either an ioctl or a new system call, though, the shell would
> need a helper program to use the facility, whereas with the existing
> approach, the shell can use the new facility without any additional
> binaries.

...and a binary to use it!

The nice thing about an ioctl is that it avoids this class of attacks
entirely.

> > and we can pass the fd around if we want to.
> 
> You can pass the FD around today --- specifically, you just pass the
> /proc/pid directory FD, not the /proc/pid/kill FD. The /proc/pid
> directory FD acts as a process handle. (It's literally a reference to
> a struct pid.) Anyone who receives one of these process handle FDs and
> who wants to use the corresponding kill file can open the kill fd with
> openat(2). What you can't do is pass the /proc/pid/kill FD to another
> security context and use it, but when would you ever want to do that?

Perhaps I don't have a good imagination, because it's not clear to me
when I'd ever use this from a shell instead of the kill binary,
either. Using this from the shell is still racy, because if I do
something like:

echo 9 > /proc/$pid/kill

There's exactly the same race that there is with kill, that $pid might
be something else. Of course I could do some magic with bind mounts or
my pwd or something to keep it alive, but I can already do that today
with kill.

I can understand the desire to have a race free way to do this, but
"it must use write(2)" seems a little unnecessary, given that the
shell use case isn't particularly convincing to me.

Tycho


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Tycho Andersen
On Wed, Oct 31, 2018 at 06:00:49PM +, Daniel Colascione wrote:
> On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
> > Why not just use an ioctl() like Jann suggested instead of this big
> > security check? Then we avoid the whole setuid writer thing entirely,
> 
> Don't you think a system call would be better than a new ioctl?

We already have a kill() system call :)

> With either an ioctl or a new system call, though, the shell would
> need a helper program to use the facility, whereas with the existing
> approach, the shell can use the new facility without any additional
> binaries.

...and a binary to use it!

The nice thing about an ioctl is that it avoids this class of attacks
entirely.

> > and we can pass the fd around if we want to.
> 
> You can pass the FD around today --- specifically, you just pass the
> /proc/pid directory FD, not the /proc/pid/kill FD. The /proc/pid
> directory FD acts as a process handle. (It's literally a reference to
> a struct pid.) Anyone who receives one of these process handle FDs and
> who wants to use the corresponding kill file can open the kill fd with
> openat(2). What you can't do is pass the /proc/pid/kill FD to another
> security context and use it, but when would you ever want to do that?

Perhaps I don't have a good imagination, because it's not clear to me
when I'd ever use this from a shell instead of the kill binary,
either. Using this from the shell is still racy, because if I do
something like:

echo 9 > /proc/$pid/kill

There's exactly the same race that there is with kill, that $pid might
be something else. Of course I could do some magic with bind mounts or
my pwd or something to keep it alive, but I can already do that today
with kill.

I can understand the desire to have a race free way to do this, but
"it must use write(2)" seems a little unnecessary, given that the
shell use case isn't particularly convincing to me.

Tycho


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Daniel Colascione
On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
> Why not just use an ioctl() like Jann suggested instead of this big
> security check? Then we avoid the whole setuid writer thing entirely,

Don't you think a system call would be better than a new ioctl? With
either an ioctl or a new system call, though, the shell would need a
helper program to use the facility, whereas with the existing
approach, the shell can use the new facility without any additional
binaries.

> and we can pass the fd around if we want to.

You can pass the FD around today --- specifically, you just pass the
/proc/pid directory FD, not the /proc/pid/kill FD. The /proc/pid
directory FD acts as a process handle. (It's literally a reference to
a struct pid.) Anyone who receives one of these process handle FDs and
who wants to use the corresponding kill file can open the kill fd with
openat(2). What you can't do is pass the /proc/pid/kill FD to another
security context and use it, but when would you ever want to do that?


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Daniel Colascione
On Wed, Oct 31, 2018 at 5:54 PM, Tycho Andersen  wrote:
> Why not just use an ioctl() like Jann suggested instead of this big
> security check? Then we avoid the whole setuid writer thing entirely,

Don't you think a system call would be better than a new ioctl? With
either an ioctl or a new system call, though, the shell would need a
helper program to use the facility, whereas with the existing
approach, the shell can use the new facility without any additional
binaries.

> and we can pass the fd around if we want to.

You can pass the FD around today --- specifically, you just pass the
/proc/pid directory FD, not the /proc/pid/kill FD. The /proc/pid
directory FD acts as a process handle. (It's literally a reference to
a struct pid.) Anyone who receives one of these process handle FDs and
who wants to use the corresponding kill file can open the kill fd with
openat(2). What you can't do is pass the /proc/pid/kill FD to another
security context and use it, but when would you ever want to do that?


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Tycho Andersen
On Wed, Oct 31, 2018 at 03:59:12PM +, Daniel Colascione wrote:
> Add a simple proc-based kill interface. To use /proc/pid/kill, just
> write the signal number in base-10 ASCII to the kill file of the
> process to be killed: for example, 'echo 9 > /proc/$$/kill'.
> 
> Semantically, /proc/pid/kill works like kill(2), except that the
> process ID comes from the proc filesystem context instead of from an
> explicit system call parameter. This way, it's possible to avoid races
> between inspecting some aspect of a process and that process's PID
> being reused for some other process.
> 
> Note that the write(2) to the kill file descriptor works only if it
> happens in the security context as the call to open(2), where
> "security context" is defined as the set of all ambient user IDs
> (effective uid, fs uid, real uid, and saved uid) as well as the
> presence of the CAP_KILL capability.  This check prevents confused
> deputy attacks via, e.g., supplying a /proc/$(pidof httpd)/kill file
> descriptor as the standard output of setuid program and convincing
> that program to write a "9".
> 
> With /proc/pid/kill, it's possible to write a proper race-free and
> safe pkill(1). An approximation follows. A real program might use
> openat(2), having opened a process's /proc/pid directory explicitly,
> with the directory file descriptor serving as a sort of "process
> handle".
> 
> #!/bin/bash
> set -euo pipefail
> pat=$1
> for proc_status in /proc/*/status; do (
> cd $(dirname $proc_status)
> readarray proc_argv -d'' < cmdline
> if ((${#proc_argv[@]} > 0)) &&
>[[ ${proc_argv[0]} = *$pat* ]];
> then
> echo 15 > kill
> fi
> ) || true; done
> 
> Signed-off-by: Daniel Colascione 
> ---
> 
> Turns out that checking struct user isn't sufficient, since signal.c's
> permissions check also cares about effective UIDs. Let's be
> extra-paranoid and bail if _anything_ relevant in struct cred
> has changed.
> 
> Also, as Joel suggested, switch from goto-return to direct return.
> 
>  fs/proc/base.c | 67 ++
>  1 file changed, 67 insertions(+)
> 
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 7e9f07bf260d..b0e7ded96af9 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -205,6 +205,72 @@ static int proc_root_link(struct dentry *dentry, struct 
> path *path)
>   return result;
>  }
>  
> +static ssize_t proc_pid_kill_write(struct file *file,
> +const char __user *buf,
> +size_t count, loff_t *ppos)
> +{
> + ssize_t res;
> + int sig;
> + char buffer[4];
> + const struct cred *cur_cred;
> + const struct cred *open_cred;
> + bool security_changed;
> +
> + /* This check prevents a confused deputy attack in which an
> +  * unprivileged process opens /proc/victim/kill and convinces
> +  * a privileged process to write to that kill FD, effectively
> +  * performing a kill with the privileges of the unwitting
> +  * privileged process.  Here, we just fail the kill operation
> +  * if someone calls write(2) with a real user ID that differs
> +  * from the one used to open the kill FD.
> +  */
> + cur_cred = current_cred();
> + open_cred = file->f_cred;
> + security_changed =
> + cur_cred->user_ns != open_cred->user_ns ||
> + !uid_eq(cur_cred->euid, open_cred->euid) ||
> + !uid_eq(cur_cred->fsuid, open_cred->fsuid) ||
> + !uid_eq(cur_cred->suid, open_cred->suid) ||
> + !uid_eq(cur_cred->uid, open_cred->uid) ||
> + /* No audit: if we actually use the capability, we'll
> +  * audit during the actual kill. Here, we're just
> +  * checking whether our kill-FD has escaped its
> +  * original security context and bailing if it has.
> +  */
> + (security_capable_noaudit(cur_cred,
> +   cur_cred->user_ns,
> +   CAP_KILL)
> +  != security_capable_noaudit(open_cred,
> +  open_cred->user_ns,
> +  CAP_KILL));
> + if (security_changed)
> + return -EPERM;

Why not just use an ioctl() like Jann suggested instead of this big
security check? Then we avoid the whole setuid writer thing entirely,
and we can pass the fd around if we want to.

Tycho


Re: [PATCH v3] Implement /proc/pid/kill

2018-10-31 Thread Tycho Andersen
On Wed, Oct 31, 2018 at 03:59:12PM +, Daniel Colascione wrote:
> Add a simple proc-based kill interface. To use /proc/pid/kill, just
> write the signal number in base-10 ASCII to the kill file of the
> process to be killed: for example, 'echo 9 > /proc/$$/kill'.
> 
> Semantically, /proc/pid/kill works like kill(2), except that the
> process ID comes from the proc filesystem context instead of from an
> explicit system call parameter. This way, it's possible to avoid races
> between inspecting some aspect of a process and that process's PID
> being reused for some other process.
> 
> Note that the write(2) to the kill file descriptor works only if it
> happens in the security context as the call to open(2), where
> "security context" is defined as the set of all ambient user IDs
> (effective uid, fs uid, real uid, and saved uid) as well as the
> presence of the CAP_KILL capability.  This check prevents confused
> deputy attacks via, e.g., supplying a /proc/$(pidof httpd)/kill file
> descriptor as the standard output of setuid program and convincing
> that program to write a "9".
> 
> With /proc/pid/kill, it's possible to write a proper race-free and
> safe pkill(1). An approximation follows. A real program might use
> openat(2), having opened a process's /proc/pid directory explicitly,
> with the directory file descriptor serving as a sort of "process
> handle".
> 
> #!/bin/bash
> set -euo pipefail
> pat=$1
> for proc_status in /proc/*/status; do (
> cd $(dirname $proc_status)
> readarray proc_argv -d'' < cmdline
> if ((${#proc_argv[@]} > 0)) &&
>[[ ${proc_argv[0]} = *$pat* ]];
> then
> echo 15 > kill
> fi
> ) || true; done
> 
> Signed-off-by: Daniel Colascione 
> ---
> 
> Turns out that checking struct user isn't sufficient, since signal.c's
> permissions check also cares about effective UIDs. Let's be
> extra-paranoid and bail if _anything_ relevant in struct cred
> has changed.
> 
> Also, as Joel suggested, switch from goto-return to direct return.
> 
>  fs/proc/base.c | 67 ++
>  1 file changed, 67 insertions(+)
> 
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 7e9f07bf260d..b0e7ded96af9 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -205,6 +205,72 @@ static int proc_root_link(struct dentry *dentry, struct 
> path *path)
>   return result;
>  }
>  
> +static ssize_t proc_pid_kill_write(struct file *file,
> +const char __user *buf,
> +size_t count, loff_t *ppos)
> +{
> + ssize_t res;
> + int sig;
> + char buffer[4];
> + const struct cred *cur_cred;
> + const struct cred *open_cred;
> + bool security_changed;
> +
> + /* This check prevents a confused deputy attack in which an
> +  * unprivileged process opens /proc/victim/kill and convinces
> +  * a privileged process to write to that kill FD, effectively
> +  * performing a kill with the privileges of the unwitting
> +  * privileged process.  Here, we just fail the kill operation
> +  * if someone calls write(2) with a real user ID that differs
> +  * from the one used to open the kill FD.
> +  */
> + cur_cred = current_cred();
> + open_cred = file->f_cred;
> + security_changed =
> + cur_cred->user_ns != open_cred->user_ns ||
> + !uid_eq(cur_cred->euid, open_cred->euid) ||
> + !uid_eq(cur_cred->fsuid, open_cred->fsuid) ||
> + !uid_eq(cur_cred->suid, open_cred->suid) ||
> + !uid_eq(cur_cred->uid, open_cred->uid) ||
> + /* No audit: if we actually use the capability, we'll
> +  * audit during the actual kill. Here, we're just
> +  * checking whether our kill-FD has escaped its
> +  * original security context and bailing if it has.
> +  */
> + (security_capable_noaudit(cur_cred,
> +   cur_cred->user_ns,
> +   CAP_KILL)
> +  != security_capable_noaudit(open_cred,
> +  open_cred->user_ns,
> +  CAP_KILL));
> + if (security_changed)
> + return -EPERM;

Why not just use an ioctl() like Jann suggested instead of this big
security check? Then we avoid the whole setuid writer thing entirely,
and we can pass the fd around if we want to.

Tycho