Merge branch 'nsfs-ioctls' into HEAD
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 23 Sep 2016 01:00:36 +0000 (20:00 -0500)
committerEric W. Biederman <ebiederm@xmission.com>
Fri, 23 Sep 2016 01:00:36 +0000 (20:00 -0500)
From: Andrey Vagin <avagin@openvz.org>

Each namespace has an owning user namespace and now there is not way
to discover these relationships.

Pid and user namepaces are hierarchical. There is no way to discover
parent-child relationships too.

Why we may want to know relationships between namespaces?

One use would be visualization, in order to understand the running
system.  Another would be to answer the question: what capability does
process X have to perform operations on a resource governed by namespace
Y?

One more use-case (which usually called abnormal) is checkpoint/restart.
In CRIU we are going to dump and restore nested namespaces.

There [1] was a discussion about which interface to choose to determing
relationships between namespaces.

Eric suggested to add two ioctl-s [2]:
> Grumble, Grumble.  I think this may actually a case for creating ioctls
> for these two cases.  Now that random nsfs file descriptors are bind
> mountable the original reason for using proc files is not as pressing.
>
> One ioctl for the user namespace that owns a file descriptor.
> One ioctl for the parent namespace of a namespace file descriptor.

Here is an implementaions of these ioctl-s.

$ man man7/namespaces.7
...
Since  Linux  4.X,  the  following  ioctl(2)  calls are supported for
namespace file descriptors.  The correct syntax is:

      fd = ioctl(ns_fd, ioctl_type);

where ioctl_type is one of the following:

NS_GET_USERNS
      Returns a file descriptor that refers to an owning user namesā€
      pace.

NS_GET_PARENT
      Returns  a  file descriptor that refers to a parent namespace.
      This ioctl(2) can be used for pid  and  user  namespaces.  For
      user namespaces, NS_GET_PARENT and NS_GET_USERNS have the same
      meaning.

In addition to generic ioctl(2) errors, the following  specific  ones
can occur:

EINVAL NS_GET_PARENT was called for a nonhierarchical namespace.

EPERM  The  requested  namespace  is outside of the current namespace
      scope.

[1] https://lkml.org/lkml/2016/7/6/158
[2] https://lkml.org/lkml/2016/7/9/101

Changes for v2:
* don't return ENOENT for init_user_ns and init_pid_ns. There is nothing
  outside of the init namespace, so we can return EPERM in this case too.
  > The fewer special cases the easier the code is to get
  > correct, and the easier it is to read. // Eric

Changes for v3:
* rename ns->get_owner() to ns->owner(). get_* usually means that it
  grabs a reference.

Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com>
Cc: "W. Trevor King" <wking@tremily.us>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Serge Hallyn <serge.hallyn@canonical.com>
1  2 
fs/namespace.c
include/linux/user_namespace.h
ipc/namespace.c
kernel/cgroup.c
kernel/pid_namespace.c
kernel/user_namespace.c
kernel/utsname.c
net/core/net_namespace.c

diff --combined fs/namespace.c
@@@ -2719,20 -2719,9 +2719,20 @@@ dput_out
        return retval;
  }
  
 +static struct ucounts *inc_mnt_namespaces(struct user_namespace *ns)
 +{
 +      return inc_ucount(ns, current_euid(), UCOUNT_MNT_NAMESPACES);
 +}
 +
 +static void dec_mnt_namespaces(struct ucounts *ucounts)
 +{
 +      dec_ucount(ucounts, UCOUNT_MNT_NAMESPACES);
 +}
 +
  static void free_mnt_ns(struct mnt_namespace *ns)
  {
        ns_free_inum(&ns->ns);
 +      dec_mnt_namespaces(ns->ucounts);
        put_user_ns(ns->user_ns);
        kfree(ns);
  }
@@@ -2749,22 -2738,14 +2749,22 @@@ static atomic64_t mnt_ns_seq = ATOMIC64
  static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
  {
        struct mnt_namespace *new_ns;
 +      struct ucounts *ucounts;
        int ret;
  
 +      ucounts = inc_mnt_namespaces(user_ns);
 +      if (!ucounts)
 +              return ERR_PTR(-ENOSPC);
 +
        new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
 -      if (!new_ns)
 +      if (!new_ns) {
 +              dec_mnt_namespaces(ucounts);
                return ERR_PTR(-ENOMEM);
 +      }
        ret = ns_alloc_inum(&new_ns->ns);
        if (ret) {
                kfree(new_ns);
 +              dec_mnt_namespaces(ucounts);
                return ERR_PTR(ret);
        }
        new_ns->ns.ops = &mntns_operations;
        init_waitqueue_head(&new_ns->poll);
        new_ns->event = 0;
        new_ns->user_ns = get_user_ns(user_ns);
 +      new_ns->ucounts = ucounts;
        return new_ns;
  }
  
@@@ -3368,10 -3348,16 +3368,16 @@@ static int mntns_install(struct nsprox
        return 0;
  }
  
+ static struct user_namespace *mntns_owner(struct ns_common *ns)
+ {
+       return to_mnt_ns(ns)->user_ns;
+ }
  const struct proc_ns_operations mntns_operations = {
        .name           = "mnt",
        .type           = CLONE_NEWNS,
        .get            = mntns_get,
        .put            = mntns_put,
        .install        = mntns_install,
+       .owner          = mntns_owner,
  };
@@@ -22,19 -22,6 +22,19 @@@ struct uid_gid_map {        /* 64 bytes -- 1 c
  
  #define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED
  
 +struct ucounts;
 +
 +enum ucount_type {
 +      UCOUNT_USER_NAMESPACES,
 +      UCOUNT_PID_NAMESPACES,
 +      UCOUNT_UTS_NAMESPACES,
 +      UCOUNT_IPC_NAMESPACES,
 +      UCOUNT_NET_NAMESPACES,
 +      UCOUNT_MNT_NAMESPACES,
 +      UCOUNT_CGROUP_NAMESPACES,
 +      UCOUNT_COUNTS,
 +};
 +
  struct user_namespace {
        struct uid_gid_map      uid_map;
        struct uid_gid_map      gid_map;
        struct key              *persistent_keyring_register;
        struct rw_semaphore     persistent_keyring_register_sem;
  #endif
 +      struct work_struct      work;
 +#ifdef CONFIG_SYSCTL
 +      struct ctl_table_set    set;
 +      struct ctl_table_header *sysctls;
 +#endif
 +      struct ucounts          *ucounts;
 +      int ucount_max[UCOUNT_COUNTS];
 +};
 +
 +struct ucounts {
 +      struct hlist_node node;
 +      struct user_namespace *ns;
 +      kuid_t uid;
 +      atomic_t count;
 +      atomic_t ucount[UCOUNT_COUNTS];
  };
  
  extern struct user_namespace init_user_ns;
  
 +bool setup_userns_sysctls(struct user_namespace *ns);
 +void retire_userns_sysctls(struct user_namespace *ns);
 +struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
 +void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
 +
  #ifdef CONFIG_USER_NS
  
  static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
  
  extern int create_user_ns(struct cred *new);
  extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred);
 -extern void free_user_ns(struct user_namespace *ns);
 +extern void __put_user_ns(struct user_namespace *ns);
  
  static inline void put_user_ns(struct user_namespace *ns)
  {
        if (ns && atomic_dec_and_test(&ns->count))
 -              free_user_ns(ns);
 +              __put_user_ns(ns);
  }
  
  struct seq_operations;
@@@ -106,6 -73,8 +106,8 @@@ extern ssize_t proc_setgroups_write(str
  extern int proc_setgroups_show(struct seq_file *m, void *v);
  extern bool userns_may_setgroups(const struct user_namespace *ns);
  extern bool current_in_userns(const struct user_namespace *target_ns);
+ struct ns_common *ns_get_owner(struct ns_common *ns);
  #else
  
  static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@@ -139,6 -108,11 +141,11 @@@ static inline bool current_in_userns(co
  {
        return true;
  }
+ static inline struct ns_common *ns_get_owner(struct ns_common *ns)
+ {
+       return ERR_PTR(-EPERM);
+ }
  #endif
  
  #endif /* _LINUX_USER_H */
diff --combined ipc/namespace.c
  
  #include "util.h"
  
 +static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns)
 +{
 +      return inc_ucount(ns, current_euid(), UCOUNT_IPC_NAMESPACES);
 +}
 +
 +static void dec_ipc_namespaces(struct ucounts *ucounts)
 +{
 +      dec_ucount(ucounts, UCOUNT_IPC_NAMESPACES);
 +}
 +
  static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
                                           struct ipc_namespace *old_ns)
  {
        struct ipc_namespace *ns;
 +      struct ucounts *ucounts;
        int err;
  
 +      err = -ENOSPC;
 +      ucounts = inc_ipc_namespaces(user_ns);
 +      if (!ucounts)
 +              goto fail;
 +
 +      err = -ENOMEM;
        ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
        if (ns == NULL)
 -              return ERR_PTR(-ENOMEM);
 +              goto fail_dec;
  
        err = ns_alloc_inum(&ns->ns);
 -      if (err) {
 -              kfree(ns);
 -              return ERR_PTR(err);
 -      }
 +      if (err)
 +              goto fail_free;
        ns->ns.ops = &ipcns_operations;
  
        atomic_set(&ns->count, 1);
        ns->user_ns = get_user_ns(user_ns);
 +      ns->ucounts = ucounts;
  
        err = mq_init_ns(ns);
 -      if (err) {
 -              put_user_ns(ns->user_ns);
 -              ns_free_inum(&ns->ns);
 -              kfree(ns);
 -              return ERR_PTR(err);
 -      }
 +      if (err)
 +              goto fail_put;
  
        sem_init_ns(ns);
        msg_init_ns(ns);
        shm_init_ns(ns);
  
        return ns;
 +
 +fail_put:
 +      put_user_ns(ns->user_ns);
 +      ns_free_inum(&ns->ns);
 +fail_free:
 +      kfree(ns);
 +fail_dec:
 +      dec_ipc_namespaces(ucounts);
 +fail:
 +      return ERR_PTR(err);
  }
  
  struct ipc_namespace *copy_ipcs(unsigned long flags,
@@@ -118,7 -96,6 +118,7 @@@ static void free_ipc_ns(struct ipc_name
        msg_exit_ns(ns);
        shm_exit_ns(ns);
  
 +      dec_ipc_namespaces(ns->ucounts);
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
        kfree(ns);
@@@ -188,10 -165,16 +188,16 @@@ static int ipcns_install(struct nsprox
        return 0;
  }
  
+ static struct user_namespace *ipcns_owner(struct ns_common *ns)
+ {
+       return to_ipc_ns(ns)->user_ns;
+ }
  const struct proc_ns_operations ipcns_operations = {
        .name           = "ipc",
        .type           = CLONE_NEWIPC,
        .get            = ipcns_get,
        .put            = ipcns_put,
        .install        = ipcns_install,
+       .owner          = ipcns_owner,
  };
diff --combined kernel/cgroup.c
@@@ -6295,16 -6295,6 +6295,16 @@@ void cgroup_sk_free(struct sock_cgroup_
  
  /* cgroup namespaces */
  
 +static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
 +{
 +      return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
 +}
 +
 +static void dec_cgroup_namespaces(struct ucounts *ucounts)
 +{
 +      dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
 +}
 +
  static struct cgroup_namespace *alloc_cgroup_ns(void)
  {
        struct cgroup_namespace *new_ns;
  void free_cgroup_ns(struct cgroup_namespace *ns)
  {
        put_css_set(ns->root_cset);
 +      dec_cgroup_namespaces(ns->ucounts);
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
        kfree(ns);
@@@ -6338,7 -6327,6 +6338,7 @@@ struct cgroup_namespace *copy_cgroup_ns
                                        struct cgroup_namespace *old_ns)
  {
        struct cgroup_namespace *new_ns;
 +      struct ucounts *ucounts;
        struct css_set *cset;
  
        BUG_ON(!old_ns);
        if (!ns_capable(user_ns, CAP_SYS_ADMIN))
                return ERR_PTR(-EPERM);
  
 +      ucounts = inc_cgroup_namespaces(user_ns);
 +      if (!ucounts)
 +              return ERR_PTR(-ENOSPC);
 +
        /* It is not safe to take cgroup_mutex here */
        spin_lock_irq(&css_set_lock);
        cset = task_css_set(current);
        new_ns = alloc_cgroup_ns();
        if (IS_ERR(new_ns)) {
                put_css_set(cset);
 +              dec_cgroup_namespaces(ucounts);
                return new_ns;
        }
  
        new_ns->user_ns = get_user_ns(user_ns);
 +      new_ns->ucounts = ucounts;
        new_ns->root_cset = cset;
  
        return new_ns;
@@@ -6421,12 -6403,18 +6421,18 @@@ static void cgroupns_put(struct ns_comm
        put_cgroup_ns(to_cg_ns(ns));
  }
  
+ static struct user_namespace *cgroupns_owner(struct ns_common *ns)
+ {
+       return to_cg_ns(ns)->user_ns;
+ }
  const struct proc_ns_operations cgroupns_operations = {
        .name           = "cgroup",
        .type           = CLONE_NEWCGROUP,
        .get            = cgroupns_get,
        .put            = cgroupns_put,
        .install        = cgroupns_install,
+       .owner          = cgroupns_owner,
  };
  
  static __init int cgroup_namespaces_init(void)
diff --combined kernel/pid_namespace.c
@@@ -79,36 -79,23 +79,36 @@@ static void proc_cleanup_work(struct wo
  /* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
  #define MAX_PID_NS_LEVEL 32
  
 +static struct ucounts *inc_pid_namespaces(struct user_namespace *ns)
 +{
 +      return inc_ucount(ns, current_euid(), UCOUNT_PID_NAMESPACES);
 +}
 +
 +static void dec_pid_namespaces(struct ucounts *ucounts)
 +{
 +      dec_ucount(ucounts, UCOUNT_PID_NAMESPACES);
 +}
 +
  static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns,
        struct pid_namespace *parent_pid_ns)
  {
        struct pid_namespace *ns;
        unsigned int level = parent_pid_ns->level + 1;
 +      struct ucounts *ucounts;
        int i;
        int err;
  
 -      if (level > MAX_PID_NS_LEVEL) {
 -              err = -EINVAL;
 +      err = -ENOSPC;
 +      if (level > MAX_PID_NS_LEVEL)
 +              goto out;
 +      ucounts = inc_pid_namespaces(user_ns);
 +      if (!ucounts)
                goto out;
 -      }
  
        err = -ENOMEM;
        ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL);
        if (ns == NULL)
 -              goto out;
 +              goto out_dec;
  
        ns->pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (!ns->pidmap[0].page)
        ns->level = level;
        ns->parent = get_pid_ns(parent_pid_ns);
        ns->user_ns = get_user_ns(user_ns);
 +      ns->ucounts = ucounts;
        ns->nr_hashed = PIDNS_HASH_ADDING;
        INIT_WORK(&ns->proc_work, proc_cleanup_work);
  
@@@ -143,8 -129,6 +143,8 @@@ out_free_map
        kfree(ns->pidmap[0].page);
  out_free:
        kmem_cache_free(pid_ns_cachep, ns);
 +out_dec:
 +      dec_pid_namespaces(ucounts);
  out:
        return ERR_PTR(err);
  }
@@@ -162,7 -146,6 +162,7 @@@ static void destroy_pid_namespace(struc
        ns_free_inum(&ns->ns);
        for (i = 0; i < PIDMAP_ENTRIES; i++)
                kfree(ns->pidmap[i].page);
 +      dec_pid_namespaces(ns->ucounts);
        put_user_ns(ns->user_ns);
        call_rcu(&ns->rcu, delayed_free_pidns);
  }
@@@ -405,12 -388,37 +405,37 @@@ static int pidns_install(struct nsprox
        return 0;
  }
  
+ static struct ns_common *pidns_get_parent(struct ns_common *ns)
+ {
+       struct pid_namespace *active = task_active_pid_ns(current);
+       struct pid_namespace *pid_ns, *p;
+       /* See if the parent is in the current namespace */
+       pid_ns = p = to_pid_ns(ns)->parent;
+       for (;;) {
+               if (!p)
+                       return ERR_PTR(-EPERM);
+               if (p == active)
+                       break;
+               p = p->parent;
+       }
+       return &get_pid_ns(pid_ns)->ns;
+ }
+ static struct user_namespace *pidns_owner(struct ns_common *ns)
+ {
+       return to_pid_ns(ns)->user_ns;
+ }
  const struct proc_ns_operations pidns_operations = {
        .name           = "pid",
        .type           = CLONE_NEWPID,
        .get            = pidns_get,
        .put            = pidns_put,
        .install        = pidns_install,
+       .owner          = pidns_owner,
+       .get_parent     = pidns_get_parent,
  };
  
  static __init int pid_namespaces_init(void)
diff --combined kernel/user_namespace.c
@@@ -29,17 -29,6 +29,17 @@@ static DEFINE_MUTEX(userns_state_mutex)
  static bool new_idmap_permitted(const struct file *file,
                                struct user_namespace *ns, int cap_setid,
                                struct uid_gid_map *map);
 +static void free_user_ns(struct work_struct *work);
 +
 +static struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid)
 +{
 +      return inc_ucount(ns, uid, UCOUNT_USER_NAMESPACES);
 +}
 +
 +static void dec_user_namespaces(struct ucounts *ucounts)
 +{
 +      return dec_ucount(ucounts, UCOUNT_USER_NAMESPACES);
 +}
  
  static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
  {
@@@ -73,16 -62,10 +73,16 @@@ int create_user_ns(struct cred *new
        struct user_namespace *ns, *parent_ns = new->user_ns;
        kuid_t owner = new->euid;
        kgid_t group = new->egid;
 -      int ret;
 +      struct ucounts *ucounts;
 +      int ret, i;
  
 +      ret = -ENOSPC;
        if (parent_ns->level > 32)
 -              return -EUSERS;
 +              goto fail;
 +
 +      ucounts = inc_user_namespaces(parent_ns, owner);
 +      if (!ucounts)
 +              goto fail;
  
        /*
         * Verify that we can not violate the policy of which files
         * by verifing that the root directory is at the root of the
         * mount namespace which allows all files to be accessed.
         */
 +      ret = -EPERM;
        if (current_chrooted())
 -              return -EPERM;
 +              goto fail_dec;
  
        /* The creator needs a mapping in the parent user namespace
         * or else we won't be able to reasonably tell userspace who
         * created a user_namespace.
         */
 +      ret = -EPERM;
        if (!kuid_has_mapping(parent_ns, owner) ||
            !kgid_has_mapping(parent_ns, group))
 -              return -EPERM;
 +              goto fail_dec;
  
 +      ret = -ENOMEM;
        ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL);
        if (!ns)
 -              return -ENOMEM;
 +              goto fail_dec;
  
        ret = ns_alloc_inum(&ns->ns);
 -      if (ret) {
 -              kmem_cache_free(user_ns_cachep, ns);
 -              return ret;
 -      }
 +      if (ret)
 +              goto fail_free;
        ns->ns.ops = &userns_operations;
  
        atomic_set(&ns->count, 1);
        ns->level = parent_ns->level + 1;
        ns->owner = owner;
        ns->group = group;
 +      INIT_WORK(&ns->work, free_user_ns);
 +      for (i = 0; i < UCOUNT_COUNTS; i++) {
 +              ns->ucount_max[i] = INT_MAX;
 +      }
 +      ns->ucounts = ucounts;
  
        /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
        mutex_lock(&userns_state_mutex);
        ns->flags = parent_ns->flags;
        mutex_unlock(&userns_state_mutex);
  
 -      set_cred_user_ns(new, ns);
 -
  #ifdef CONFIG_PERSISTENT_KEYRINGS
        init_rwsem(&ns->persistent_keyring_register_sem);
  #endif
 +      ret = -ENOMEM;
 +      if (!setup_userns_sysctls(ns))
 +              goto fail_keyring;
 +
 +      set_cred_user_ns(new, ns);
        return 0;
 +fail_keyring:
 +#ifdef CONFIG_PERSISTENT_KEYRINGS
 +      key_put(ns->persistent_keyring_register);
 +#endif
 +      ns_free_inum(&ns->ns);
 +fail_free:
 +      kmem_cache_free(user_ns_cachep, ns);
 +fail_dec:
 +      dec_user_namespaces(ucounts);
 +fail:
 +      return ret;
  }
  
  int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
        return err;
  }
  
 -void free_user_ns(struct user_namespace *ns)
 +static void free_user_ns(struct work_struct *work)
  {
 -      struct user_namespace *parent;
 +      struct user_namespace *parent, *ns =
 +              container_of(work, struct user_namespace, work);
  
        do {
 +              struct ucounts *ucounts = ns->ucounts;
                parent = ns->parent;
 +              retire_userns_sysctls(ns);
  #ifdef CONFIG_PERSISTENT_KEYRINGS
                key_put(ns->persistent_keyring_register);
  #endif
                ns_free_inum(&ns->ns);
                kmem_cache_free(user_ns_cachep, ns);
 +              dec_user_namespaces(ucounts);
                ns = parent;
        } while (atomic_dec_and_test(&parent->count));
  }
 -EXPORT_SYMBOL(free_user_ns);
 +
 +void __put_user_ns(struct user_namespace *ns)
 +{
 +      schedule_work(&ns->work);
 +}
 +EXPORT_SYMBOL(__put_user_ns);
  
  static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count)
  {
@@@ -1050,12 -1004,37 +1050,37 @@@ static int userns_install(struct nsprox
        return commit_creds(cred);
  }
  
+ struct ns_common *ns_get_owner(struct ns_common *ns)
+ {
+       struct user_namespace *my_user_ns = current_user_ns();
+       struct user_namespace *owner, *p;
+       /* See if the owner is in the current user namespace */
+       owner = p = ns->ops->owner(ns);
+       for (;;) {
+               if (!p)
+                       return ERR_PTR(-EPERM);
+               if (p == my_user_ns)
+                       break;
+               p = p->parent;
+       }
+       return &get_user_ns(owner)->ns;
+ }
+ static struct user_namespace *userns_owner(struct ns_common *ns)
+ {
+       return to_user_ns(ns)->parent;
+ }
  const struct proc_ns_operations userns_operations = {
        .name           = "user",
        .type           = CLONE_NEWUSER,
        .get            = userns_get,
        .put            = userns_put,
        .install        = userns_install,
+       .owner          = userns_owner,
+       .get_parent     = ns_get_owner,
  };
  
  static __init int user_namespaces_init(void)
diff --combined kernel/utsname.c
  #include <linux/user_namespace.h>
  #include <linux/proc_ns.h>
  
 +static struct ucounts *inc_uts_namespaces(struct user_namespace *ns)
 +{
 +      return inc_ucount(ns, current_euid(), UCOUNT_UTS_NAMESPACES);
 +}
 +
 +static void dec_uts_namespaces(struct ucounts *ucounts)
 +{
 +      dec_ucount(ucounts, UCOUNT_UTS_NAMESPACES);
 +}
 +
  static struct uts_namespace *create_uts_ns(void)
  {
        struct uts_namespace *uts_ns;
@@@ -46,24 -36,18 +46,24 @@@ static struct uts_namespace *clone_uts_
                                          struct uts_namespace *old_ns)
  {
        struct uts_namespace *ns;
 +      struct ucounts *ucounts;
        int err;
  
 +      err = -ENOSPC;
 +      ucounts = inc_uts_namespaces(user_ns);
 +      if (!ucounts)
 +              goto fail;
 +
 +      err = -ENOMEM;
        ns = create_uts_ns();
        if (!ns)
 -              return ERR_PTR(-ENOMEM);
 +              goto fail_dec;
  
        err = ns_alloc_inum(&ns->ns);
 -      if (err) {
 -              kfree(ns);
 -              return ERR_PTR(err);
 -      }
 +      if (err)
 +              goto fail_free;
  
 +      ns->ucounts = ucounts;
        ns->ns.ops = &utsns_operations;
  
        down_read(&uts_sem);
        ns->user_ns = get_user_ns(user_ns);
        up_read(&uts_sem);
        return ns;
 +
 +fail_free:
 +      kfree(ns);
 +fail_dec:
 +      dec_uts_namespaces(ucounts);
 +fail:
 +      return ERR_PTR(err);
  }
  
  /*
@@@ -108,7 -85,6 +108,7 @@@ void free_uts_ns(struct kref *kref
        struct uts_namespace *ns;
  
        ns = container_of(kref, struct uts_namespace, kref);
 +      dec_uts_namespaces(ns->ucounts);
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
        kfree(ns);
@@@ -154,10 -130,16 +154,16 @@@ static int utsns_install(struct nsprox
        return 0;
  }
  
+ static struct user_namespace *utsns_owner(struct ns_common *ns)
+ {
+       return to_uts_ns(ns)->user_ns;
+ }
  const struct proc_ns_operations utsns_operations = {
        .name           = "uts",
        .type           = CLONE_NEWUTS,
        .get            = utsns_get,
        .put            = utsns_put,
        .install        = utsns_install,
+       .owner          = utsns_owner,
  };
diff --combined net/core/net_namespace.c
@@@ -266,16 -266,6 +266,16 @@@ struct net *get_net_ns_by_id(struct ne
        return peer;
  }
  
 +static struct ucounts *inc_net_namespaces(struct user_namespace *ns)
 +{
 +      return inc_ucount(ns, current_euid(), UCOUNT_NET_NAMESPACES);
 +}
 +
 +static void dec_net_namespaces(struct ucounts *ucounts)
 +{
 +      dec_ucount(ucounts, UCOUNT_NET_NAMESPACES);
 +}
 +
  /*
   * setup_net runs the initializers for the network namespace object.
   */
@@@ -361,27 -351,19 +361,27 @@@ void net_drop_ns(void *p
  struct net *copy_net_ns(unsigned long flags,
                        struct user_namespace *user_ns, struct net *old_net)
  {
 +      struct ucounts *ucounts;
        struct net *net;
        int rv;
  
        if (!(flags & CLONE_NEWNET))
                return get_net(old_net);
  
 +      ucounts = inc_net_namespaces(user_ns);
 +      if (!ucounts)
 +              return ERR_PTR(-ENOSPC);
 +
        net = net_alloc();
 -      if (!net)
 +      if (!net) {
 +              dec_net_namespaces(ucounts);
                return ERR_PTR(-ENOMEM);
 +      }
  
        get_user_ns(user_ns);
  
        mutex_lock(&net_mutex);
 +      net->ucounts = ucounts;
        rv = setup_net(net, user_ns);
        if (rv == 0) {
                rtnl_lock();
        }
        mutex_unlock(&net_mutex);
        if (rv < 0) {
 +              dec_net_namespaces(ucounts);
                put_user_ns(user_ns);
                net_drop_ns(net);
                return ERR_PTR(rv);
@@@ -463,7 -444,6 +463,7 @@@ static void cleanup_net(struct work_str
        /* Finally it is safe to free my network namespace structure */
        list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
                list_del_init(&net->exit_list);
 +              dec_net_namespaces(net->ucounts);
                put_user_ns(net->user_ns);
                net_drop_ns(net);
        }
@@@ -1016,11 -996,17 +1016,17 @@@ static int netns_install(struct nsprox
        return 0;
  }
  
+ static struct user_namespace *netns_owner(struct ns_common *ns)
+ {
+       return to_net_ns(ns)->user_ns;
+ }
  const struct proc_ns_operations netns_operations = {
        .name           = "net",
        .type           = CLONE_NEWNET,
        .get            = netns_get,
        .put            = netns_put,
        .install        = netns_install,
+       .owner          = netns_owner,
  };
  #endif