2005-03-12 11:42:43

by Alexander Nyberg

[permalink] [raw]
Subject: Capabilities across execve

This makes it possible for a root-task to pass capabilities to
nonroot-task across execve. The root-task needs to change it's
cap_inheritable mask and set prctl(PR_SET_KEEPCAPS, 1) to pass on
capabilities.
At execve time the capabilities will be passed on to the new
nonroot-task and any non-inheritable effective and permitted
capabilities will be masked out.
The effective capability of the new nonroot-task will be set to the
maximum permitted.

>From here on the inheritable mask will be passed on unchanged to the new
tasks children unless told otherwise (effectively the complete
capability state is passed on).

With a small insert of prctl(PR_SET_KEEPCAPS, 1) into pam_cap.c at the
correct place this makes pam_cap work as expected. I'm also attaching a
test-case that tests capabilities across setuid => execve (makes the new
task inherit CAP_CHOWN).


Signed-off-by: Alexander Nyberg <[email protected]>

===== security/commoncap.c 1.15 vs edited =====
--- 1.15/security/commoncap.c 2005-01-11 02:29:23 +01:00
+++ edited/security/commoncap.c 2005-03-12 12:04:34 +01:00
@@ -111,13 +111,19 @@ void cap_capset_set (struct task_struct

int cap_bprm_set_security (struct linux_binprm *bprm)
{
- /* Copied from fs/exec.c:prepare_binprm. */
-
- /* We don't have VFS support for capabilities yet */
- cap_clear (bprm->cap_inheritable);
- cap_clear (bprm->cap_permitted);
- cap_clear (bprm->cap_effective);
+ struct task_struct *p = current;

+ /*
+ * Mask out the non-inheritable capabilities.
+ * Note: init has a zero mask of cap_inheritable, so a root-task will not
+ * pass on any capabilities unless explicitly told to do so. If a non-zero
+ * inheritable mask is passed to a positive uid task it will then pass on
+ * its inheritable mask to all children unless told otherwise.
+ */
+ bprm->cap_permitted = cap_intersect(p->cap_permitted, p->cap_inheritable);
+ bprm->cap_effective = cap_intersect(p->cap_effective, p->cap_inheritable);
+ bprm->cap_inheritable = p->cap_inheritable;
+
/* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we raise all three
* capability sets for the file.
@@ -127,7 +133,7 @@ int cap_bprm_set_security (struct linux_
*/

if (!issecure (SECURE_NOROOT)) {
- if (bprm->e_uid == 0 || current->uid == 0) {
+ if (bprm->e_uid == 0 || p->uid == 0) {
cap_set_full (bprm->cap_inheritable);
cap_set_full (bprm->cap_permitted);
}
@@ -139,13 +145,9 @@ int cap_bprm_set_security (struct linux_

void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
- /* Derived from fs/exec.c:compute_creds. */
- kernel_cap_t new_permitted, working;
+ kernel_cap_t new_permitted;

new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
- working = cap_intersect (bprm->cap_inheritable,
- current->cap_inheritable);
- new_permitted = cap_combine (new_permitted, working);

if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
!cap_issubset (new_permitted, current->cap_permitted)) {
@@ -166,14 +168,9 @@ void cap_bprm_apply_creds (struct linux_
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;

- /* For init, we want to retain the capabilities set
- * in the init_task struct. Thus we skip the usual
- * capability rules */
- if (current->pid != 1) {
- current->cap_permitted = new_permitted;
- current->cap_effective =
- cap_intersect (new_permitted, bprm->cap_effective);
- }
+ current->cap_permitted = new_permitted;
+ current->cap_effective =
+ cap_intersect (new_permitted, bprm->cap_effective);

/* AUD: Audit candidate if current->cap_effective is set */

@@ -249,9 +246,9 @@ static inline void cap_emulate_setxuid (
cap_clear (current->cap_permitted);
cap_clear (current->cap_effective);
}
- if (old_euid == 0 && current->euid != 0) {
+ if (old_euid == 0 && current->euid != 0 && !current->keep_capabilities)
cap_clear (current->cap_effective);
- }
+
if (old_euid != 0 && current->euid == 0) {
current->cap_effective = current->cap_permitted;
}


Attachments:
cap_test.c (1.69 kB)

2005-03-13 03:21:31

by Chris Wright

[permalink] [raw]
Subject: Re: Capabilities across execve

* Alexander Nyberg ([email protected]) wrote:
> This makes it possible for a root-task to pass capabilities to
> nonroot-task across execve. The root-task needs to change it's
> cap_inheritable mask and set prctl(PR_SET_KEEPCAPS, 1) to pass on
> capabilities.

This overloads keepcaps, which could surprise to existing users.

> At execve time the capabilities will be passed on to the new
> nonroot-task and any non-inheritable effective and permitted
> capabilities will be masked out.
> The effective capability of the new nonroot-task will be set to the
> maximum permitted.

What happens to eff on setuid() to non-root or restore to uid 0?
What happens if you exec a setuid-root binary, or a setuid-nonroot binary?
How about ptrace?

Here's the tests I use.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net


Attachments:
(No filename) (858.00 B)
testcap.tgz (4.17 kB)
Download all attachments

2005-03-13 18:36:11

by Pavel Machek

[permalink] [raw]
Subject: Re: Capabilities across execve

Hi!

> This makes it possible for a root-task to pass capabilities to
> nonroot-task across execve. The root-task needs to change it's
> cap_inheritable mask and set prctl(PR_SET_KEEPCAPS, 1) to pass on
> capabilities.
> At execve time the capabilities will be passed on to the new
> nonroot-task and any non-inheritable effective and permitted
> capabilities will be masked out.
> The effective capability of the new nonroot-task will be set to the
> maximum permitted.
>
> >From here on the inheritable mask will be passed on unchanged to the new
> tasks children unless told otherwise (effectively the complete
> capability state is passed on).
>
> With a small insert of prctl(PR_SET_KEEPCAPS, 1) into pam_cap.c at the
> correct place this makes pam_cap work as expected. I'm also attaching a
> test-case that tests capabilities across setuid => execve (makes the new
> task inherit CAP_CHOWN).

FWIV, I think this is good idea; this way capabilities will not only
be castle in the sky, but also will be actually usable.
Pavel


--
People were complaining that M$ turns users into beta-testers...
...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!

2005-03-15 13:49:32

by Alexander Nyberg

[permalink] [raw]
Subject: Re: Capabilities across execve

> > This makes it possible for a root-task to pass capabilities to
> > nonroot-task across execve. The root-task needs to change it's
> > cap_inheritable mask and set prctl(PR_SET_KEEPCAPS, 1) to pass on
> > capabilities.
>
> This overloads keepcaps, which could surprise to existing users.

current->keep_capabilities is set to 0 at each execve, however the
inheritable mask is passed on and therefor also the allowed effective +
permitted. I think this is very necessery if there's ever going to be a
real use of it. It's not worth anything getting a shell with every
capability if every new process you run afterwards will have its
capabilities dropped. If we do like this it will only be useful in
special circumstances when wanting to run _one_ application with some
special capability. The scope can be much more general. How about having
users that can run all the way CAP_SYS_NICE, would give every audio man
his realtime applications. This is certainly possible with capabilities
across execve and pam_cap (using a few caps myself right now).

> > At execve time the capabilities will be passed on to the new
> > nonroot-task and any non-inheritable effective and permitted
> > capabilities will be masked out.
> > The effective capability of the new nonroot-task will be set to the
> > maximum permitted.
>
> What happens to eff on setuid() to non-root

If KEEPCAPS is set the permitted and inheritable capabilities are still
there, the effective capabilities are cleared either way.

> or restore to uid 0?

Full capabilities restored.

> What happens if you exec a setuid-root binary,

Sets full permitted & effective, inheritable left as is.
This means that if the setuid-root binary does an execve to another
program cap_inheritable will take effect and the capabilities will be
the same as before calling the setuid-root binary. I doubt this is
common scenario however.

> or a setuid-nonroot binary?

capabilities unchanged

> How about ptrace?

I'll look into this part, but I don't see it changing anything here
right now.

However I'm sure there are cases I've missed and I'm looking for them
right now. This patch is going to need a few good eyes.

> Here's the tests I use.

I've looked at some cases in this test suite but as It doesn't say much
more than "begin test 37" I have no idea of how to parse the output.

Updated patch.

===== security/commoncap.c 1.15 vs edited =====
--- 1.15/security/commoncap.c 2005-01-11 02:29:23 +01:00
+++ edited/security/commoncap.c 2005-03-15 14:45:36 +01:00
@@ -111,13 +111,19 @@ void cap_capset_set (struct task_struct

int cap_bprm_set_security (struct linux_binprm *bprm)
{
- /* Copied from fs/exec.c:prepare_binprm. */
-
- /* We don't have VFS support for capabilities yet */
- cap_clear (bprm->cap_inheritable);
- cap_clear (bprm->cap_permitted);
- cap_clear (bprm->cap_effective);
+ struct task_struct *p = current;

+ /*
+ * Mask out the non-inheritable capabilities.
+ * Note: init has a zero mask of cap_inheritable, so a root-task will not
+ * pass on any capabilities unless explicitly told to do so. If a non-zero
+ * inheritable mask is passed to a positive uid task it will then pass on
+ * its inheritable mask to all children unless told otherwise.
+ */
+ bprm->cap_permitted = cap_intersect(p->cap_permitted, p->cap_inheritable);
+ bprm->cap_effective = cap_intersect(p->cap_effective, p->cap_inheritable);
+ bprm->cap_inheritable = p->cap_inheritable;
+
/* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we raise all three
* capability sets for the file.
@@ -127,7 +133,7 @@ int cap_bprm_set_security (struct linux_
*/

if (!issecure (SECURE_NOROOT)) {
- if (bprm->e_uid == 0 || current->uid == 0) {
+ if (bprm->e_uid == 0 || p->uid == 0) {
cap_set_full (bprm->cap_inheritable);
cap_set_full (bprm->cap_permitted);
}
@@ -139,13 +145,9 @@ int cap_bprm_set_security (struct linux_

void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
- /* Derived from fs/exec.c:compute_creds. */
- kernel_cap_t new_permitted, working;
+ kernel_cap_t new_permitted;

new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
- working = cap_intersect (bprm->cap_inheritable,
- current->cap_inheritable);
- new_permitted = cap_combine (new_permitted, working);

if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
!cap_issubset (new_permitted, current->cap_permitted)) {
@@ -166,14 +168,15 @@ void cap_bprm_apply_creds (struct linux_
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;

- /* For init, we want to retain the capabilities set
- * in the init_task struct. Thus we skip the usual
- * capability rules */
- if (current->pid != 1) {
- current->cap_permitted = new_permitted;
- current->cap_effective =
- cap_intersect (new_permitted, bprm->cap_effective);
- }
+ current->cap_permitted = new_permitted;
+ /*
+ * Is this a root task that did seteuid before execve? if so
+ * it wanted its effective permissions dropped.
+ */
+ if (current->euid && current->uid == 0)
+ cap_clear(current->cap_effective);
+ else
+ current->cap_effective = new_permitted;

/* AUD: Audit candidate if current->cap_effective is set */



2005-03-15 21:58:00

by Russell King

[permalink] [raw]
Subject: Re: Capabilities across execve

On Sat, Mar 12, 2005 at 07:21:17PM -0800, Chris Wright wrote:
> * Alexander Nyberg ([email protected]) wrote:
> > This makes it possible for a root-task to pass capabilities to
> > nonroot-task across execve. The root-task needs to change it's
> > cap_inheritable mask and set prctl(PR_SET_KEEPCAPS, 1) to pass on
> > capabilities.
>
> This overloads keepcaps, which could surprise to existing users.

Chris,

Since you seem to be knowledgeable about the capability system, I have
a question.

As part of the libcap library (found on Fedora and such like), there are
several programs supplied with it - execcap and sucap for instance:

usage: execcap <caps> <command-path> [command-args...]

This program is a wrapper that can be used to limit the Inheritable
capabilities of a program to be executed. Note, this wrapper is
intended to assist in overcoming a lack of support for filesystem
capability attributes and should be used to launch other files.
This program should _NOT_ be made setuid-0.

usage: sucap <user> <group> <command-path> [command-args...]

This program is a wrapper that change UID but not privileges of a
program to be executed.
Note, this wrapper is intended to assist in overcoming a lack of support
for filesystem capability attributes and should be used to launch other
files. This program should _NOT_ be made setuid-0.

At some point, I decided I'd like to run a certain program non-root
with certain capabilities only. I looked at the above two programs
and stupidly thought they'd actually allow me to do this.

However, the way the kernel is setup today, this seems impossible to
achieve, which tends to make the whole idea of capabilities completely
and utterly useless.

How is this stuff supposed to work? Are my ideas of what's supposed
to be achievable completely wrong, although they look completely
reasonable to me.

Don't get me wrong - the capability system seems great at permanently
revoking capabilities via /proc/sys/kernel/cap-bound, and dropping
them within an application provided it remains UID0. Apart from that,
capabilities seem completely useless.

For example:

bash-2.05a# execcap all-ep /bin/sh -c 'getpcaps $$'
Capabilities for `5036': =ep cap_setpcap-ep

Note carefully that the requested capabilities haven't been granted:

capset(0x19980330, 0, {, , }) = 0
execve("/bin/sh", ["/bin/sh", "-c", "getpcaps $$"], [/* 19 vars */]) = 0

The reason this happens is that we're still running UID0, and UID0 on
execve appears to re-gain all privileges. This is fine of you're
running in compatibility mode. So, in order to do this, we want to
drop from UID0 _first_ and then play around with capabilities. Great,
we have the sucap program to do that for us. So we can do:

sucap rmk rmk execcap <capabilities> program args

Or can we?

bash-2.05a# sucap rmk rmk /bin/sh -c 'getpcaps $$'
Caps: =ep cap_setpcap-ep
Caps: =
[debug] uid:501, real uid:501
sucaps: capsetp: Operation not permitted
sucap: child did not exit cleanly.

Oh dear, I guess sucap doesn't work after all. (It forks a child
process, the parent then switches UID, the child then tries to
capsetp() the parent - which of course won't work without the
cap_setpcap. Since the kernel never grants this capability in the
first place to *anyone*... it seems to be something of a lost cause.

Don't get me wrong - the current behaviour is secure. But it's so
secure that it gets in the way of things which should appear to work.

I forget precisely what I wanted to achieve with this, and why I
couldn't just make the program do it itself... It may have been a
script running from cron periodically which needed just one or two
capabilities in order to operate, rather than the whole truck load
you get by running it as root. What I do remember is that my goal
of running the script with minimal capabilities was completely
*impossible* to achieve.

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: 2.6 Serial core

2005-03-15 22:45:46

by Chris Wright

[permalink] [raw]
Subject: Re: Capabilities across execve

* Russell King ([email protected]) wrote:
> At some point, I decided I'd like to run a certain program non-root
> with certain capabilities only. I looked at the above two programs
> and stupidly thought they'd actually allow me to do this.
>
> However, the way the kernel is setup today, this seems impossible to
> achieve, which tends to make the whole idea of capabilities completely
> and utterly useless.

Yes, the only value of capabilities right now is for a single program
that starts off as root with full caps to drop uid and caps.

> How is this stuff supposed to work? Are my ideas of what's supposed
> to be achievable completely wrong, although they look completely
> reasonable to me.

It was meant to work with capabilities in the filesystem like setuid bits.
So the patches that have floated around from myself, Andy Lutomirski
and Alex Nyberg are attempts to make something half-way sane out of the
mess. The trouble is then convincing yourself that it's not some way to
leak capabilities (esp. since some programs use the interface already,
like bind9).

> Don't get me wrong - the capability system seems great at permanently
> revoking capabilities via /proc/sys/kernel/cap-bound, and dropping
> them within an application provided it remains UID0. Apart from that,
> capabilities seem completely useless.

It doesn't have to remain uid0. That's what the prctl PR_SET_KEEPCAPS does.
But it's not a nice interface, nor simple to use (for example, it'll
drop the effective set, so you have to reinstate them).

> For example:
>
> bash-2.05a# execcap all-ep /bin/sh -c 'getpcaps $$'
> Capabilities for `5036': =ep cap_setpcap-ep
>
> Note carefully that the requested capabilities haven't been granted:
>
> capset(0x19980330, 0, {, , }) = 0
> execve("/bin/sh", ["/bin/sh", "-c", "getpcaps $$"], [/* 19 vars */]) = 0
>
> The reason this happens is that we're still running UID0, and UID0 on
> execve appears to re-gain all privileges. This is fine of you're
> running in compatibility mode. So, in order to do this, we want to
> drop from UID0 _first_ and then play around with capabilities. Great,
> we have the sucap program to do that for us. So we can do:
>
> sucap rmk rmk execcap <capabilities> program args
>
> Or can we?
>
> bash-2.05a# sucap rmk rmk /bin/sh -c 'getpcaps $$'
> Caps: =ep cap_setpcap-ep
> Caps: =
> [debug] uid:501, real uid:501
> sucaps: capsetp: Operation not permitted
> sucap: child did not exit cleanly.
>
> Oh dear, I guess sucap doesn't work after all. (It forks a child
> process, the parent then switches UID, the child then tries to
> capsetp() the parent - which of course won't work without the
> cap_setpcap. Since the kernel never grants this capability in the
> first place to *anyone*... it seems to be something of a lost cause.

Yes, that's the core of the issue. If you exec a uid0 process you get
all caps, otherwise you lose all caps. And cap_setpcap was removed when the
sendmail exploit came out, so it's further crippled.

> Don't get me wrong - the current behaviour is secure. But it's so
> secure that it gets in the way of things which should appear to work.
>
> I forget precisely what I wanted to achieve with this, and why I
> couldn't just make the program do it itself... It may have been a
> script running from cron periodically which needed just one or two
> capabilities in order to operate, rather than the whole truck load
> you get by running it as root. What I do remember is that my goal
> of running the script with minimal capabilities was completely
> *impossible* to achieve.

All I can say is work is underway. There's 3 different patches that
will get you to your goal. I understand that it's a real pain right now.
One of the authors of the withdrawn draft has told me that the notion of
capabilities w/out filesystem support was considered effectively useless.
So, we're in uncharted territory. BTW, thanks for reminding me of
scripts, I had been testing just C programs.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2005-03-15 23:49:52

by Alexander Nyberg

[permalink] [raw]
Subject: Re: Capabilities across execve

tis 2005-03-15 klockan 14:42 -0800 skrev Chris Wright:
> * Russell King ([email protected]) wrote:
> > At some point, I decided I'd like to run a certain program non-root
> > with certain capabilities only. I looked at the above two programs
> > and stupidly thought they'd actually allow me to do this.
> >
> > However, the way the kernel is setup today, this seems impossible to
> > achieve, which tends to make the whole idea of capabilities completely
> > and utterly useless.
>
> Yes, the only value of capabilities right now is for a single program
> that starts off as root with full caps to drop uid and caps.
>
> > How is this stuff supposed to work? Are my ideas of what's supposed
> > to be achievable completely wrong, although they look completely
> > reasonable to me.
>
> It was meant to work with capabilities in the filesystem like setuid bits.
> So the patches that have floated around from myself, Andy Lutomirski
> and Alex Nyberg are attempts to make something half-way sane out of the
> mess. The trouble is then convincing yourself that it's not some way to
> leak capabilities (esp. since some programs use the interface already,
> like bind9).

Anyone who uses the current interfaces should not play with the
inheritable flag, the text I looked at said it was specifically for
execve. Thus if the application doesn't modify the inheritable mask
things will look like it has always done. And it really should not mess
with inheritable mask if it doesn't intend to, that would be a security
bug.
We really should be safe doing this.

> > Don't get me wrong - the capability system seems great at permanently
> > revoking capabilities via /proc/sys/kernel/cap-bound, and dropping
> > them within an application provided it remains UID0. Apart from that,
> > capabilities seem completely useless.
>
> It doesn't have to remain uid0. That's what the prctl PR_SET_KEEPCAPS does.
> But it's not a nice interface, nor simple to use (for example, it'll
> drop the effective set, so you have to reinstate them).
>
>
> > Don't get me wrong - the current behaviour is secure. But it's so
> > secure that it gets in the way of things which should appear to work.
> >
> > I forget precisely what I wanted to achieve with this, and why I
> > couldn't just make the program do it itself... It may have been a
> > script running from cron periodically which needed just one or two
> > capabilities in order to operate, rather than the whole truck load
> > you get by running it as root. What I do remember is that my goal
> > of running the script with minimal capabilities was completely
> > *impossible* to achieve.
>
> All I can say is work is underway. There's 3 different patches that
> will get you to your goal. I understand that it's a real pain right now.
> One of the authors of the withdrawn draft has told me that the notion of
> capabilities w/out filesystem support was considered effectively useless.
> So, we're in uncharted territory. BTW, thanks for reminding me of
> scripts, I had been testing just C programs.

I wouldn't call it useless, retaining capabilities across execve +
pam_cap is a very useful thing, on my machine I can give myself a few
capabilities that have always annoyed me (iirc the database that wanted
mlock as regular user would have been solved aswell).

Regarding fs attributes:
http://www.ussg.iu.edu/hypermail/linux/kernel/0211.0/0171.html

I can see useful scenarios of having the possiblity of capabilities per
inode (it appears the xattr way wins somewhat in the previous
discussion).

Chris, have you seen any capabilities+xattr patches around?

2005-03-16 00:05:46

by Chris Wright

[permalink] [raw]
Subject: Re: Capabilities across execve

* Alexander Nyberg ([email protected]) wrote:
> tis 2005-03-15 klockan 14:42 -0800 skrev Chris Wright:
> > It was meant to work with capabilities in the filesystem like setuid bits.
> > So the patches that have floated around from myself, Andy Lutomirski
> > and Alex Nyberg are attempts to make something half-way sane out of the
> > mess. The trouble is then convincing yourself that it's not some way to
> > leak capabilities (esp. since some programs use the interface already,
> > like bind9).
>
> Anyone who uses the current interfaces should not play with the
> inheritable flag, the text I looked at said it was specifically for
> execve. Thus if the application doesn't modify the inheritable mask
> things will look like it has always done. And it really should not mess
> with inheritable mask if it doesn't intend to, that would be a security
> bug.
> We really should be safe doing this.

That's one of the points. Latent bugs getting triggered is what makes
the change deserving of being conservative.

> > All I can say is work is underway. There's 3 different patches that
> > will get you to your goal. I understand that it's a real pain right now.
> > One of the authors of the withdrawn draft has told me that the notion of
> > capabilities w/out filesystem support was considered effectively useless.
> > So, we're in uncharted territory. BTW, thanks for reminding me of
> > scripts, I had been testing just C programs.
>
> I wouldn't call it useless, retaining capabilities across execve +
> pam_cap is a very useful thing, on my machine I can give myself a few
> capabilities that have always annoyed me (iirc the database that wanted
> mlock as regular user would have been solved aswell).

Yes, that's useful, but having 3 sets and complicated rules for
combining task and file based sets is not really necessary for that.

> Regarding fs attributes:
> http://www.ussg.iu.edu/hypermail/linux/kernel/0211.0/0171.html
>
> I can see useful scenarios of having the possiblity of capabilities per
> inode (it appears the xattr way wins somewhat in the previous
> discussion).

It's how it should be done.

> Chris, have you seen any capabilities+xattr patches around?

http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.4-fcap/

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2005-03-16 00:19:45

by Albert Cahalan

[permalink] [raw]
Subject: Re: Capabilities across execve

Russell King, the latest person to notice defects, writes:

> However, the way the kernel is setup today, this seems
> impossible to achieve, which tends to make the whole
> idea of capabilities completely and utterly useless.
>
> How is this stuff supposed to work? Are my ideas of
> what's supposed to be achievable completely wrong,
> although they look completely reasonable to me.
>
> Don't get me wrong - the capability system seems great at
> permanently revoking capabilities via /proc/sys/kernel/cap-bound,
> and dropping them within an application provided it remains UID0.
> Apart from that, capabilities seem completely useless.
...
> it seems to be something of a lost cause.
...
> my goal of running the script with minimal capabilities
> was completely *impossible* to achieve.

Uh huh. First, some history.

Capability bits were implemented in DG-UX and IRIX.
The two systems did not agree on operation. The draft
POSIX standard, withdrawn for good reason, greatly
changed between draft 16 and draft 17. Settings that
work for one draft are horribly insecure on the other.
Linux capabilities were partly done by the IRIX crew,
working from draft 16. Everyone else had draft 17 or
even draft 13. (and DG-UX had a better system anyway)

Tytso put things well when he wrote: "A lot of innocent
bits have been deforested while trying work out the
differences between what Linux is doing (which is basically
following Draft 17), and what Trusted Irix is doing (which
apparently is following Draft 16)."

Then along comes a sendmail exploit. An emergency fix
was produced, breaking an already-defective capability
design.

Note that, unlike DG-UX, our IRIX-inspired design did
not reserve any capability bits for non-kernel use.
This causes an inconsistent security model, with things
like the X server relying on UID. Inconsistency is bad.

OK, so that's how we got into this mess.

Now, how do we get out?

We will always have to deal with old-style apps. Those
few apps that handle capabilities can handle the bad
system we have now, and can handle a system without the
capability syscalls. (for old kernels) These apps can
not handle a changed setup though; to change things we
must make the old syscalls return failure. ANYTHING ELSE
IS VERY UNSAFE.

There is exactly one capability system in popular use.
That would be the one that comes with Solaris. Moving
toward that, via a kernel config option, appears to be
a sane way to get ourselves unstuck from this big mess.
An added advantage that that the Solaris-style method
instantly becomes the standard, especially if Linux is
strongly compatible. This helps with admin training and
portable software.

See if you can find any holes:
http://docs.sun.com/app/docs/doc/816-5175/6mbba7f39?a=view


2005-03-16 00:36:24

by Alexander Nyberg

[permalink] [raw]
Subject: Re: Capabilities across execve

> > > It was meant to work with capabilities in the filesystem like setuid bits.
> > > So the patches that have floated around from myself, Andy Lutomirski
> > > and Alex Nyberg are attempts to make something half-way sane out of the
> > > mess. The trouble is then convincing yourself that it's not some way to
> > > leak capabilities (esp. since some programs use the interface already,
> > > like bind9).
> >
> > Anyone who uses the current interfaces should not play with the
> > inheritable flag, the text I looked at said it was specifically for
> > execve. Thus if the application doesn't modify the inheritable mask
> > things will look like it has always done. And it really should not mess
> > with inheritable mask if it doesn't intend to, that would be a security
> > bug.
> > We really should be safe doing this.
>
> That's one of the points. Latent bugs getting triggered is what makes
> the change deserving of being conservative.

bind9 actually sets inheritable, but I don't see it doing any exec in
the whole package, so it should be safe. I'll look for other large
common packages using capabilities.
I don't think this necessarily is 2.7 material, but otoh if it has
waited this long there doesn't appear to be that kind of rush to get it
in.

> > > All I can say is work is underway. There's 3 different patches that
> > > will get you to your goal. I understand that it's a real pain right now.
> > > One of the authors of the withdrawn draft has told me that the notion of
> > > capabilities w/out filesystem support was considered effectively useless.
> > > So, we're in uncharted territory. BTW, thanks for reminding me of
> > > scripts, I had been testing just C programs.
> >
> > I wouldn't call it useless, retaining capabilities across execve +
> > pam_cap is a very useful thing, on my machine I can give myself a few
> > capabilities that have always annoyed me (iirc the database that wanted
> > mlock as regular user would have been solved aswell).
>
> Yes, that's useful, but having 3 sets and complicated rules for
> combining task and file based sets is not really necessary for that.

However I never saw any real clean solution for the problem and I would
call this better and more general for this kind of problems.

> > Regarding fs attributes:
> > http://www.ussg.iu.edu/hypermail/linux/kernel/0211.0/0171.html
> >
> > I can see useful scenarios of having the possiblity of capabilities per
> > inode (it appears the xattr way wins somewhat in the previous
> > discussion).
>
> It's how it should be done.
>
> > Chris, have you seen any capabilities+xattr patches around?
>
> http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.4-fcap/

Thanks, I'll have a look at this.

2005-03-19 00:13:35

by Olaf Dietsche

[permalink] [raw]
Subject: Re: Capabilities across execve

Chris Wright <[email protected]> writes:

> * Alexander Nyberg ([email protected]) wrote:
>> I can see useful scenarios of having the possiblity of capabilities per
>> inode (it appears the xattr way wins somewhat in the previous
>> discussion).
>
> It's how it should be done.

I agree to disagree :-)

>> Chris, have you seen any capabilities+xattr patches around?
>
> http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.4-fcap/

Which is pretty useless, since it doesn't apply to any recent
(> 2.4.3) kernel. If you insist on a xattr based approach, take
Andy Lutomirski's <http://www.stanford.edu/~luto/linux-fscap/>
patch. It is more recent, a lot smaller and considerably more
understandable (at least for me ;-).

Regards, Olaf.