]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.apparmor/apparmor-rlimits.diff
Add ignored *.diff files of the xen patches
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.apparmor / apparmor-rlimits.diff
1 From: John Johansen <jjohansen@suse.de>
2 Subject: AppArmor: per profile controls for system rlimits
3
4 Provide contol of rlimits on a per profile basis. Each profile provides
5 a per limit contol and corresponding hard limit value, such that when a
6 profile becomes attached to a task it sets the tasks limits to be <= to
7 the profiles specified limits. Note: the profile limit value will not
8 raise a tasks limit if it is already less than the profile mandates.
9
10 In addition to setting a tasks limits, the ability to set limits on
11 a confined task are controlled. AppArmor only controls the raising
12 of a tasks limits Tasks with CAP_SYS_RESOURCE can have their hard limits
13 raised up to the value specified by the profile. AppArmor does not
14 prevent a task for lowering its hard limits, nor does it provide
15 additional control on soft limits.
16
17 AppArmor only controls the limits specified in a profile so that
18 any limit not specified is free to be modified subject to standard
19 linux limitations.
20
21 ---
22 security/apparmor/apparmor.h | 23 ++++++
23 security/apparmor/apparmorfs.c | 2
24 security/apparmor/lsm.c | 16 ++++
25 security/apparmor/main.c | 132 +++++++++++++++++++++++++++++++----
26 security/apparmor/module_interface.c | 56 ++++++++++++++
27 5 files changed, 215 insertions(+), 14 deletions(-)
28
29 --- a/security/apparmor/apparmor.h
30 +++ b/security/apparmor/apparmor.h
31 @@ -16,6 +16,7 @@
32 #include <linux/fs.h>
33 #include <linux/binfmts.h>
34 #include <linux/rcupdate.h>
35 +#include <linux/resource.h>
36 #include <linux/socket.h>
37 #include <net/sock.h>
38
39 @@ -139,6 +140,18 @@ extern unsigned int apparmor_path_max;
40
41 #define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
42
43 +/* struct aa_rlimit - rlimits settings for the profile
44 + * @mask: which hard limits to set
45 + * @limits: rlimit values that override task limits
46 + *
47 + * AppArmor rlimits are used to set confined task rlimits. Only the
48 + * limits specified in @mask will be controlled by apparmor.
49 + */
50 +struct aa_rlimit {
51 + unsigned int mask;
52 + struct rlimit limits[RLIM_NLIMITS];
53 +};
54 +
55 struct aa_profile;
56
57 /* struct aa_namespace - namespace for a set of profiles
58 @@ -173,6 +186,8 @@ struct aa_namespace {
59 * @audit_caps: caps that are to be audited
60 * @quiet_caps: caps that should not be audited
61 * @capabilities: capabilities granted by the process
62 + * @rlimits: rlimits for the profile
63 + * @task_count: how many tasks the profile is attached to
64 * @count: reference count of the profile
65 * @task_contexts: list of tasks confined by profile
66 * @lock: lock for the task_contexts list
67 @@ -210,6 +225,9 @@ struct aa_profile {
68 kernel_cap_t audit_caps;
69 kernel_cap_t quiet_caps;
70
71 + struct aa_rlimit rlimits;
72 + unsigned int task_count;
73 +
74 struct kref count;
75 struct list_head task_contexts;
76 spinlock_t lock;
77 @@ -261,6 +279,7 @@ struct aa_audit {
78 const char *name2;
79 const char *name3;
80 int request_mask, denied_mask, audit_mask;
81 + int rlimit;
82 struct iattr *iattr;
83 pid_t task, parent;
84 int family, type, protocol;
85 @@ -328,6 +347,10 @@ extern int aa_may_ptrace(struct aa_task_
86 extern int aa_net_perm(struct aa_profile *profile, char *operation,
87 int family, int type, int protocol);
88 extern int aa_revalidate_sk(struct sock *sk, char *operation);
89 +extern int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
90 + struct rlimit *new_rlim);
91 +extern void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile);
92 +
93
94 /* lsm.c */
95 extern int apparmor_initialized;
96 --- a/security/apparmor/apparmorfs.c
97 +++ b/security/apparmor/apparmorfs.c
98 @@ -106,7 +106,7 @@ static ssize_t aa_features_read(struct f
99 {
100 const char *features = "file=3.0 capability=2.0 network=1.0 "
101 "change_hat=1.5 change_profile=1.0 "
102 - "aanamespaces=1.0";
103 + "aanamespaces=1.0 rlimit=1.0";
104
105 return simple_read_from_buffer(buf, size, ppos, features,
106 strlen(features));
107 --- a/security/apparmor/lsm.c
108 +++ b/security/apparmor/lsm.c
109 @@ -883,6 +883,21 @@ static int apparmor_setprocattr(struct t
110 return error;
111 }
112
113 +static int apparmor_task_setrlimit(unsigned int resource,
114 + struct rlimit *new_rlim)
115 +{
116 + struct aa_profile *profile;
117 + int error = 0;
118 +
119 + profile = aa_get_profile(current);
120 + if (profile) {
121 + error = aa_task_setrlimit(profile, resource, new_rlim);
122 + }
123 + aa_put_profile(profile);
124 +
125 + return error;
126 +}
127 +
128 struct security_operations apparmor_ops = {
129 .ptrace = apparmor_ptrace,
130 .capget = cap_capget,
131 @@ -926,6 +941,7 @@ struct security_operations apparmor_ops
132 .task_free_security = apparmor_task_free_security,
133 .task_post_setuid = cap_task_post_setuid,
134 .task_reparent_to_init = cap_task_reparent_to_init,
135 + .task_setrlimit = apparmor_task_setrlimit,
136
137 .getprocattr = apparmor_getprocattr,
138 .setprocattr = apparmor_setprocattr,
139 --- a/security/apparmor/main.c
140 +++ b/security/apparmor/main.c
141 @@ -177,6 +177,9 @@ static int aa_audit_base(struct aa_profi
142 if (sa->request_mask)
143 audit_log_format(ab, " fsuid=%d", current->fsuid);
144
145 + if (sa->rlimit)
146 + audit_log_format(ab, " rlimit=%d", sa->rlimit - 1);
147 +
148 if (sa->iattr) {
149 struct iattr *iattr = sa->iattr;
150
151 @@ -872,6 +875,79 @@ int aa_revalidate_sk(struct sock *sk, ch
152
153 return error;
154 }
155 +/**
156 + * aa_task_setrlimit - test permission to set an rlimit
157 + * @profile - profile confining the task
158 + * @resource - the resource being set
159 + * @new_rlim - the new resource limit
160 + *
161 + * Control raising the processes hard limit.
162 + */
163 +int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
164 + struct rlimit *new_rlim)
165 +{
166 + struct aa_audit sa;
167 + int error = 0;
168 +
169 + memset(&sa, 0, sizeof(sa));
170 + sa.operation = "setrlimit";
171 + sa.gfp_mask = GFP_KERNEL;
172 + sa.rlimit = resource + 1;
173 +
174 + if (profile->rlimits.mask & (1 << resource) &&
175 + new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max) {
176 + sa.error_code = -EACCES;
177 +
178 + error = aa_audit(profile, &sa);
179 + }
180 +
181 + return error;
182 +}
183 +
184 +static int aa_rlimit_nproc(struct aa_profile *profile) {
185 + if (profile && (profile->rlimits.mask & (1 << RLIMIT_NPROC)) &&
186 + profile->task_count >= profile->rlimits.limits[RLIMIT_NPROC].rlim_max)
187 + return -EAGAIN;
188 + return 0;
189 +}
190 +
191 +void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile)
192 +{
193 + int i, mask;
194 +
195 + if (!profile)
196 + return;
197 +
198 + if (!profile->rlimits.mask)
199 + return;
200 +
201 + task_lock(task->group_leader);
202 + mask = 1;
203 + for (i = 0; i < RLIM_NLIMITS; i++, mask <<= 1) {
204 + struct rlimit new_rlim, *old_rlim;
205 +
206 + /* check to see if NPROC which is per profile and handled
207 + * in clone/exec or whether this is a limit to be set
208 + * can't set cpu limit either right now
209 + */
210 + if (i == RLIMIT_NPROC || i == RLIMIT_CPU)
211 + continue;
212 +
213 + old_rlim = task->signal->rlim + i;
214 + new_rlim = *old_rlim;
215 +
216 + if (mask & profile->rlimits.mask &&
217 + profile->rlimits.limits[i].rlim_max < new_rlim.rlim_max) {
218 + new_rlim.rlim_max = profile->rlimits.limits[i].rlim_max;
219 + /* soft limit should not exceed hard limit */
220 + if (new_rlim.rlim_cur > new_rlim.rlim_max)
221 + new_rlim.rlim_cur = new_rlim.rlim_max;
222 + }
223 +
224 + *old_rlim = new_rlim;
225 + }
226 + task_unlock(task->group_leader);
227 +}
228
229 /*******************************
230 * Global task related functions
231 @@ -885,6 +961,7 @@ int aa_revalidate_sk(struct sock *sk, ch
232 */
233 int aa_clone(struct task_struct *child)
234 {
235 + struct aa_audit sa;
236 struct aa_task_context *cxt, *child_cxt;
237 struct aa_profile *profile;
238
239 @@ -894,6 +971,11 @@ int aa_clone(struct task_struct *child)
240 if (!child_cxt)
241 return -ENOMEM;
242
243 + memset(&sa, 0, sizeof(sa));
244 + sa.operation = "clone";
245 + sa.task = child->pid;
246 + sa.gfp_mask = GFP_KERNEL;
247 +
248 repeat:
249 profile = aa_get_profile(current);
250 if (profile) {
251 @@ -910,18 +992,22 @@ repeat:
252 goto repeat;
253 }
254
255 + if (aa_rlimit_nproc(profile)) {
256 + sa.info = "rlimit nproc limit exceeded";
257 + unlock_profile(profile);
258 + aa_audit_reject(profile, &sa);
259 + aa_put_profile(profile);
260 + return -EAGAIN;
261 + }
262 +
263 /* No need to grab the child's task lock here. */
264 aa_change_task_context(child, child_cxt, profile,
265 cxt->cookie, cxt->previous_profile);
266 +
267 unlock_profile(profile);
268
269 if (APPARMOR_COMPLAIN(child_cxt) &&
270 profile == profile->ns->null_complain_profile) {
271 - struct aa_audit sa;
272 - memset(&sa, 0, sizeof(sa));
273 - sa.operation = "clone";
274 - sa.gfp_mask = GFP_KERNEL;
275 - sa.task = child->pid;
276 aa_audit_hint(profile, &sa);
277 }
278 aa_put_profile(profile);
279 @@ -1156,6 +1242,10 @@ repeat:
280 sa.task = current->parent->pid;
281 aa_audit_reject(profile, &sa);
282 }
283 + if (PTR_ERR(old_profile) == -EAGAIN) {
284 + sa.info = "rlimit nproc limit exceeded";
285 + aa_audit_reject(profile, &sa);
286 + }
287 new_profile = old_profile;
288 goto cleanup;
289 }
290 @@ -1303,6 +1393,12 @@ static int do_change_profile(struct aa_p
291 goto out;
292 }
293
294 + if ((error = aa_rlimit_nproc(new_profile))) {
295 + sa->info = "rlimit nproc limit exceeded";
296 + aa_audit_reject(cxt->profile, sa);
297 + goto out;
298 + }
299 +
300 if (new_profile == ns->null_complain_profile)
301 aa_audit_hint(cxt->profile, sa);
302
303 @@ -1481,17 +1577,18 @@ struct aa_profile *__aa_replace_profile(
304
305 cxt = lock_task_and_profiles(task, profile);
306 if (unlikely(profile && profile->isstale)) {
307 - task_unlock(task);
308 - unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
309 - aa_free_task_context(new_cxt);
310 - return ERR_PTR(-ESTALE);
311 + old_profile = ERR_PTR(-ESTALE);
312 + goto error;
313 }
314
315 if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, profile)) {
316 - task_unlock(task);
317 - unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
318 - aa_free_task_context(new_cxt);
319 - return ERR_PTR(-EPERM);
320 + old_profile = ERR_PTR(-EPERM);
321 + goto error;
322 + }
323 +
324 + if (aa_rlimit_nproc(profile)) {
325 + old_profile = ERR_PTR(-EAGAIN);
326 + goto error;
327 }
328
329 if (cxt)
330 @@ -1499,8 +1596,15 @@ struct aa_profile *__aa_replace_profile(
331 aa_change_task_context(task, new_cxt, profile, 0, NULL);
332
333 task_unlock(task);
334 + aa_set_rlimits(task, profile);
335 unlock_both_profiles(profile, old_profile);
336 return old_profile;
337 +
338 +error:
339 + task_unlock(task);
340 + unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
341 + aa_free_task_context(new_cxt);
342 + return old_profile;
343 }
344
345 /**
346 @@ -1565,6 +1669,7 @@ void aa_change_task_context(struct task_
347
348 if (old_cxt) {
349 list_del_init(&old_cxt->list);
350 + old_cxt->profile->task_count--;
351 call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
352 }
353 if (new_cxt) {
354 @@ -1576,6 +1681,7 @@ void aa_change_task_context(struct task_
355 new_cxt->cookie = cookie;
356 new_cxt->task = task;
357 new_cxt->profile = aa_dup_profile(profile);
358 + profile->task_count++;
359 new_cxt->previous_profile = aa_dup_profile(previous_profile);
360 list_move(&new_cxt->list, &profile->task_contexts);
361 }
362 --- a/security/apparmor/module_interface.c
363 +++ b/security/apparmor/module_interface.c
364 @@ -177,6 +177,22 @@ fail:
365 return 0;
366 }
367
368 +static int aa_is_u64(struct aa_ext *e, u64 *data, const char *name)
369 +{
370 + void *pos = e->pos;
371 + if (aa_is_nameX(e, AA_U64, name)) {
372 + if (!aa_inbounds(e, sizeof(u64)))
373 + goto fail;
374 + if (data)
375 + *data = le64_to_cpu(get_unaligned((u64 *)e->pos));
376 + e->pos += sizeof(u64);
377 + return 1;
378 + }
379 +fail:
380 + e->pos = pos;
381 + return 0;
382 +}
383 +
384 static size_t aa_is_array(struct aa_ext *e, const char *name)
385 {
386 void *pos = e->pos;
387 @@ -312,6 +328,39 @@ fail:
388 return 0;
389 }
390
391 +int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
392 +{
393 + void *pos = e->pos;
394 +
395 + /* rlimits are optional */
396 + if (aa_is_nameX(e, AA_STRUCT, "rlimits")) {
397 + int i, size;
398 + u32 tmp = 0;
399 + if (!aa_is_u32(e, &tmp, NULL))
400 + goto fail;
401 + profile->rlimits.mask = tmp;
402 +
403 + size = aa_is_array(e, NULL);
404 + if (size > RLIM_NLIMITS)
405 + goto fail;
406 + for (i = 0; i < size; i++) {
407 + u64 tmp = 0;
408 + if (!aa_is_u64(e, &tmp, NULL))
409 + goto fail;
410 + profile->rlimits.limits[i].rlim_max = tmp;
411 + }
412 + if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
413 + goto fail;
414 + if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
415 + goto fail;
416 + }
417 + return 1;
418 +
419 +fail:
420 + e->pos = pos;
421 + return 0;
422 +}
423 +
424 /**
425 * aa_unpack_profile - unpack a serialized profile
426 * @e: serialized data extent information
427 @@ -355,6 +404,9 @@ static struct aa_profile *aa_unpack_prof
428 if (!aa_is_u32(e, &(profile->set_caps), NULL))
429 goto fail;
430
431 + if (!aa_unpack_rlimits(e, profile))
432 + goto fail;
433 +
434 size = aa_is_array(e, "net_allowed_af");
435 if (size) {
436 if (size > AF_MAX)
437 @@ -614,6 +666,8 @@ ssize_t aa_replace_profile(void *udata,
438 sa.operation = "profile_load";
439 goto out;
440 }
441 + /* do not fail replacement based off of profile's NPROC rlimit */
442 +
443 /*
444 * Replacement needs to allocate a new aa_task_context for each
445 * task confined by old_profile. To do this the profile locks
446 @@ -634,6 +688,7 @@ ssize_t aa_replace_profile(void *udata,
447 task_lock(task);
448 task_replace(task, new_cxt, new_profile);
449 task_unlock(task);
450 + aa_set_rlimits(task, new_profile);
451 new_cxt = NULL;
452 }
453 unlock_both_profiles(old_profile, new_profile);
454 @@ -656,6 +711,7 @@ out:
455 *
456 * remove a profile from the profile list and all aa_task_context references
457 * to said profile.
458 + * NOTE: removing confinement does not restore rlimits to preconfinemnet values
459 */
460 ssize_t aa_remove_profile(char *name, size_t size)
461 {