]>
Commit | Line | Data |
---|---|---|
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> | |
10 | #include <linux/proc_fs.h> | |
11 | #include <linux/slab.h> | |
12 | #include <linux/nsproxy.h> | |
13 | ||
14 | struct ns_cgroup { | |
15 | struct cgroup_subsys_state css; | |
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 | ||
27 | int ns_cgroup_clone(struct task_struct *task, struct pid *pid) | |
28 | { | |
29 | char name[PROC_NUMBUF]; | |
30 | ||
31 | snprintf(name, PROC_NUMBUF, "%d", pid_vnr(pid)); | |
32 | return cgroup_clone(task, &ns_subsys, name); | |
33 | } | |
34 | ||
35 | /* | |
36 | * Rules: | |
37 | * 1. you can only enter a cgroup which is a descendant of your current | |
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 | */ | |
45 | static int ns_can_attach(struct cgroup_subsys *ss, struct cgroup *new_cgroup, | |
46 | struct task_struct *task, bool threadgroup) | |
47 | { | |
48 | if (current != task) { | |
49 | if (!capable(CAP_SYS_ADMIN)) | |
50 | return -EPERM; | |
51 | ||
52 | if (!cgroup_is_descendant(new_cgroup, current)) | |
53 | return -EPERM; | |
54 | } | |
55 | ||
56 | if (!cgroup_is_descendant(new_cgroup, task)) | |
57 | return -EPERM; | |
58 | ||
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 | ||
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); | |
86 | if (!cgroup_is_descendant(cgroup, current)) | |
87 | return ERR_PTR(-EPERM); | |
88 | ||
89 | ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL); | |
90 | if (!ns_cgroup) | |
91 | return ERR_PTR(-ENOMEM); | |
92 | return &ns_cgroup->css; | |
93 | } | |
94 | ||
95 | static void ns_destroy(struct cgroup_subsys *ss, | |
96 | struct cgroup *cgroup) | |
97 | { | |
98 | struct ns_cgroup *ns_cgroup; | |
99 | ||
100 | ns_cgroup = cgroup_to_ns(cgroup); | |
101 | kfree(ns_cgroup); | |
102 | } | |
103 | ||
104 | struct cgroup_subsys ns_subsys = { | |
105 | .name = "ns", | |
106 | .can_attach = ns_can_attach, | |
107 | .create = ns_create, | |
108 | .destroy = ns_destroy, | |
109 | .subsys_id = ns_subsys_id, | |
110 | }; |