namespace.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include "cgroup-internal.h"
  3. #include <linux/sched/task.h>
  4. #include <linux/slab.h>
  5. #include <linux/nsproxy.h>
  6. #include <linux/proc_ns.h>
  7. #include <linux/nstree.h>
  8. /* cgroup namespaces */
  9. static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
  10. {
  11. return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
  12. }
  13. static void dec_cgroup_namespaces(struct ucounts *ucounts)
  14. {
  15. dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
  16. }
  17. static struct cgroup_namespace *alloc_cgroup_ns(void)
  18. {
  19. struct cgroup_namespace *new_ns __free(kfree) = NULL;
  20. int ret;
  21. new_ns = kzalloc_obj(struct cgroup_namespace, GFP_KERNEL_ACCOUNT);
  22. if (!new_ns)
  23. return ERR_PTR(-ENOMEM);
  24. ret = ns_common_init(new_ns);
  25. if (ret)
  26. return ERR_PTR(ret);
  27. return no_free_ptr(new_ns);
  28. }
  29. void free_cgroup_ns(struct cgroup_namespace *ns)
  30. {
  31. ns_tree_remove(ns);
  32. put_css_set(ns->root_cset);
  33. dec_cgroup_namespaces(ns->ucounts);
  34. put_user_ns(ns->user_ns);
  35. ns_common_free(ns);
  36. /* Concurrent nstree traversal depends on a grace period. */
  37. kfree_rcu(ns, ns.ns_rcu);
  38. }
  39. EXPORT_SYMBOL(free_cgroup_ns);
  40. struct cgroup_namespace *copy_cgroup_ns(u64 flags,
  41. struct user_namespace *user_ns,
  42. struct cgroup_namespace *old_ns)
  43. {
  44. struct cgroup_namespace *new_ns;
  45. struct ucounts *ucounts;
  46. struct css_set *cset;
  47. BUG_ON(!old_ns);
  48. if (!(flags & CLONE_NEWCGROUP)) {
  49. get_cgroup_ns(old_ns);
  50. return old_ns;
  51. }
  52. /* Allow only sysadmin to create cgroup namespace. */
  53. if (!ns_capable(user_ns, CAP_SYS_ADMIN))
  54. return ERR_PTR(-EPERM);
  55. ucounts = inc_cgroup_namespaces(user_ns);
  56. if (!ucounts)
  57. return ERR_PTR(-ENOSPC);
  58. /* It is not safe to take cgroup_mutex here */
  59. spin_lock_irq(&css_set_lock);
  60. cset = task_css_set(current);
  61. get_css_set(cset);
  62. spin_unlock_irq(&css_set_lock);
  63. new_ns = alloc_cgroup_ns();
  64. if (IS_ERR(new_ns)) {
  65. put_css_set(cset);
  66. dec_cgroup_namespaces(ucounts);
  67. return new_ns;
  68. }
  69. new_ns->user_ns = get_user_ns(user_ns);
  70. new_ns->ucounts = ucounts;
  71. new_ns->root_cset = cset;
  72. ns_tree_add(new_ns);
  73. return new_ns;
  74. }
  75. static int cgroupns_install(struct nsset *nsset, struct ns_common *ns)
  76. {
  77. struct nsproxy *nsproxy = nsset->nsproxy;
  78. struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
  79. if (!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN) ||
  80. !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
  81. return -EPERM;
  82. /* Don't need to do anything if we are attaching to our own cgroupns. */
  83. if (cgroup_ns == nsproxy->cgroup_ns)
  84. return 0;
  85. get_cgroup_ns(cgroup_ns);
  86. put_cgroup_ns(nsproxy->cgroup_ns);
  87. nsproxy->cgroup_ns = cgroup_ns;
  88. return 0;
  89. }
  90. static struct ns_common *cgroupns_get(struct task_struct *task)
  91. {
  92. struct cgroup_namespace *ns = NULL;
  93. struct nsproxy *nsproxy;
  94. task_lock(task);
  95. nsproxy = task->nsproxy;
  96. if (nsproxy) {
  97. ns = nsproxy->cgroup_ns;
  98. get_cgroup_ns(ns);
  99. }
  100. task_unlock(task);
  101. return ns ? &ns->ns : NULL;
  102. }
  103. static void cgroupns_put(struct ns_common *ns)
  104. {
  105. put_cgroup_ns(to_cg_ns(ns));
  106. }
  107. static struct user_namespace *cgroupns_owner(struct ns_common *ns)
  108. {
  109. return to_cg_ns(ns)->user_ns;
  110. }
  111. const struct proc_ns_operations cgroupns_operations = {
  112. .name = "cgroup",
  113. .get = cgroupns_get,
  114. .put = cgroupns_put,
  115. .install = cgroupns_install,
  116. .owner = cgroupns_owner,
  117. };