LCOV - code coverage report
Current view: top level - kernel/cgroup - namespace.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 12 80 15.0 %
Date: 2021-04-22 12:43:58 Functions: 2 9 22.2 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include "cgroup-internal.h"
       3             : 
       4             : #include <linux/sched/task.h>
       5             : #include <linux/slab.h>
       6             : #include <linux/nsproxy.h>
       7             : #include <linux/proc_ns.h>
       8             : 
       9             : 
      10             : /* cgroup namespaces */
      11             : 
      12           0 : static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
      13             : {
      14           0 :         return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
      15             : }
      16             : 
      17           0 : static void dec_cgroup_namespaces(struct ucounts *ucounts)
      18             : {
      19           0 :         dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
      20             : }
      21             : 
      22           0 : static struct cgroup_namespace *alloc_cgroup_ns(void)
      23             : {
      24           0 :         struct cgroup_namespace *new_ns;
      25           0 :         int ret;
      26             : 
      27           0 :         new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL);
      28           0 :         if (!new_ns)
      29           0 :                 return ERR_PTR(-ENOMEM);
      30           0 :         ret = ns_alloc_inum(&new_ns->ns);
      31           0 :         if (ret) {
      32           0 :                 kfree(new_ns);
      33           0 :                 return ERR_PTR(ret);
      34             :         }
      35           0 :         refcount_set(&new_ns->ns.count, 1);
      36           0 :         new_ns->ns.ops = &cgroupns_operations;
      37           0 :         return new_ns;
      38             : }
      39             : 
      40           0 : void free_cgroup_ns(struct cgroup_namespace *ns)
      41             : {
      42           0 :         put_css_set(ns->root_cset);
      43           0 :         dec_cgroup_namespaces(ns->ucounts);
      44           0 :         put_user_ns(ns->user_ns);
      45           0 :         ns_free_inum(&ns->ns);
      46           0 :         kfree(ns);
      47           0 : }
      48             : EXPORT_SYMBOL(free_cgroup_ns);
      49             : 
      50          50 : struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
      51             :                                         struct user_namespace *user_ns,
      52             :                                         struct cgroup_namespace *old_ns)
      53             : {
      54          50 :         struct cgroup_namespace *new_ns;
      55          50 :         struct ucounts *ucounts;
      56          50 :         struct css_set *cset;
      57             : 
      58          50 :         BUG_ON(!old_ns);
      59             : 
      60          50 :         if (!(flags & CLONE_NEWCGROUP)) {
      61          50 :                 get_cgroup_ns(old_ns);
      62          50 :                 return old_ns;
      63             :         }
      64             : 
      65             :         /* Allow only sysadmin to create cgroup namespace. */
      66           0 :         if (!ns_capable(user_ns, CAP_SYS_ADMIN))
      67          50 :                 return ERR_PTR(-EPERM);
      68             : 
      69           0 :         ucounts = inc_cgroup_namespaces(user_ns);
      70           0 :         if (!ucounts)
      71          50 :                 return ERR_PTR(-ENOSPC);
      72             : 
      73             :         /* It is not safe to take cgroup_mutex here */
      74           0 :         spin_lock_irq(&css_set_lock);
      75           0 :         cset = task_css_set(current);
      76           0 :         get_css_set(cset);
      77           0 :         spin_unlock_irq(&css_set_lock);
      78             : 
      79           0 :         new_ns = alloc_cgroup_ns();
      80           0 :         if (IS_ERR(new_ns)) {
      81           0 :                 put_css_set(cset);
      82           0 :                 dec_cgroup_namespaces(ucounts);
      83           0 :                 return new_ns;
      84             :         }
      85             : 
      86           0 :         new_ns->user_ns = get_user_ns(user_ns);
      87           0 :         new_ns->ucounts = ucounts;
      88           0 :         new_ns->root_cset = cset;
      89             : 
      90           0 :         return new_ns;
      91             : }
      92             : 
      93           0 : static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
      94             : {
      95           0 :         return container_of(ns, struct cgroup_namespace, ns);
      96             : }
      97             : 
      98           0 : static int cgroupns_install(struct nsset *nsset, struct ns_common *ns)
      99             : {
     100           0 :         struct nsproxy *nsproxy = nsset->nsproxy;
     101           0 :         struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
     102             : 
     103           0 :         if (!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN) ||
     104           0 :             !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
     105           0 :                 return -EPERM;
     106             : 
     107             :         /* Don't need to do anything if we are attaching to our own cgroupns. */
     108           0 :         if (cgroup_ns == nsproxy->cgroup_ns)
     109             :                 return 0;
     110             : 
     111           0 :         get_cgroup_ns(cgroup_ns);
     112           0 :         put_cgroup_ns(nsproxy->cgroup_ns);
     113           0 :         nsproxy->cgroup_ns = cgroup_ns;
     114             : 
     115           0 :         return 0;
     116             : }
     117             : 
     118           0 : static struct ns_common *cgroupns_get(struct task_struct *task)
     119             : {
     120           0 :         struct cgroup_namespace *ns = NULL;
     121           0 :         struct nsproxy *nsproxy;
     122             : 
     123           0 :         task_lock(task);
     124           0 :         nsproxy = task->nsproxy;
     125           0 :         if (nsproxy) {
     126           0 :                 ns = nsproxy->cgroup_ns;
     127           0 :                 get_cgroup_ns(ns);
     128             :         }
     129           0 :         task_unlock(task);
     130             : 
     131           0 :         return ns ? &ns->ns : NULL;
     132             : }
     133             : 
     134           0 : static void cgroupns_put(struct ns_common *ns)
     135             : {
     136           0 :         put_cgroup_ns(to_cg_ns(ns));
     137           0 : }
     138             : 
     139           0 : static struct user_namespace *cgroupns_owner(struct ns_common *ns)
     140             : {
     141           0 :         return to_cg_ns(ns)->user_ns;
     142             : }
     143             : 
     144             : const struct proc_ns_operations cgroupns_operations = {
     145             :         .name           = "cgroup",
     146             :         .type           = CLONE_NEWCGROUP,
     147             :         .get            = cgroupns_get,
     148             :         .put            = cgroupns_put,
     149             :         .install        = cgroupns_install,
     150             :         .owner          = cgroupns_owner,
     151             : };
     152             : 
     153           1 : static __init int cgroup_namespaces_init(void)
     154             : {
     155           1 :         return 0;
     156             : }
     157             : subsys_initcall(cgroup_namespaces_init);

Generated by: LCOV version 1.14