File: /usr/src/linux/kernel/capability.c

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