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

Reply via email to