Blame view

kernel/capability.c 6.12 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   * linux/kernel/capability.c
   *
   * Copyright (C) 1997  Andrew Main <zefram@fysh.org>
   *
72c2d5823   Andrew Morgan   V3 file capabilit...
6
   * Integrated into 2.1.97+,  Andrew G. Morgan <morgan@kernel.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   * 30 May 2002:	Cleanup, Robert M. Love <rml@tech9.net>
314f70fd9   Daniel Walker   whitespace fixes:...
8
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9

c59ede7b7   Randy.Dunlap   [PATCH] move capa...
10
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/security.h>
  #include <linux/syscalls.h>
b460cbc58   Serge E. Hallyn   pid namespaces: d...
15
  #include <linux/pid_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
25
26
27
  /*
   * This lock protects task->cap_* for all tasks including current.
   * Locking rule: acquire this prior to tasklist_lock.
   */
  static DEFINE_SPINLOCK(task_capability_lock);
  
  /*
   * For sys_getproccap() and sys_setproccap(), any of the three
   * capability set pointers may be NULL -- indicating that that set is
   * uninteresting and/or not to be changed.
   */
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
28
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
   * sys_capget - get the capabilities of a given process.
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
30
31
32
33
34
35
   * @header: pointer to struct that contains capability version and
   *	target pid data
   * @dataptr: pointer to struct that contains the effective, permitted,
   *	and inheritable capabilities that are returned
   *
   * Returns 0 on success and < 0 on error.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
   */
  asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
  {
314f70fd9   Daniel Walker   whitespace fixes:...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  	int ret = 0;
  	pid_t pid;
  	__u32 version;
  	struct task_struct *target;
  	struct __user_cap_data_struct data;
  
  	if (get_user(version, &header->version))
  		return -EFAULT;
  
  	if (version != _LINUX_CAPABILITY_VERSION) {
  		if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
  			return -EFAULT;
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53

314f70fd9   Daniel Walker   whitespace fixes:...
54
55
  	if (get_user(pid, &header->pid))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

314f70fd9   Daniel Walker   whitespace fixes:...
57
58
  	if (pid < 0)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

314f70fd9   Daniel Walker   whitespace fixes:...
60
61
  	spin_lock(&task_capability_lock);
  	read_lock(&tasklist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

b488893a3   Pavel Emelyanov   pid namespaces: c...
63
  	if (pid && pid != task_pid_vnr(current)) {
228ebcbe6   Pavel Emelyanov   Uninline find_tas...
64
  		target = find_task_by_vpid(pid);
314f70fd9   Daniel Walker   whitespace fixes:...
65
66
67
68
69
70
  		if (!target) {
  			ret = -ESRCH;
  			goto out;
  		}
  	} else
  		target = current;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71

314f70fd9   Daniel Walker   whitespace fixes:...
72
  	ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  
  out:
314f70fd9   Daniel Walker   whitespace fixes:...
75
76
  	read_unlock(&tasklist_lock);
  	spin_unlock(&task_capability_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

314f70fd9   Daniel Walker   whitespace fixes:...
78
79
  	if (!ret && copy_to_user(dataptr, &data, sizeof data))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

314f70fd9   Daniel Walker   whitespace fixes:...
81
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
87
  }
  
  /*
   * cap_set_pg - set capabilities for all processes in a given process
   * group.  We call this holding task_capability_lock and tasklist_lock.
   */
41487c65b   Eric W. Biederman   [PATCH] pid: repl...
88
  static inline int cap_set_pg(int pgrp_nr, kernel_cap_t *effective,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
  			      kernel_cap_t *inheritable,
  			      kernel_cap_t *permitted)
  {
36c8b5868   Ingo Molnar   [PATCH] sched: cl...
92
  	struct task_struct *g, *target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
  	int ret = -EPERM;
  	int found = 0;
41487c65b   Eric W. Biederman   [PATCH] pid: repl...
95
  	struct pid *pgrp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96

8990571eb   Pavel Emelyanov   Uninline find_pid...
97
  	pgrp = find_vpid(pgrp_nr);
41487c65b   Eric W. Biederman   [PATCH] pid: repl...
98
  	do_each_pid_task(pgrp, PIDTYPE_PGID, g) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
105
106
107
108
109
110
  		target = g;
  		while_each_thread(g, target) {
  			if (!security_capset_check(target, effective,
  							inheritable,
  							permitted)) {
  				security_capset_set(target, effective,
  							inheritable,
  							permitted);
  				ret = 0;
  			}
  			found = 1;
  		}
41487c65b   Eric W. Biederman   [PATCH] pid: repl...
111
  	} while_each_pid_task(pgrp, PIDTYPE_PGID, g);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  
  	if (!found)
314f70fd9   Daniel Walker   whitespace fixes:...
114
  		ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
122
123
124
125
  	return ret;
  }
  
  /*
   * cap_set_all - set capabilities for all processes other than init
   * and self.  We call this holding task_capability_lock and tasklist_lock.
   */
  static inline int cap_set_all(kernel_cap_t *effective,
  			       kernel_cap_t *inheritable,
  			       kernel_cap_t *permitted)
  {
36c8b5868   Ingo Molnar   [PATCH] sched: cl...
126
       struct task_struct *g, *target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
       int ret = -EPERM;
       int found = 0;
  
       do_each_thread(g, target) {
b460cbc58   Serge E. Hallyn   pid namespaces: d...
131
               if (target == current || is_container_init(target->group_leader))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
139
140
141
142
143
144
                       continue;
               found = 1;
  	     if (security_capset_check(target, effective, inheritable,
  						permitted))
  		     continue;
  	     ret = 0;
  	     security_capset_set(target, effective, inheritable, permitted);
       } while_each_thread(g, target);
  
       if (!found)
  	     ret = 0;
       return ret;
  }
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
145
146
147
148
149
150
151
152
  /**
   * sys_capset - set capabilities for a process or a group of processes
   * @header: pointer to struct that contains capability version and
   *	target pid data
   * @data: pointer to struct that contains the effective, permitted,
   *	and inheritable capabilities
   *
   * Set capabilities for a given process, all processes, or all
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
   * processes in a given process group.
   *
   * The restrictions on setting capabilities are specified as:
   *
   * [pid is for the 'target' task.  'current' is the calling task.]
   *
   * I: any raised capabilities must be a subset of the (old current) permitted
   * P: any raised capabilities must be a subset of the (old current) permitted
   * E: must be set to a subset of (new target) permitted
207a7ba8d   Randy Dunlap   [PATCH] kernel/ca...
162
163
   *
   * Returns 0 on success and < 0 on error.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
   */
  asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
  {
314f70fd9   Daniel Walker   whitespace fixes:...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
  	kernel_cap_t inheritable, permitted, effective;
  	__u32 version;
  	struct task_struct *target;
  	int ret;
  	pid_t pid;
  
  	if (get_user(version, &header->version))
  		return -EFAULT;
  
  	if (version != _LINUX_CAPABILITY_VERSION) {
  		if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
  			return -EFAULT;
  		return -EINVAL;
  	}
  
  	if (get_user(pid, &header->pid))
  		return -EFAULT;
b488893a3   Pavel Emelyanov   pid namespaces: c...
184
  	if (pid && pid != task_pid_vnr(current) && !capable(CAP_SETPCAP))
314f70fd9   Daniel Walker   whitespace fixes:...
185
186
187
188
189
190
191
192
193
  		return -EPERM;
  
  	if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||
  	    copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||
  	    copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
  		return -EFAULT;
  
  	spin_lock(&task_capability_lock);
  	read_lock(&tasklist_lock);
b488893a3   Pavel Emelyanov   pid namespaces: c...
194
  	if (pid > 0 && pid != task_pid_vnr(current)) {
228ebcbe6   Pavel Emelyanov   Uninline find_tas...
195
  		target = find_task_by_vpid(pid);
314f70fd9   Daniel Walker   whitespace fixes:...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  		if (!target) {
  			ret = -ESRCH;
  			goto out;
  		}
  	} else
  		target = current;
  
  	ret = 0;
  
  	/* having verified that the proposed changes are legal,
  	   we now put them into effect. */
  	if (pid < 0) {
  		if (pid == -1)	/* all procs other than current and init */
  			ret = cap_set_all(&effective, &inheritable, &permitted);
  
  		else		/* all procs in process group */
  			ret = cap_set_pg(-pid, &effective, &inheritable,
  					 &permitted);
  	} else {
  		ret = security_capset_check(target, &effective, &inheritable,
  					    &permitted);
  		if (!ret)
  			security_capset_set(target, &effective, &inheritable,
  					    &permitted);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
  
  out:
314f70fd9   Daniel Walker   whitespace fixes:...
223
224
  	read_unlock(&tasklist_lock);
  	spin_unlock(&task_capability_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225

314f70fd9   Daniel Walker   whitespace fixes:...
226
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  }
12b5989be   Chris Wright   [PATCH] refactor ...
228
229
230
231
232
233
234
235
236
  
  int __capable(struct task_struct *t, int cap)
  {
  	if (security_capable(t, cap) == 0) {
  		t->flags |= PF_SUPERPRIV;
  		return 1;
  	}
  	return 0;
  }
12b5989be   Chris Wright   [PATCH] refactor ...
237
238
239
240
241
242
  
  int capable(int cap)
  {
  	return __capable(current, cap);
  }
  EXPORT_SYMBOL(capable);