vserver 1.9.5.x5
[linux-2.6.git] / kernel / capability.c
1 /*
2  * linux/kernel/capability.c
3  *
4  * Copyright (C) 1997  Andrew Main <zefram@fysh.org>
5  *
6  * Integrated into 2.1.97+,  Andrew G. Morgan <morgan@transmeta.com>
7  * 30 May 2002: Cleanup, Robert M. Love <rml@tech9.net>
8  */ 
9
10 #include <linux/mm.h>
11 #include <linux/module.h>
12 #include <linux/security.h>
13 #include <linux/syscalls.h>
14 #include <linux/vs_cvirt.h>
15
16 #include <asm/uaccess.h>
17
18 unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
19 kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
20
21 EXPORT_SYMBOL(securebits);
22 EXPORT_SYMBOL(cap_bset);
23
24 /*
25  * This global lock protects task->cap_* for all tasks including current.
26  * Locking rule: acquire this prior to tasklist_lock.
27  */
28 DEFINE_SPINLOCK(task_capability_lock);
29
30 /*
31  * For sys_getproccap() and sys_setproccap(), any of the three
32  * capability set pointers may be NULL -- indicating that that set is
33  * uninteresting and/or not to be changed.
34  */
35
36 /*
37  * sys_capget - get the capabilities of a given process.
38  */
39 asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
40 {
41      int ret = 0;
42      pid_t pid;
43      __u32 version;
44      task_t *target;
45      struct __user_cap_data_struct data;
46
47      if (get_user(version, &header->version))
48              return -EFAULT;
49
50      if (version != _LINUX_CAPABILITY_VERSION) {
51              if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
52                      return -EFAULT; 
53              return -EINVAL;
54      }
55
56      if (get_user(pid, &header->pid))
57              return -EFAULT;
58
59      if (pid < 0) 
60              return -EINVAL;
61
62      spin_lock(&task_capability_lock);
63      read_lock(&tasklist_lock); 
64
65      if (pid && pid != current->pid) {
66              target = find_task_by_pid(pid);
67              if (!target) {
68                   ret = -ESRCH;
69                   goto out;
70              }
71      } else
72              target = current;
73
74      ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted);
75
76 out:
77      read_unlock(&tasklist_lock); 
78      spin_unlock(&task_capability_lock);
79
80      if (!ret && copy_to_user(dataptr, &data, sizeof data))
81           return -EFAULT; 
82
83      return ret;
84 }
85
86 /*
87  * cap_set_pg - set capabilities for all processes in a given process
88  * group.  We call this holding task_capability_lock and tasklist_lock.
89  */
90 static inline int cap_set_pg(int pgrp, kernel_cap_t *effective,
91                               kernel_cap_t *inheritable,
92                               kernel_cap_t *permitted)
93 {
94         task_t *g, *target;
95         int ret = -EPERM;
96         int found = 0;
97
98         do_each_task_pid(pgrp, PIDTYPE_PGID, g) {
99                 target = g;
100                 while_each_thread(g, target) {
101                         if (!security_capset_check(target, effective,
102                                                         inheritable,
103                                                         permitted)) {
104                                 security_capset_set(target, effective,
105                                                         inheritable,
106                                                         permitted);
107                                 ret = 0;
108                         }
109                         found = 1;
110                 }
111         } while_each_task_pid(pgrp, PIDTYPE_PGID, g);
112
113         if (!found)
114              ret = 0;
115         return ret;
116 }
117
118 /*
119  * cap_set_all - set capabilities for all processes other than init
120  * and self.  We call this holding task_capability_lock and tasklist_lock.
121  */
122 static inline int cap_set_all(kernel_cap_t *effective,
123                                kernel_cap_t *inheritable,
124                                kernel_cap_t *permitted)
125 {
126      task_t *g, *target;
127      int ret = -EPERM;
128      int found = 0;
129
130      do_each_thread(g, target) {
131              if (target == current || target->pid == 1)
132                      continue;
133              found = 1;
134              if (security_capset_check(target, effective, inheritable,
135                                                 permitted))
136                      continue;
137              ret = 0;
138              security_capset_set(target, effective, inheritable, permitted);
139      } while_each_thread(g, target);
140
141      if (!found)
142              ret = 0;
143      return ret;
144 }
145
146 /*
147  * sys_capset - set capabilities for a given process, all processes, or all
148  * processes in a given process group.
149  *
150  * The restrictions on setting capabilities are specified as:
151  *
152  * [pid is for the 'target' task.  'current' is the calling task.]
153  *
154  * I: any raised capabilities must be a subset of the (old current) permitted
155  * P: any raised capabilities must be a subset of the (old current) permitted
156  * E: must be set to a subset of (new target) permitted
157  */
158 asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
159 {
160      kernel_cap_t inheritable, permitted, effective;
161      __u32 version;
162      task_t *target;
163      int ret;
164      pid_t pid;
165
166      if (get_user(version, &header->version))
167              return -EFAULT; 
168
169      if (version != _LINUX_CAPABILITY_VERSION) {
170              if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
171                      return -EFAULT; 
172              return -EINVAL;
173      }
174
175      if (get_user(pid, &header->pid))
176              return -EFAULT; 
177
178      if (pid && pid != current->pid && !capable(CAP_SETPCAP))
179              return -EPERM;
180
181      if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||
182          copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||
183          copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
184              return -EFAULT; 
185
186      spin_lock(&task_capability_lock);
187      read_lock(&tasklist_lock);
188
189      if (pid > 0 && pid != current->pid) {
190           target = find_task_by_pid(pid);
191           if (!target) {
192                ret = -ESRCH;
193                goto out;
194           }
195      } else
196                target = current;
197
198      ret = 0;
199
200      /* having verified that the proposed changes are legal,
201            we now put them into effect. */
202      if (pid < 0) {
203              if (pid == -1)  /* all procs other than current and init */
204                      ret = cap_set_all(&effective, &inheritable, &permitted);
205
206              else            /* all procs in process group */
207                      ret = cap_set_pg(-pid, &effective, &inheritable,
208                                                         &permitted);
209      } else {
210              ret = security_capset_check(target, &effective, &inheritable,
211                                                         &permitted);
212              if (!ret)
213                      security_capset_set(target, &effective, &inheritable,
214                                                         &permitted);
215      }
216
217 out:
218      read_unlock(&tasklist_lock);
219      spin_unlock(&task_capability_lock);
220
221      return ret;
222 }