]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Dec 2012 18:55:28 +0000 (10:55 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Dec 2012 18:55:28 +0000 (10:55 -0800)
Pull (again) user namespace infrastructure changes from Eric Biederman:
 "Those bugs, those darn embarrasing bugs just want don't want to get
  fixed.

  Linus I just updated my mirror of your kernel.org tree and it appears
  you successfully pulled everything except the last 4 commits that fix
  those embarrasing bugs.

  When you get a chance can you please repull my branch"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  userns: Fix typo in description of the limitation of userns_install
  userns: Add a more complete capability subset test to commit_creds
  userns: Require CAP_SYS_ADMIN for most uses of setns.
  Fix cap_capable to only allow owners in the parent user namespace to have caps.

1  2 
kernel/cred.c

diff --combined kernel/cred.c
index 8888afb846e95f36f5fa4ab27b82685785083bd8,709d521903f62ab8811d206386c332b1ad6a5460..e0573a43c7df62b1b37df319bd74ff377603ccf5
  
  static struct kmem_cache *cred_jar;
  
 -/*
 - * The common credentials for the initial task's thread group
 - */
 -#ifdef CONFIG_KEYS
 -static struct thread_group_cred init_tgcred = {
 -      .usage  = ATOMIC_INIT(2),
 -      .tgid   = 0,
 -      .lock   = __SPIN_LOCK_UNLOCKED(init_cred.tgcred.lock),
 -};
 -#endif
 -
  /*
   * The initial credentials for the initial task
   */
@@@ -54,6 -65,9 +54,6 @@@ struct cred init_cred = 
        .user                   = INIT_USER,
        .user_ns                = &init_user_ns,
        .group_info             = &init_groups,
 -#ifdef CONFIG_KEYS
 -      .tgcred                 = &init_tgcred,
 -#endif
  };
  
  static inline void set_cred_subscribers(struct cred *cred, int n)
@@@ -81,6 -95,36 +81,6 @@@ static inline void alter_cred_subscribe
  #endif
  }
  
 -/*
 - * Dispose of the shared task group credentials
 - */
 -#ifdef CONFIG_KEYS
 -static void release_tgcred_rcu(struct rcu_head *rcu)
 -{
 -      struct thread_group_cred *tgcred =
 -              container_of(rcu, struct thread_group_cred, rcu);
 -
 -      BUG_ON(atomic_read(&tgcred->usage) != 0);
 -
 -      key_put(tgcred->session_keyring);
 -      key_put(tgcred->process_keyring);
 -      kfree(tgcred);
 -}
 -#endif
 -
 -/*
 - * Release a set of thread group credentials.
 - */
 -static void release_tgcred(struct cred *cred)
 -{
 -#ifdef CONFIG_KEYS
 -      struct thread_group_cred *tgcred = cred->tgcred;
 -
 -      if (atomic_dec_and_test(&tgcred->usage))
 -              call_rcu(&tgcred->rcu, release_tgcred_rcu);
 -#endif
 -}
 -
  /*
   * The RCU callback to actually dispose of a set of credentials
   */
@@@ -106,10 -150,9 +106,10 @@@ static void put_cred_rcu(struct rcu_hea
  #endif
  
        security_cred_free(cred);
 +      key_put(cred->session_keyring);
 +      key_put(cred->process_keyring);
        key_put(cred->thread_keyring);
        key_put(cred->request_key_auth);
 -      release_tgcred(cred);
        if (cred->group_info)
                put_group_info(cred->group_info);
        free_uid(cred->user);
@@@ -203,6 -246,15 +203,6 @@@ struct cred *cred_alloc_blank(void
        if (!new)
                return NULL;
  
 -#ifdef CONFIG_KEYS
 -      new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL);
 -      if (!new->tgcred) {
 -              kmem_cache_free(cred_jar, new);
 -              return NULL;
 -      }
 -      atomic_set(&new->tgcred->usage, 1);
 -#endif
 -
        atomic_set(&new->usage, 1);
  #ifdef CONFIG_DEBUG_CREDENTIALS
        new->magic = CRED_MAGIC;
@@@ -256,10 -308,9 +256,10 @@@ struct cred *prepare_creds(void
        get_user_ns(new->user_ns);
  
  #ifdef CONFIG_KEYS
 +      key_get(new->session_keyring);
 +      key_get(new->process_keyring);
        key_get(new->thread_keyring);
        key_get(new->request_key_auth);
 -      atomic_inc(&new->tgcred->usage);
  #endif
  
  #ifdef CONFIG_SECURITY
@@@ -283,20 -334,39 +283,20 @@@ EXPORT_SYMBOL(prepare_creds)
   */
  struct cred *prepare_exec_creds(void)
  {
 -      struct thread_group_cred *tgcred = NULL;
        struct cred *new;
  
 -#ifdef CONFIG_KEYS
 -      tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
 -      if (!tgcred)
 -              return NULL;
 -#endif
 -
        new = prepare_creds();
 -      if (!new) {
 -              kfree(tgcred);
 +      if (!new)
                return new;
 -      }
  
  #ifdef CONFIG_KEYS
        /* newly exec'd tasks don't get a thread keyring */
        key_put(new->thread_keyring);
        new->thread_keyring = NULL;
  
 -      /* create a new per-thread-group creds for all this set of threads to
 -       * share */
 -      memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
 -
 -      atomic_set(&tgcred->usage, 1);
 -      spin_lock_init(&tgcred->lock);
 -
        /* inherit the session keyring; new process keyring */
 -      key_get(tgcred->session_keyring);
 -      tgcred->process_keyring = NULL;
 -
 -      release_tgcred(new);
 -      new->tgcred = tgcred;
 +      key_put(new->process_keyring);
 +      new->process_keyring = NULL;
  #endif
  
        return new;
   */
  int copy_creds(struct task_struct *p, unsigned long clone_flags)
  {
 -#ifdef CONFIG_KEYS
 -      struct thread_group_cred *tgcred;
 -#endif
        struct cred *new;
        int ret;
  
                        install_thread_keyring_to_cred(new);
        }
  
 -      /* we share the process and session keyrings between all the threads in
 -       * a process - this is slightly icky as we violate COW credentials a
 -       * bit */
 +      /* The process keyring is only shared between the threads in a process;
 +       * anything outside of those threads doesn't inherit.
 +       */
        if (!(clone_flags & CLONE_THREAD)) {
 -              tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
 -              if (!tgcred) {
 -                      ret = -ENOMEM;
 -                      goto error_put;
 -              }
 -              atomic_set(&tgcred->usage, 1);
 -              spin_lock_init(&tgcred->lock);
 -              tgcred->process_keyring = NULL;
 -              tgcred->session_keyring = key_get(new->tgcred->session_keyring);
 -
 -              release_tgcred(new);
 -              new->tgcred = tgcred;
 +              key_put(new->process_keyring);
 +              new->process_keyring = NULL;
        }
  #endif
  
@@@ -372,6 -455,31 +372,31 @@@ error_put
        return ret;
  }
  
+ static bool cred_cap_issubset(const struct cred *set, const struct cred *subset)
+ {
+       const struct user_namespace *set_ns = set->user_ns;
+       const struct user_namespace *subset_ns = subset->user_ns;
+       /* If the two credentials are in the same user namespace see if
+        * the capabilities of subset are a subset of set.
+        */
+       if (set_ns == subset_ns)
+               return cap_issubset(subset->cap_permitted, set->cap_permitted);
+       /* The credentials are in a different user namespaces
+        * therefore one is a subset of the other only if a set is an
+        * ancestor of subset and set->euid is owner of subset or one
+        * of subsets ancestors.
+        */
+       for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) {
+               if ((set_ns == subset_ns->parent)  &&
+                   uid_eq(subset_ns->owner, set->euid))
+                       return true;
+       }
+       return false;
+ }
  /**
   * commit_creds - Install new credentials upon the current task
   * @new: The credentials to be assigned
@@@ -410,7 -518,7 +435,7 @@@ int commit_creds(struct cred *new
            !gid_eq(old->egid, new->egid) ||
            !uid_eq(old->fsuid, new->fsuid) ||
            !gid_eq(old->fsgid, new->fsgid) ||
-           !cap_issubset(new->cap_permitted, old->cap_permitted)) {
+           !cred_cap_issubset(old, new)) {
                if (task->mm)
                        set_dumpable(task->mm, suid_dumpable);
                task->pdeath_signal = 0;
@@@ -560,6 -668,9 +585,6 @@@ void __init cred_init(void
   */
  struct cred *prepare_kernel_cred(struct task_struct *daemon)
  {
 -#ifdef CONFIG_KEYS
 -      struct thread_group_cred *tgcred;
 -#endif
        const struct cred *old;
        struct cred *new;
  
        if (!new)
                return NULL;
  
 -#ifdef CONFIG_KEYS
 -      tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
 -      if (!tgcred) {
 -              kmem_cache_free(cred_jar, new);
 -              return NULL;
 -      }
 -#endif
 -
        kdebug("prepare_kernel_cred() alloc %p", new);
  
        if (daemon)
        get_group_info(new->group_info);
  
  #ifdef CONFIG_KEYS
 -      atomic_set(&tgcred->usage, 1);
 -      spin_lock_init(&tgcred->lock);
 -      tgcred->process_keyring = NULL;
 -      tgcred->session_keyring = NULL;
 -      new->tgcred = tgcred;
 -      new->request_key_auth = NULL;
 +      new->session_keyring = NULL;
 +      new->process_keyring = NULL;
        new->thread_keyring = NULL;
 +      new->request_key_auth = NULL;
        new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
  #endif