Merge branch 'next' into for-linus
authorJames Morris <jmorris@namei.org>
Tue, 24 May 2011 12:55:24 +0000 (22:55 +1000)
committerJames Morris <jmorris@namei.org>
Tue, 24 May 2011 12:55:24 +0000 (22:55 +1000)
1  2 
include/linux/capability.h
include/linux/init_task.h
include/linux/kmod.h
kernel/kmod.c
kernel/sysctl.c
security/keys/user_defined.c

@@@ -355,12 -355,7 +355,12 @@@ struct cpu_vfs_cap_data 
  
  #define CAP_SYSLOG           34
  
 -#define CAP_LAST_CAP         CAP_SYSLOG
 +/* Allow triggering something that will wake the system */
 +
 +#define CAP_WAKE_ALARM            35
 +
 +
 +#define CAP_LAST_CAP         CAP_WAKE_ALARM
  
  #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
  
@@@ -417,7 -412,6 +417,6 @@@ extern const kernel_cap_t __cap_init_ef
  
  # define CAP_EMPTY_SET    ((kernel_cap_t){{ 0, 0 }})
  # define CAP_FULL_SET     ((kernel_cap_t){{ ~0, ~0 }})
- # define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }})
  # define CAP_FS_SET       ((kernel_cap_t){{ CAP_FS_MASK_B0 \
                                    | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
                                    CAP_FS_MASK_B1 } })
  
  #endif /* _KERNEL_CAPABILITY_U32S != 2 */
  
- #define CAP_INIT_INH_SET    CAP_EMPTY_SET
  # define cap_clear(c)         do { (c) = __cap_empty_set; } while (0)
- # define cap_set_full(c)      do { (c) = __cap_full_set; } while (0)
- # define cap_set_init_eff(c)  do { (c) = __cap_init_eff_set; } while (0)
  
  #define cap_raise(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
  #define cap_lower(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))
@@@ -83,13 -83,6 +83,6 @@@ extern struct group_info init_groups
  #define INIT_IDS
  #endif
  
- /*
-  * Because of the reduced scope of CAP_SETPCAP when filesystem
-  * capabilities are in effect, it is safe to allow CAP_SETPCAP to
-  * be available in the default configuration.
-  */
- # define CAP_INIT_BSET  CAP_FULL_SET
  #ifdef CONFIG_RCU_BOOST
  #define INIT_TASK_RCU_BOOST()                                         \
        .rcu_boost_mutex = NULL,
@@@ -134,6 -127,7 +127,6 @@@ extern struct cred init_cred
        .stack          = &init_thread_info,                            \
        .usage          = ATOMIC_INIT(2),                               \
        .flags          = PF_KTHREAD,                                   \
 -      .lock_depth     = -1,                                           \
        .prio           = MAX_PRIO-20,                                  \
        .static_prio    = MAX_PRIO-20,                                  \
        .normal_prio    = MAX_PRIO-20,                                  \
diff --combined include/linux/kmod.h
@@@ -24,6 -24,7 +24,7 @@@
  #include <linux/errno.h>
  #include <linux/compiler.h>
  #include <linux/workqueue.h>
+ #include <linux/sysctl.h>
  
  #define KMOD_PATH_LEN 256
  
@@@ -109,10 -110,11 +110,12 @@@ call_usermodehelper(char *path, char **
                                       NULL, NULL, NULL);
  }
  
+ extern struct ctl_table usermodehelper_table[];
  extern void usermodehelper_init(void);
  
  extern int usermodehelper_disable(void);
  extern void usermodehelper_enable(void);
 +extern bool usermodehelper_is_disabled(void);
  
  #endif /* __LINUX_KMOD_H__ */
diff --combined kernel/kmod.c
@@@ -25,6 -25,7 +25,7 @@@
  #include <linux/kmod.h>
  #include <linux/slab.h>
  #include <linux/completion.h>
+ #include <linux/cred.h>
  #include <linux/file.h>
  #include <linux/fdtable.h>
  #include <linux/workqueue.h>
@@@ -43,6 -44,13 +44,13 @@@ extern int max_threads
  
  static struct workqueue_struct *khelper_wq;
  
+ #define CAP_BSET      (void *)1
+ #define CAP_PI                (void *)2
+ static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
+ static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
+ static DEFINE_SPINLOCK(umh_sysctl_lock);
  #ifdef CONFIG_MODULES
  
  /*
@@@ -132,6 -140,7 +140,7 @@@ EXPORT_SYMBOL(__request_module)
  static int ____call_usermodehelper(void *data)
  {
        struct subprocess_info *sub_info = data;
+       struct cred *new;
        int retval;
  
        spin_lock_irq(&current->sighand->siglock);
                        goto fail;
        }
  
+       retval = -ENOMEM;
+       new = prepare_kernel_cred(current);
+       if (!new)
+               goto fail;
+       spin_lock(&umh_sysctl_lock);
+       new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
+       new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
+                                            new->cap_inheritable);
+       spin_unlock(&umh_sysctl_lock);
+       commit_creds(new);
        retval = kernel_execve(sub_info->path,
                               (const char *const *)sub_info->argv,
                               (const char *const *)sub_info->envp);
@@@ -245,6 -267,7 +267,6 @@@ static void __call_usermodehelper(struc
        }
  }
  
 -#ifdef CONFIG_PM_SLEEP
  /*
   * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
   * (used for preventing user land processes from being created after the user
@@@ -300,15 -323,6 +322,15 @@@ void usermodehelper_enable(void
        usermodehelper_disabled = 0;
  }
  
 +/**
 + * usermodehelper_is_disabled - check if new helpers are allowed to be started
 + */
 +bool usermodehelper_is_disabled(void)
 +{
 +      return usermodehelper_disabled;
 +}
 +EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
 +
  static void helper_lock(void)
  {
        atomic_inc(&running_helpers);
@@@ -320,6 -334,12 +342,6 @@@ static void helper_unlock(void
        if (atomic_dec_and_test(&running_helpers))
                wake_up(&running_helpers_waitq);
  }
 -#else /* CONFIG_PM_SLEEP */
 -#define usermodehelper_disabled       0
 -
 -static inline void helper_lock(void) {}
 -static inline void helper_unlock(void) {}
 -#endif /* CONFIG_PM_SLEEP */
  
  /**
   * call_usermodehelper_setup - prepare to call a usermode helper
@@@ -420,6 -440,84 +442,84 @@@ unlock
  }
  EXPORT_SYMBOL(call_usermodehelper_exec);
  
+ static int proc_cap_handler(struct ctl_table *table, int write,
+                        void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+       struct ctl_table t;
+       unsigned long cap_array[_KERNEL_CAPABILITY_U32S];
+       kernel_cap_t new_cap;
+       int err, i;
+       if (write && (!capable(CAP_SETPCAP) ||
+                     !capable(CAP_SYS_MODULE)))
+               return -EPERM;
+       /*
+        * convert from the global kernel_cap_t to the ulong array to print to
+        * userspace if this is a read.
+        */
+       spin_lock(&umh_sysctl_lock);
+       for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)  {
+               if (table->data == CAP_BSET)
+                       cap_array[i] = usermodehelper_bset.cap[i];
+               else if (table->data == CAP_PI)
+                       cap_array[i] = usermodehelper_inheritable.cap[i];
+               else
+                       BUG();
+       }
+       spin_unlock(&umh_sysctl_lock);
+       t = *table;
+       t.data = &cap_array;
+       /*
+        * actually read or write and array of ulongs from userspace.  Remember
+        * these are least significant 32 bits first
+        */
+       err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
+       if (err < 0)
+               return err;
+       /*
+        * convert from the sysctl array of ulongs to the kernel_cap_t
+        * internal representation
+        */
+       for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)
+               new_cap.cap[i] = cap_array[i];
+       /*
+        * Drop everything not in the new_cap (but don't add things)
+        */
+       spin_lock(&umh_sysctl_lock);
+       if (write) {
+               if (table->data == CAP_BSET)
+                       usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap);
+               if (table->data == CAP_PI)
+                       usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap);
+       }
+       spin_unlock(&umh_sysctl_lock);
+       return 0;
+ }
+ struct ctl_table usermodehelper_table[] = {
+       {
+               .procname       = "bset",
+               .data           = CAP_BSET,
+               .maxlen         = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
+               .mode           = 0600,
+               .proc_handler   = proc_cap_handler,
+       },
+       {
+               .procname       = "inheritable",
+               .data           = CAP_PI,
+               .maxlen         = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
+               .mode           = 0600,
+               .proc_handler   = proc_cap_handler,
+       },
+       { }
+ };
  void __init usermodehelper_init(void)
  {
        khelper_wq = create_singlethread_workqueue("khelper");
diff --combined kernel/sysctl.c
@@@ -56,6 -56,7 +56,7 @@@
  #include <linux/kprobes.h>
  #include <linux/pipe_fs_i.h>
  #include <linux/oom.h>
+ #include <linux/kmod.h>
  
  #include <asm/uaccess.h>
  #include <asm/processor.h>
@@@ -616,6 -617,11 +617,11 @@@ static struct ctl_table kern_table[] = 
                .child          = random_table,
        },
        {
+               .procname       = "usermodehelper",
+               .mode           = 0555,
+               .child          = usermodehelper_table,
+       },
+       {
                .procname       = "overflowuid",
                .data           = &overflowuid,
                .maxlen         = sizeof(int),
                .data           = &watchdog_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
 -              .proc_handler   = proc_dowatchdog_enabled,
 +              .proc_handler   = proc_dowatchdog,
 +              .extra1         = &zero,
 +              .extra2         = &one,
        },
        {
                .procname       = "watchdog_thresh",
 -              .data           = &softlockup_thresh,
 +              .data           = &watchdog_thresh,
                .maxlen         = sizeof(int),
                .mode           = 0644,
 -              .proc_handler   = proc_dowatchdog_thresh,
 +              .proc_handler   = proc_dowatchdog,
                .extra1         = &neg_one,
                .extra2         = &sixty,
        },
                .data           = &watchdog_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
 -              .proc_handler   = proc_dowatchdog_enabled,
 +              .proc_handler   = proc_dowatchdog,
 +              .extra1         = &zero,
 +              .extra2         = &one,
        },
  #endif
  #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
@@@ -69,6 -69,18 +69,6 @@@ error
  EXPORT_SYMBOL_GPL(user_instantiate);
  
  /*
 - * dispose of the old data from an updated user defined key
 - */
 -static void user_update_rcu_disposal(struct rcu_head *rcu)
 -{
 -      struct user_key_payload *upayload;
 -
 -      upayload = container_of(rcu, struct user_key_payload, rcu);
 -
 -      kfree(upayload);
 -}
 -
 -/*
   * update a user defined key
   * - the key's semaphore is write-locked
   */
@@@ -102,7 -114,7 +102,7 @@@ int user_update(struct key *key, const 
                key->expiry = 0;
        }
  
 -      call_rcu(&zap->rcu, user_update_rcu_disposal);
 +      kfree_rcu(zap, rcu);
  
  error:
        return ret;
@@@ -133,7 -145,7 +133,7 @@@ void user_revoke(struct key *key
  
        if (upayload) {
                rcu_assign_pointer(key->payload.data, NULL);
 -              call_rcu(&upayload->rcu, user_update_rcu_disposal);
 +              kfree_rcu(upayload, rcu);
        }
  }
  
@@@ -157,8 -169,8 +157,8 @@@ EXPORT_SYMBOL_GPL(user_destroy)
  void user_describe(const struct key *key, struct seq_file *m)
  {
        seq_puts(m, key->description);
-       seq_printf(m, ": %u", key->datalen);
+       if (key_is_instantiated(key))
+               seq_printf(m, ": %u", key->datalen);
  }
  
  EXPORT_SYMBOL_GPL(user_describe);