Andrew Morgan wrote: > Serge E. Hallyn wrote: >>> 0. fix the implementation of cap_setpcap. It is supposed to mean 'this >>> process can raise capabilities, outside its permitted set, in _its own_ >>> inheritable set'.
I believe the attached patch does this. FWIW There is a mighty old (circa 1999) pam_cap tar.gz file here: http://www.kernel.org/pub/linux/libs/pam/pre/modules/pam_cap-0.1.tar.gz I'll see what it takes to get this to all work together. :-) Cheers Andrew
>From 54c13846946b86e4254bfd2b32d02f4a949760da Mon Sep 17 00:00:00 2001 From: Andrew Morgan <[EMAIL PROTECTED]> Date: Sat, 4 Aug 2007 19:14:50 -0700 Subject: [PATCH] Change the meaning of CAP_SETPCAP when filesystem support is enabled. The non-filesystem capability meaning of CAP_SETPCAP is that a process, p1, can change the capabilities of another process, p2. This is not the meaning that was intended for this capability at all, and this implementation came about purely because, without filesystem capabilities, there was no way to use capabilities without one process bestowing them on another. Since we now have a filesystem support for capabilities we can fix the implementation of CAP_SETPCAP. The most significant thing about this change is that, with it in effect, no process can set the capabilities of another process. The capabilities of a program are set via the capability convolution rules: pI(post-exec) = pI(pre-exec) pP(post-exec) = (X(aka cap_bset) & fP) | (pI(post-exec) & fI) pE(post-exec) = fE ? pP(post-exec) : 0 at exec() time. As such, the only influence the pre-exec() program can have on the post-exec() program's capabilities are throught the pI capability set. The correct implementation for CAP_SETPCAP (and that enabled by this patch) is that it can be used to add extra pI capabilities to the current process - to be picked up by subsequent exec()s when the above convolution rules are applied. Here is how it works: Let's say we have a process, p. It has capability sets, pE, pP and pI. Generally, p, can change the value of its own pI to pI' where (pI' & ~pI) & ~pP = 0. That is, the only new things in pI' that were not present in pI need to be present in pP. The role of CAP_SETPCAP is basically to permit changes to pI beyond the above: if (pE & CAP_SETPCAP) { pI' = anything; /* ie., even (pI' & ~pI) & ~pP != 0 */ } This capability is useful for things like login, which (say, via pam_cap) might want to raise certain inheritable capabilities for use by the children of the logged-in user's shell, but those capabilities are not useful to or needed by the login program itself. One such use might be to limit who can run ping. You set the capabilities of the 'ping' program to be "= cap_net_raw+i", and then only shells that have (pI & CAP_NET_RAW) will be able to run it. Without CAP_SETPCAP implemented as described above, login(pam_cap) would have to also have (pP & CAP_NET_RAW) in order to raise this capability and pass it on through the inheritable set. Signed-off-by: Andrew Morgan <[EMAIL PROTECTED]> --- kernel/capability.c | 2 +- security/capability.c | 8 ++++++++ security/commoncap.c | 20 +++++++++++++++++--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/kernel/capability.c b/kernel/capability.c index c8d3c77..4f6166f 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -3,7 +3,7 @@ * * Copyright (C) 1997 Andrew Main <[EMAIL PROTECTED]> * - * Integrated into 2.1.97+, Andrew G. Morgan <[EMAIL PROTECTED]> + * Integrated into 2.1.97+, Andrew G. Morgan <[EMAIL PROTECTED]> * 30 May 2002: Cleanup, Robert M. Love <[EMAIL PROTECTED]> */ diff --git a/security/capability.c b/security/capability.c index 0db5fda..47ec7ca 100644 --- a/security/capability.c +++ b/security/capability.c @@ -74,6 +74,14 @@ static int __init capability_init (void) } secondary = 1; } +#ifdef CONFIG_SECURITY_FILE_CAPABILITIES + /* + * Because of the reduced scope of CAP_SETPCAP when filesystem + * capabilities are in effect, it is safe to allow this + * capability to be available in the default configuration. + */ + cap_bset = CAP_FULL_SET; +#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ printk (KERN_INFO "Capability LSM initialized%s\n", secondary ? " as secondary" : ""); return 0; diff --git a/security/commoncap.c b/security/commoncap.c index 6349093..19efaed 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -78,11 +78,25 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective, int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - /* Derived from kernel/capability.c:sys_capset. */ - /* verify restrictions on target's new Inheritable set */ - if (!cap_issubset (*inheritable, +#ifdef CONFIG_SECURITY_FILE_CAPABILITIES + if (target != current) { + /* + * No support for remote process capability manipulation + * with filesystem capability support. + */ + return -EPERM; + } + + if ( (!cap_capable(current, CAP_SETPCAP)) + && +#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */ + if ( +#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ + + !cap_issubset (*inheritable, cap_combine (target->cap_inheritable, current->cap_permitted))) { + /* incapable of using this inheritable set */ return -EPERM; } -- 1.5.1.3