Quoting Andrew Morgan ([EMAIL PROTECTED]): > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Andrew Morgan wrote: > > Andrew Morgan wrote: > >> Serge E. Hallyn wrote: > >>> (Sorry, I should have ran shorter tests to get these results a little > >>> quicker...) > >>> Unfortunately these can't be moved here. If you have > >>> SECURITY=y > >>> SECURITY_CAPABILITIES=n > >>> then commoncap is not compiled, and > >>> security/dummy.c wants securebits > > OK. I believe this (finally) does it. :-) > > Cheers > > Andrew > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.2.6 (GNU/Linux) > > iD8DBQFGxzFTQheEq9QabfIRAsJeAJ91MC/tJrtsJpg+vZf7sdPrTXCOTwCeOln6 > 74oG9QD9TWy3F5ne2p2Npa4= > =ZKAK > -----END PGP SIGNATURE-----
> >From d1904e8f5f28e00957cae25255b1690be8413c77 Mon Sep 17 00:00:00 2001 > From: Andrew Morgan <[EMAIL PROTECTED]> > Date: Wed, 15 Aug 2007 07:27:29 -0700 > Subject: [PATCH] File capabilities implementation of CAP_SETPCAP > > 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 through 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]> > --- > include/linux/capability.h | 4 --- > include/linux/security.h | 7 +++++ > kernel/capability.c | 8 +----- > kernel/sysctl.c | 8 ++++- > kernel/sysctl_check.c | 5 +++ > security/commoncap.c | 59 ++++++++++++++++++++++++++++++++++++++++--- > security/dummy.c | 16 +++++------ > 7 files changed, 80 insertions(+), 27 deletions(-) > > diff --git a/include/linux/capability.h b/include/linux/capability.h > index 8961e7f..7a8d7ad 100644 > --- a/include/linux/capability.h > +++ b/include/linux/capability.h > @@ -310,10 +310,6 @@ typedef __u32 kernel_cap_t; > #define CAP_SETFCAP 31 > > #ifdef __KERNEL__ > -/* > - * Bounding set > - */ > -extern kernel_cap_t cap_bset; > > /* > * Internal kernel functions only > diff --git a/include/linux/security.h b/include/linux/security.h > index e38230f..b673fd2 100644 > --- a/include/linux/security.h > +++ b/include/linux/security.h > @@ -34,6 +34,13 @@ > #include <linux/xfrm.h> > #include <net/flow.h> > > +/* > + * Bounding set > + */ > +extern kernel_cap_t cap_bset; > + > +extern unsigned securebits; > + > struct ctl_table; > > /* > diff --git a/kernel/capability.c b/kernel/capability.c > index 8c4773c..55aa5f0 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]> > */ > > @@ -15,12 +15,6 @@ > #include <linux/pid_namespace.h> > #include <asm/uaccess.h> > > -unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ > -kernel_cap_t cap_bset = CAP_INIT_EFF_SET; > - > -EXPORT_SYMBOL(securebits); > -EXPORT_SYMBOL(cap_bset); > - > /* > * This lock protects task->cap_* for all tasks including current. > * Locking rule: acquire this prior to tasklist_lock. > diff --git a/kernel/sysctl.c b/kernel/sysctl.c > index 8ced8cc..cf0b136 100644 > --- a/kernel/sysctl.c > +++ b/kernel/sysctl.c > @@ -25,7 +25,7 @@ > #include <linux/swap-prefetch.h> > #include <linux/sysctl.h> > #include <linux/proc_fs.h> > -#include <linux/capability.h> > +#include <linux/security.h> > #include <linux/ctype.h> > #include <linux/utsname.h> > #include <linux/smp_lock.h> > @@ -370,6 +370,7 @@ static struct ctl_table kern_table[] = { > .proc_handler = &proc_dointvec_taint, > }, > #endif > +#ifdef CONFIG_SECURITY_CAPABILITIES > { > .procname = "cap-bound", > .data = &cap_bset, > @@ -377,6 +378,7 @@ static struct ctl_table kern_table[] = { > .mode = 0600, > .proc_handler = &proc_dointvec_bset, > }, > +#endif /* def CONFIG_SECURITY_CAPABILITIES */ > #ifdef CONFIG_BLK_DEV_INITRD > { > .ctl_name = KERN_REALROOTDEV, > @@ -1899,10 +1901,11 @@ static int do_proc_dointvec_bset_conv(int *negp, > unsigned long *lvalp, > return 0; > } > > +#ifdef CONFIG_SECURITY_CAPABILITIES > /* > * init may raise the set. > */ > - > + > int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp, > void __user *buffer, size_t *lenp, loff_t *ppos) > { > @@ -1916,6 +1919,7 @@ int proc_dointvec_bset(struct ctl_table *table, int > write, struct file *filp, > return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, > do_proc_dointvec_bset_conv,&op); > } > +#endif /* def CONFIG_SECURITY_CAPABILITIES */ > > /* > * Taint values can only be increased > diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c > index 930a514..7aa581b 100644 > --- a/kernel/sysctl_check.c > +++ b/kernel/sysctl_check.c > @@ -37,7 +37,10 @@ static struct trans_ctl_table trans_kern_table[] = { > { KERN_NODENAME, "hostname" }, > { KERN_DOMAINNAME, "domainname" }, > > +#ifdef CONFIG_SECURITY_CAPABILITIES > { KERN_CAP_BSET, "cap-bound" }, > +#endif /* def CONFIG_SECURITY_CAPABILITIES */ > + > { KERN_PANIC, "panic" }, > { KERN_REALROOTDEV, "real-root-dev" }, > > @@ -1510,7 +1513,9 @@ int sysctl_check_table(struct ctl_table *table) > (table->strategy == sysctl_ms_jiffies) || > (table->proc_handler == proc_dostring) || > (table->proc_handler == proc_dointvec) || > +#ifdef CONFIG_SECURITY_CAPABILITIES > (table->proc_handler == proc_dointvec_bset) || > +#endif /* def CONFIG_SECURITY_CAPABILITIES */ > (table->proc_handler == proc_dointvec_minmax) || > (table->proc_handler == proc_dointvec_jiffies) || > (table->proc_handler == > proc_dointvec_userhz_jiffies) || > diff --git a/security/commoncap.c b/security/commoncap.c > index 7816cdc..ef4beaa 100644 > --- a/security/commoncap.c > +++ b/security/commoncap.c > @@ -25,6 +25,25 @@ > #include <linux/mount.h> > #include <linux/sched.h> > > +#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. > + */ > +# define CAP_INIT_BSET CAP_FULL_SET > +#else /* ie. ndef CONFIG_SECURITY_FILE_CAPABILITIES */ > +# define CAP_INIT_BSET CAP_INIT_EFF_SET > +#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ > + > +kernel_cap_t cap_bset = CAP_INIT_BSET; /* systemwide capability bound */ > +EXPORT_SYMBOL(cap_bset); > + > +/* Global security state */ > + > +unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ > +EXPORT_SYMBOL(securebits); > + > int cap_netlink_send(struct sock *sk, struct sk_buff *skb) > { > NETLINK_CB(skb).eff_cap = current->cap_effective; > @@ -76,14 +95,44 @@ int cap_capget (struct task_struct *target, kernel_cap_t > *effective, > return 0; > } > > +#ifdef CONFIG_SECURITY_FILE_CAPABILITIES > + > +static inline int cap_block_setpcap(struct task_struct *target) > +{ > + /* > + * No support for remote process capability manipulation with > + * filesystem capability support. > + */ > + return (target != current); > +} > + > +static inline int cap_inh_is_capped(void) > +{ > + /* > + * return 1 if changes to the inheritable set are limited > + * to the old permitted set. > + */ > + return !cap_capable(current, CAP_SETPCAP); > +} > + > +#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */ > + > +static inline int cap_block_setpcap(struct task_struct *t) { return 0; } > +static inline int cap_inh_is_capped(void) { return 1; } > + > +#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ > + > 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, > - cap_combine (target->cap_inheritable, > - current->cap_permitted))) { > + if (cap_block_setpcap(target)) { > + return -EPERM; > + } > + if (cap_inh_is_capped() > + && !cap_issubset(*inheritable, > + cap_combine(target->cap_inheritable, > + current->cap_permitted))) { > + /* incapable of using this inheritable set */ > return -EPERM; > } > > diff --git a/security/dummy.c b/security/dummy.c > index 5839faa..80142a9 100644 > --- a/security/dummy.c > +++ b/security/dummy.c > @@ -37,15 +37,13 @@ static int dummy_capget (struct task_struct *target, > kernel_cap_t * effective, > kernel_cap_t * inheritable, kernel_cap_t * permitted) > { > *effective = *inheritable = *permitted = 0; > - if (!issecure(SECURE_NOROOT)) { > - if (target->euid == 0) { > - *permitted |= (~0 & ~CAP_FS_MASK); > - *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & > ~CAP_FS_MASK); > - } > - if (target->fsuid == 0) { > - *permitted |= CAP_FS_MASK; > - *effective |= CAP_FS_MASK; > - } > + if (target->euid == 0) { > + *permitted |= (~0 & ~CAP_FS_MASK); > + *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); > + } > + if (target->fsuid == 0) { > + *permitted |= CAP_FS_MASK; > + *effective |= CAP_FS_MASK; > } > return 0; > } > -- > 1.5.1.3 This passed ltp with all sorts of kernel configs. Signed-off-by: Serge E. Hallyn <[EMAIL PROTECTED]> thanks, -serge - To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html