]>
Commit | Line | Data |
---|---|---|
858d72ea SH |
1 | /* |
2 | * ns_cgroup.c - namespace cgroup subsystem | |
3 | * | |
4 | * Copyright 2006, 2007 IBM Corp | |
5 | */ | |
6 | ||
7 | #include <linux/module.h> | |
8 | #include <linux/cgroup.h> | |
9 | #include <linux/fs.h> | |
e885dcde | 10 | #include <linux/proc_fs.h> |
1aeb272c | 11 | #include <linux/slab.h> |
3ff31d0c | 12 | #include <linux/nsproxy.h> |
858d72ea SH |
13 | |
14 | struct ns_cgroup { | |
15 | struct cgroup_subsys_state css; | |
858d72ea SH |
16 | }; |
17 | ||
18 | struct cgroup_subsys ns_subsys; | |
19 | ||
20 | static inline struct ns_cgroup *cgroup_to_ns( | |
21 | struct cgroup *cgroup) | |
22 | { | |
23 | return container_of(cgroup_subsys_state(cgroup, ns_subsys_id), | |
24 | struct ns_cgroup, css); | |
25 | } | |
26 | ||
e885dcde | 27 | int ns_cgroup_clone(struct task_struct *task, struct pid *pid) |
858d72ea | 28 | { |
e885dcde SH |
29 | char name[PROC_NUMBUF]; |
30 | ||
31 | snprintf(name, PROC_NUMBUF, "%d", pid_vnr(pid)); | |
32 | return cgroup_clone(task, &ns_subsys, name); | |
858d72ea SH |
33 | } |
34 | ||
35 | /* | |
36 | * Rules: | |
313e924c | 37 | * 1. you can only enter a cgroup which is a descendant of your current |
858d72ea SH |
38 | * cgroup |
39 | * 2. you can only place another process into a cgroup if | |
40 | * a. you have CAP_SYS_ADMIN | |
41 | * b. your cgroup is an ancestor of task's destination cgroup | |
42 | * (hence either you are in the same cgroup as task, or in an | |
43 | * ancestor cgroup thereof) | |
44 | */ | |
be367d09 BB |
45 | static int ns_can_attach(struct cgroup_subsys *ss, struct cgroup *new_cgroup, |
46 | struct task_struct *task, bool threadgroup) | |
858d72ea | 47 | { |
858d72ea SH |
48 | if (current != task) { |
49 | if (!capable(CAP_SYS_ADMIN)) | |
50 | return -EPERM; | |
51 | ||
313e924c | 52 | if (!cgroup_is_descendant(new_cgroup, current)) |
858d72ea SH |
53 | return -EPERM; |
54 | } | |
55 | ||
313e924c | 56 | if (!cgroup_is_descendant(new_cgroup, task)) |
858d72ea SH |
57 | return -EPERM; |
58 | ||
be367d09 BB |
59 | if (threadgroup) { |
60 | struct task_struct *c; | |
61 | rcu_read_lock(); | |
62 | list_for_each_entry_rcu(c, &task->thread_group, thread_group) { | |
63 | if (!cgroup_is_descendant(new_cgroup, c)) { | |
64 | rcu_read_unlock(); | |
65 | return -EPERM; | |
66 | } | |
67 | } | |
68 | rcu_read_unlock(); | |
69 | } | |
70 | ||
858d72ea SH |
71 | return 0; |
72 | } | |
73 | ||
74 | /* | |
75 | * Rules: you can only create a cgroup if | |
76 | * 1. you are capable(CAP_SYS_ADMIN) | |
77 | * 2. the target cgroup is a descendant of your own cgroup | |
78 | */ | |
79 | static struct cgroup_subsys_state *ns_create(struct cgroup_subsys *ss, | |
80 | struct cgroup *cgroup) | |
81 | { | |
82 | struct ns_cgroup *ns_cgroup; | |
83 | ||
84 | if (!capable(CAP_SYS_ADMIN)) | |
85 | return ERR_PTR(-EPERM); | |
313e924c | 86 | if (!cgroup_is_descendant(cgroup, current)) |
858d72ea | 87 | return ERR_PTR(-EPERM); |
45531757 DL |
88 | if (test_bit(CGRP_CLONE_CHILDREN, &cgroup->flags)) { |
89 | printk("ns_cgroup can't be created with parent " | |
90 | "'clone_children' set.\n"); | |
91 | return ERR_PTR(-EINVAL); | |
92 | } | |
93 | ||
94 | printk_once("ns_cgroup deprecated: consider using the " | |
95 | "'clone_children' flag without the ns_cgroup.\n"); | |
858d72ea SH |
96 | |
97 | ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL); | |
98 | if (!ns_cgroup) | |
99 | return ERR_PTR(-ENOMEM); | |
858d72ea SH |
100 | return &ns_cgroup->css; |
101 | } | |
102 | ||
103 | static void ns_destroy(struct cgroup_subsys *ss, | |
104 | struct cgroup *cgroup) | |
105 | { | |
106 | struct ns_cgroup *ns_cgroup; | |
107 | ||
108 | ns_cgroup = cgroup_to_ns(cgroup); | |
109 | kfree(ns_cgroup); | |
110 | } | |
111 | ||
112 | struct cgroup_subsys ns_subsys = { | |
113 | .name = "ns", | |
114 | .can_attach = ns_can_attach, | |
115 | .create = ns_create, | |
116 | .destroy = ns_destroy, | |
117 | .subsys_id = ns_subsys_id, | |
118 | }; |