1 commit 5ea33f587f5f7324c40c5986286d0f38307923bb
2 Author: John Johansen <john.johansen@canonical.com>
3 Date: Mon Apr 11 16:55:10 2016 -0700
5 apparmor: fix refcount bug in profile replacement
7 Signed-off-by: John Johansen <john.johansen@canonical.com>
8 Acked-by: Seth Arnold <seth.arnold@canonical.com>
10 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
11 index 705c287..222052f 100644
12 --- a/security/apparmor/policy.c
13 +++ b/security/apparmor/policy.c
14 @@ -1189,12 +1189,12 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
15 aa_get_profile(newest);
16 aa_put_profile(parent);
17 rcu_assign_pointer(ent->new->parent, newest);
19 - aa_put_profile(newest);
21 /* aafs interface uses replacedby */
22 rcu_assign_pointer(ent->new->replacedby->profile,
23 aa_get_profile(ent->new));
24 __list_add_profile(&parent->base.profiles, ent->new);
25 + aa_put_profile(newest);
27 /* aafs interface uses replacedby */
28 rcu_assign_pointer(ent->new->replacedby->profile,
30 commit f65b1c9b72442e6166332c04f332e4b4d4797887
31 Author: John Johansen <john.johansen@canonical.com>
32 Date: Mon Apr 11 16:57:19 2016 -0700
34 apparmor: fix replacement bug that adds new child to old parent
36 When set atomic replacement is used and the parent is updated before the
37 child, and the child did not exist in the old parent so there is no
38 direct replacement then the new child is incorrectly added to the old
39 parent. This results in the new parent not having the child(ren) that
40 it should and the old parent when being destroyed asserting the
43 AppArmor: policy_destroy: internal error, policy '<profile/name>' still
46 Signed-off-by: John Johansen <john.johansen@canonical.com>
47 Acked-by: Seth Arnold <seth.arnold@canonical.com>
49 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
50 index 222052f..c92a9f6 100644
51 --- a/security/apparmor/policy.c
52 +++ b/security/apparmor/policy.c
53 @@ -1193,7 +1193,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
54 /* aafs interface uses replacedby */
55 rcu_assign_pointer(ent->new->replacedby->profile,
56 aa_get_profile(ent->new));
57 - __list_add_profile(&parent->base.profiles, ent->new);
58 + __list_add_profile(&newest->base.profiles, ent->new);
59 aa_put_profile(newest);
61 /* aafs interface uses replacedby */
63 commit b6669bef20c9d934bc6498e79fffa220f6226518
64 Author: John Johansen <john.johansen@canonical.com>
65 Date: Sun Jun 8 11:20:54 2014 -0700
67 apparmor: fix uninitialized lsm_audit member
69 BugLink: http://bugs.launchpad.net/bugs/1268727
71 The task field in the lsm_audit struct needs to be initialized if
72 a change_hat fails, otherwise the following oops will occur
74 BUG: unable to handle kernel paging request at 0000002fbead7d08
75 IP: [<ffffffff8171153e>] _raw_spin_lock+0xe/0x50
78 Modules linked in: pppox crc_ccitt p8023 p8022 psnap llc ax25 btrfs raid6_pq xor xfs libcrc32c dm_multipath scsi_dh kvm_amd dcdbas kvm microcode amd64_edac_mod joydev edac_core psmouse edac_mce_amd serio_raw k10temp sp5100_tco i2c_piix4 ipmi_si ipmi_msghandler acpi_power_meter mac_hid lp parport hid_generic usbhid hid pata_acpi mpt2sas ahci raid_class pata_atiixp bnx2 libahci scsi_transport_sas [last unloaded: tipc]
79 CPU: 2 PID: 699 Comm: changehat_twice Tainted: GF O 3.13.0-7-generic #25-Ubuntu
80 Hardware name: Dell Inc. PowerEdge R415/08WNM9, BIOS 1.8.6 12/06/2011
81 task: ffff8802135c6000 ti: ffff880212986000 task.ti: ffff880212986000
82 RIP: 0010:[<ffffffff8171153e>] [<ffffffff8171153e>] _raw_spin_lock+0xe/0x50
83 RSP: 0018:ffff880212987b68 EFLAGS: 00010006
84 RAX: 0000000000020000 RBX: 0000002fbead7500 RCX: 0000000000000000
85 RDX: 0000000000000292 RSI: ffff880212987ba8 RDI: 0000002fbead7d08
86 RBP: ffff880212987b68 R08: 0000000000000246 R09: ffff880216e572a0
87 R10: ffffffff815fd677 R11: ffffea0008469580 R12: ffffffff8130966f
88 R13: ffff880212987ba8 R14: 0000002fbead7d08 R15: ffff8800d8c6b830
89 FS: 00002b5e6c84e7c0(0000) GS:ffff880216e40000(0000) knlGS:0000000055731700
90 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
91 CR2: 0000002fbead7d08 CR3: 000000021270f000 CR4: 00000000000006e0
93 ffff880212987b98 ffffffff81075f17 ffffffff8130966f 0000000000000009
94 0000000000000000 0000000000000000 ffff880212987bd0 ffffffff81075f7c
95 0000000000000292 ffff880212987c08 ffff8800d8c6b800 0000000000000026
97 [<ffffffff81075f17>] __lock_task_sighand+0x47/0x80
98 [<ffffffff8130966f>] ? apparmor_cred_prepare+0x2f/0x50
99 [<ffffffff81075f7c>] do_send_sig_info+0x2c/0x80
100 [<ffffffff81075fee>] send_sig_info+0x1e/0x30
101 [<ffffffff8130242d>] aa_audit+0x13d/0x190
102 [<ffffffff8130c1dc>] aa_audit_file+0xbc/0x130
103 [<ffffffff8130966f>] ? apparmor_cred_prepare+0x2f/0x50
104 [<ffffffff81304cc2>] aa_change_hat+0x202/0x530
105 [<ffffffff81308fc6>] aa_setprocattr_changehat+0x116/0x1d0
106 [<ffffffff8130a11d>] apparmor_setprocattr+0x25d/0x300
107 [<ffffffff812cee56>] security_setprocattr+0x16/0x20
108 [<ffffffff8121fc87>] proc_pid_attr_write+0x107/0x130
109 [<ffffffff811b7604>] vfs_write+0xb4/0x1f0
110 [<ffffffff811b8039>] SyS_write+0x49/0xa0
111 [<ffffffff8171a1bf>] tracesys+0xe1/0xe6
113 Signed-off-by: John Johansen <john.johansen@canonical.com>
114 Acked-by: Seth Arnold <seth.arnold@canonical.com>
116 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
117 index 89c7865..3a7f1da 100644
118 --- a/security/apparmor/audit.c
119 +++ b/security/apparmor/audit.c
120 @@ -200,7 +200,8 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
122 if (sa->aad->type == AUDIT_APPARMOR_KILL)
123 (void)send_sig_info(SIGKILL, NULL,
124 - sa->u.tsk ? sa->u.tsk : current);
125 + sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ?
126 + sa->u.tsk : current);
128 if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
129 return complain_error(sa->aad->error);
130 diff --git a/security/apparmor/file.c b/security/apparmor/file.c
131 index d186674..4d2af4b 100644
132 --- a/security/apparmor/file.c
133 +++ b/security/apparmor/file.c
134 @@ -110,7 +110,8 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
135 int type = AUDIT_APPARMOR_AUTO;
136 struct common_audit_data sa;
137 struct apparmor_audit_data aad = {0,};
138 - sa.type = LSM_AUDIT_DATA_NONE;
139 + sa.type = LSM_AUDIT_DATA_TASK;
143 aad.fs.request = request;
145 commit aeab4cbfb86d0faeeb709e8201672e0662aa2c6f
146 Author: John Johansen <john.johansen@canonical.com>
147 Date: Fri Jul 25 04:02:03 2014 -0700
149 apparmor: exec should not be returning ENOENT when it denies
151 The current behavior is confusing as it causes exec failures to report
152 the executable is missing instead of identifying that apparmor
155 Signed-off-by: John Johansen <john.johansen@canonical.com>
156 Acked-by: Seth Arnold <seth.arnold@canonical.com>
158 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
159 index dc0027b..67a7418 100644
160 --- a/security/apparmor/domain.c
161 +++ b/security/apparmor/domain.c
162 @@ -433,7 +433,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
163 new_profile = aa_get_newest_profile(ns->unconfined);
164 info = "ux fallback";
168 info = "profile not found";
169 /* remove MAY_EXEC to audit as failure */
170 perms.allow &= ~MAY_EXEC;
172 commit 752e4263021d90cf23c262f2fd3ebfd6dbccd455
173 Author: John Johansen <john.johansen@canonical.com>
174 Date: Fri Jul 25 04:01:56 2014 -0700
176 apparmor: fix update the mtime of the profile file on replacement
178 Signed-off-by: John Johansen <john.johansen@canonical.com>
179 Acked-by: Seth Arnold <seth.arnold@canonical.com>
181 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
182 index ad4fa49..45a6199 100644
183 --- a/security/apparmor/apparmorfs.c
184 +++ b/security/apparmor/apparmorfs.c
185 @@ -379,6 +379,8 @@ void __aa_fs_profile_migrate_dents(struct aa_profile *old,
187 for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
188 new->dents[i] = old->dents[i];
190 + new->dents[i]->d_inode->i_mtime = CURRENT_TIME;
191 old->dents[i] = NULL;
195 commit 0c67233b18406dc7a8629faf8f9452feace6fb13
196 Author: John Johansen <john.johansen@canonical.com>
197 Date: Fri Jul 25 04:02:08 2014 -0700
199 apparmor: fix disconnected bind mnts reconnection
201 Bind mounts can fail to be properly reconnected when PATH_CONNECT is
202 specified. Ensure that when PATH_CONNECT is specified the path has
205 BugLink: http://bugs.launchpad.net/bugs/1319984
207 Signed-off-by: John Johansen <john.johansen@canonical.com>
208 Acked-by: Seth Arnold <seth.arnold@canonical.com>
210 diff --git a/security/apparmor/path.c b/security/apparmor/path.c
211 index edddc02..f261678 100644
212 --- a/security/apparmor/path.c
213 +++ b/security/apparmor/path.c
214 @@ -141,7 +141,10 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
219 + } else if (*res != '/')
220 + /* CONNECT_PATH with missing root */
221 + error = prepend(name, *name - buf, "/", 1);
227 commit 30c2b759b4f456e97e859ca550666c8abe84ff3c
228 Author: John Johansen <john.johansen@canonical.com>
229 Date: Fri Jul 25 04:02:10 2014 -0700
231 apparmor: internal paths should be treated as disconnected
233 Internal mounts are not mounted anywhere and as such should be treated
234 as disconnected paths.
236 Signed-off-by: John Johansen <john.johansen@canonical.com>
237 Acked-by: Seth Arnold <seth.arnold@canonical.com>
239 diff --git a/security/apparmor/path.c b/security/apparmor/path.c
240 index f261678..a8fc7d0 100644
241 --- a/security/apparmor/path.c
242 +++ b/security/apparmor/path.c
244 #include "include/path.h"
245 #include "include/policy.h"
248 /* modified from dcache.c */
249 static int prepend(char **buffer, int buflen, const char *str, int namelen)
251 @@ -39,6 +38,38 @@ static int prepend(char **buffer, int buflen, const char *str, int namelen)
253 #define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
255 +/* If the path is not connected to the expected root,
256 + * check if it is a sysctl and handle specially else remove any
257 + * leading / that __d_path may have returned.
259 + * specifically directed to connect the path,
261 + * if in a chroot and doing chroot relative paths and the path
262 + * resolves to the namespace root (would be connected outside
263 + * of chroot) and specifically directed to connect paths to
266 +static int disconnect(const struct path *path, char *buf, char **name,
271 + if (!(flags & PATH_CONNECT_PATH) &&
272 + !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
273 + our_mnt(path->mnt))) {
274 + /* disconnected path, don't return pathname starting
280 + } else if (**name != '/')
281 + /* CONNECT_PATH with missing root */
282 + error = prepend(name, *name - buf, "/", 1);
288 * d_namespace_path - lookup a name associated with a given path
289 * @path: path to lookup (NOT NULL)
290 @@ -74,7 +105,8 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
291 * control instead of hard coded /proc
293 return prepend(name, *name - buf, "/proc", 5);
296 + return disconnect(path, buf, name, flags);
300 @@ -120,32 +152,8 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
304 - /* If the path is not connected to the expected root,
305 - * check if it is a sysctl and handle specially else remove any
306 - * leading / that __d_path may have returned.
308 - * specifically directed to connect the path,
310 - * if in a chroot and doing chroot relative paths and the path
311 - * resolves to the namespace root (would be connected outside
312 - * of chroot) and specifically directed to connect paths to
316 - if (!(flags & PATH_CONNECT_PATH) &&
317 - !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
318 - our_mnt(path->mnt))) {
319 - /* disconnected path, don't return pathname starting
325 - } else if (*res != '/')
326 - /* CONNECT_PATH with missing root */
327 - error = prepend(name, *name - buf, "/", 1);
331 + error = disconnect(path, buf, name, flags);
336 commit 35f89b597a40c870f93a068bc92a7ef4f9b16a66
337 Author: John Johansen <john.johansen@canonical.com>
338 Date: Sat Apr 16 13:59:02 2016 -0700
340 apparmor: fix put() parent ref after updating the active ref
342 Signed-off-by: John Johansen <john.johansen@canonical.com>
343 Acked-by: Seth Arnold <seth.arnold@canonical.com>
345 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
346 index c92a9f6..455c9f8 100644
347 --- a/security/apparmor/policy.c
348 +++ b/security/apparmor/policy.c
349 @@ -1187,8 +1187,8 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
350 /* parent replaced in this atomic set? */
351 if (newest != parent) {
352 aa_get_profile(newest);
353 - aa_put_profile(parent);
354 rcu_assign_pointer(ent->new->parent, newest);
355 + aa_put_profile(parent);
357 /* aafs interface uses replacedby */
358 rcu_assign_pointer(ent->new->replacedby->profile,
360 commit 7b1ec6a04ca57fabe250f1102f2803dea7fbd03b
361 Author: John Johansen <john.johansen@canonical.com>
362 Date: Sat Apr 16 14:16:50 2016 -0700
364 apparmor: fix log failures for all profiles in a set
366 currently only the profile that is causing the failure is logged. This
367 makes it more confusing than necessary about which profiles loaded
368 and which didn't. So make sure to log success and failure messages for
369 all profiles in the set being loaded.
371 Signed-off-by: John Johansen <john.johansen@canonical.com>
372 Acked-by: Seth Arnold <seth.arnold@canonical.com>
374 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
375 index 455c9f8..db31bc5 100644
376 --- a/security/apparmor/policy.c
377 +++ b/security/apparmor/policy.c
378 @@ -1067,7 +1067,7 @@ static int __lookup_replace(struct aa_namespace *ns, const char *hname,
380 ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
382 - const char *ns_name, *name = NULL, *info = NULL;
383 + const char *ns_name, *info = NULL;
384 struct aa_namespace *ns = NULL;
385 struct aa_load_ent *ent, *tmp;
386 int op = OP_PROF_REPL;
387 @@ -1082,18 +1082,15 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
389 ns = aa_prepare_namespace(ns_name);
391 - info = "failed to prepare namespace";
395 + error = audit_policy(op, GFP_KERNEL, ns_name,
396 + "failed to prepare namespace", -ENOMEM);
400 mutex_lock(&ns->lock);
401 /* setup parent and ns info */
402 list_for_each_entry(ent, &lh, list) {
403 struct aa_policy *policy;
405 - name = ent->new->base.hname;
406 error = __lookup_replace(ns, ent->new->base.hname, noreplace,
409 @@ -1121,7 +1118,6 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
412 info = "parent does not exist";
413 - name = ent->new->base.hname;
416 rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
417 @@ -1214,9 +1210,22 @@ out:
420 mutex_unlock(&ns->lock);
422 - error = audit_policy(op, GFP_KERNEL, name, info, error);
424 + /* audit cause of failure */
425 + op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
426 + audit_policy(op, GFP_KERNEL, ent->new->base.hname, info, error);
427 + /* audit status that rest of profiles in the atomic set failed too */
428 + info = "valid profile in failed atomic policy load";
429 + list_for_each_entry(tmp, &lh, list) {
431 + info = "unchecked profile in failed atomic policy load";
432 + /* skip entry that caused failure */
435 + op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
436 + audit_policy(op, GFP_KERNEL, tmp->new->base.hname, info, error);
439 list_for_each_entry_safe(ent, tmp, &lh, list) {
440 list_del_init(&ent->list);
441 aa_load_ent_free(ent);
443 commit 4c475747a31b0637f0d47cb9bddaf2c6efb02854
444 Author: John Johansen <john.johansen@canonical.com>
445 Date: Sat Apr 16 14:19:38 2016 -0700
447 apparmor: fix audit full profile hname on successful load
449 Currently logging of a successful profile load only logs the basename
450 of the profile. This can result in confusion when a child profile has
451 the same name as the another profile in the set. Logging the hname
452 will ensure there is no confusion.
454 Signed-off-by: John Johansen <john.johansen@canonical.com>
455 Acked-by: Seth Arnold <seth.arnold@canonical.com>
457 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
458 index db31bc5..ca402d0 100644
459 --- a/security/apparmor/policy.c
460 +++ b/security/apparmor/policy.c
461 @@ -1159,7 +1159,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
462 list_del_init(&ent->list);
463 op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
465 - audit_policy(op, GFP_ATOMIC, ent->new->base.name, NULL, error);
466 + audit_policy(op, GFP_ATOMIC, ent->new->base.hname, NULL, error);
469 __replace_profile(ent->old, ent->new, 1);
471 commit 430741dd766291d2e618b04e918ee6da844c230a
472 Author: John Johansen <john.johansen@canonical.com>
473 Date: Wed Apr 20 14:18:18 2016 -0700
475 apparmor: ensure the target profile name is always audited
477 The target profile name was not being correctly audited in a few
478 cases because the target variable was not being set and gotos
479 passed the code to set it at apply:
481 Since it is always based on new_profile just drop the target var
482 and conditionally report based on new_profile.
484 Signed-off-by: John Johansen <john.johansen@canonical.com>
485 Acked-by: Seth Arnold <seth.arnold@canonical.com>
487 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
488 index 67a7418..fc3036b 100644
489 --- a/security/apparmor/domain.c
490 +++ b/security/apparmor/domain.c
491 @@ -346,7 +346,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
492 file_inode(bprm->file)->i_uid,
493 file_inode(bprm->file)->i_mode
495 - const char *name = NULL, *target = NULL, *info = NULL;
496 + const char *name = NULL, *info = NULL;
499 if (bprm->cred_prepared)
500 @@ -399,6 +399,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
502 struct file_perms cp;
503 info = "change_profile onexec";
504 + new_profile = aa_get_newest_profile(cxt->onexec);
505 if (!(perms.allow & AA_MAY_ONEXEC))
508 @@ -413,7 +414,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
510 if (!(cp.allow & AA_MAY_ONEXEC))
512 - new_profile = aa_get_newest_profile(cxt->onexec);
516 @@ -445,10 +445,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
519 info = "could not create null profile";
523 - target = new_profile->base.hname;
525 perms.xindex |= AA_X_UNSAFE;
528 @@ -459,7 +457,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
531 if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) {
532 - aa_put_profile(new_profile);
536 @@ -474,10 +471,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
538 if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
539 error = may_change_ptraced_domain(new_profile);
541 - aa_put_profile(new_profile);
547 /* Determine if secure exec is needed.
548 @@ -498,7 +493,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
549 bprm->unsafe |= AA_SECURE_X_NEEDED;
552 - target = new_profile->base.hname;
553 /* when transitioning profiles clear unsafe personality bits */
554 bprm->per_clear |= PER_CLEAR_ON_SETID;
556 @@ -506,15 +500,19 @@ x_clear:
557 aa_put_profile(cxt->profile);
558 /* transfer new profile reference will be released when cxt is freed */
559 cxt->profile = new_profile;
560 + new_profile = NULL;
562 /* clear out all temporary/transitional state from the context */
563 aa_clear_task_cxt_trans(cxt);
566 error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
567 - name, target, cond.uid, info, error);
569 + new_profile ? new_profile->base.hname : NULL,
570 + cond.uid, info, error);
573 + aa_put_profile(new_profile);
574 aa_put_profile(profile);
578 commit 06763d057300b3d5bbe1894acfe236cf193bab78
579 Author: John Johansen <john.johansen@canonical.com>
580 Date: Thu Mar 17 12:02:54 2016 -0700
582 apparmor: check that xindex is in trans_table bounds
584 Signed-off-by: John Johansen <john.johansen@canonical.com>
585 Acked-by: Seth Arnold <seth.arnold@canonical.com>
587 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
588 index a689f10..c841b12 100644
589 --- a/security/apparmor/policy_unpack.c
590 +++ b/security/apparmor/policy_unpack.c
591 @@ -676,7 +676,7 @@ static bool verify_xindex(int xindex, int table_size)
593 xtype = xindex & AA_X_TYPE_MASK;
594 index = xindex & AA_X_INDEX_MASK;
595 - if (xtype == AA_X_TABLE && index > table_size)
596 + if (xtype == AA_X_TABLE && index >= table_size)
601 commit e13f968d154ba9d6a2c4f82f33d3312a63430b54
602 Author: John Johansen <john.johansen@canonical.com>
603 Date: Wed Dec 16 18:09:10 2015 -0800
605 apparmor: fix refcount race when finding a child profile
607 When finding a child profile via an rcu critical section, the profile
608 may be put and scheduled for deletion after the child is found but
609 before its refcount is incremented.
611 Protect against this by repeating the lookup if the profiles refcount
612 is 0 and is one its way to deletion.
614 Signed-off-by: John Johansen <john.johansen@canonical.com>
615 Acked-by: Seth Arnold <seth.arnold@canonical.com>
617 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
618 index ca402d0..7807125 100644
619 --- a/security/apparmor/policy.c
620 +++ b/security/apparmor/policy.c
621 @@ -766,7 +766,9 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
622 struct aa_profile *profile;
625 - profile = aa_get_profile(__find_child(&parent->base.profiles, name));
627 + profile = __find_child(&parent->base.profiles, name);
628 + } while (profile && !aa_get_profile_not0(profile));
631 /* refcount released by caller */
633 commit 5833ccff1227fbc8f1bab64351f6747a6c71bdeb
634 Author: Geliang Tang <geliangtang@163.com>
635 Date: Mon Nov 16 21:46:33 2015 +0800
637 apparmor: use list_next_entry instead of list_entry_next
639 list_next_entry has been defined in list.h, so I replace list_entry_next
642 Signed-off-by: Geliang Tang <geliangtang@163.com>
643 Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
644 Signed-off-by: John Johansen <john.johansen@canonical.com>
646 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
647 index 0d8dd71..729e595 100644
648 --- a/security/apparmor/apparmorfs.c
649 +++ b/security/apparmor/apparmorfs.c
650 @@ -553,8 +553,6 @@ fail2:
654 -#define list_entry_next(pos, member) \
655 - list_entry(pos->member.next, typeof(*pos), member)
656 #define list_entry_is_head(pos, head, member) (&pos->member == (head))
659 @@ -585,7 +583,7 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root,
662 mutex_unlock(&ns->lock);
663 - next = list_entry_next(ns, base.list);
664 + next = list_next_entry(ns, base.list);
665 if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
666 mutex_lock(&next->lock);
668 @@ -639,7 +637,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
669 parent = rcu_dereference_protected(p->parent,
670 mutex_is_locked(&p->ns->lock));
672 - p = list_entry_next(p, base.list);
673 + p = list_next_entry(p, base.list);
674 if (!list_entry_is_head(p, &parent->base.profiles, base.list))
677 @@ -648,7 +646,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
680 /* is next another profile in the namespace */
681 - p = list_entry_next(p, base.list);
682 + p = list_next_entry(p, base.list);
683 if (!list_entry_is_head(p, &ns->base.profiles, base.list))
687 commit 645801f1ddd183109c011e5ecee23ed3fdcae244
688 Author: Jeff Mahoney <jeffm@suse.com>
689 Date: Fri Nov 6 15:17:30 2015 -0500
691 apparmor: allow SYS_CAP_RESOURCE to be sufficient to prlimit another task
693 While using AppArmor, SYS_CAP_RESOURCE is insufficient to call prlimit
694 on another task. The only other example of a AppArmor mediating access to
695 another, already running, task (ignoring fork+exec) is ptrace.
697 The AppArmor model for ptrace is that one of the following must be true:
698 1) The tracer is unconfined
699 2) The tracer is in complain mode
700 3) The tracer and tracee are confined by the same profile
701 4) The tracer is confined but has SYS_CAP_PTRACE
703 1), 2, and 3) are already true for setrlimit.
705 We can match the ptrace model just by allowing CAP_SYS_RESOURCE.
707 We still test the values of the rlimit since it can always be overridden
708 using a value that means unlimited for a particular resource.
710 Signed-off-by: Jeff Mahoney <jeffm@suse.com>
711 Signed-off-by: John Johansen <john.johansen@canonical.com>
713 diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
714 index 748bf0c..67a6072 100644
715 --- a/security/apparmor/resource.c
716 +++ b/security/apparmor/resource.c
717 @@ -101,9 +101,11 @@ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task,
718 /* TODO: extend resource control to handle other (non current)
719 * profiles. AppArmor rules currently have the implicit assumption
720 * that the task is setting the resource of a task confined with
721 - * the same profile.
722 + * the same profile or that the task setting the resource of another
723 + * task has CAP_SYS_RESOURCE.
725 - if (profile != task_profile ||
726 + if ((profile != task_profile &&
727 + aa_capable(profile, CAP_SYS_RESOURCE, 1)) ||
728 (profile->rlimits.mask & (1 << resource) &&
729 new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max))
732 commit 2be4aed1f3332d87273eb593944332054f3cffac
733 Author: John Johansen <john.johansen@canonical.com>
734 Date: Thu Jun 2 02:37:02 2016 -0700
736 apparmor: add missing id bounds check on dfa verification
738 Signed-off-by: John Johansen <john.johansen@canonical.com>
740 diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
741 index 001c43a..a1c04fe 100644
742 --- a/security/apparmor/include/match.h
743 +++ b/security/apparmor/include/match.h
744 @@ -62,6 +62,7 @@ struct table_set_header {
745 #define YYTD_ID_ACCEPT2 6
746 #define YYTD_ID_NXT 7
747 #define YYTD_ID_TSIZE 8
748 +#define YYTD_ID_MAX 8
751 #define YYTD_DATA16 2
752 diff --git a/security/apparmor/match.c b/security/apparmor/match.c
753 index 727eb42..f9f57c6 100644
754 --- a/security/apparmor/match.c
755 +++ b/security/apparmor/match.c
756 @@ -47,6 +47,8 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
757 * it every time we use td_id as an index
759 th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
760 + if (th.td_id > YYTD_ID_MAX)
762 th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
763 th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
764 blob += sizeof(struct table_header);
766 commit c7f87d3c3363b1a0c4724e627e5c8e640a883c89
767 Author: John Johansen <john.johansen@canonical.com>
768 Date: Wed Jun 15 09:57:55 2016 +0300
770 apparmor: don't check for vmalloc_addr if kvzalloc() failed
772 Signed-off-by: John Johansen <john.johansen@canonical.com>
774 diff --git a/security/apparmor/match.c b/security/apparmor/match.c
775 index f9f57c6..32b72eb 100644
776 --- a/security/apparmor/match.c
777 +++ b/security/apparmor/match.c
778 @@ -75,14 +75,14 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
782 + /* if table was vmalloced make sure the page tables are synced
783 + * before it is used, as it goes live to all cpus.
785 + if (is_vmalloc_addr(table))
786 + vm_unmap_aliases();
790 - /* if table was vmalloced make sure the page tables are synced
791 - * before it is used, as it goes live to all cpus.
793 - if (is_vmalloc_addr(table))
794 - vm_unmap_aliases();
799 commit 0f7e61013dd1e67ebb54d58eee11ab009ceb5ef3
800 Author: John Johansen <john.johansen@canonical.com>
801 Date: Wed Jun 15 10:00:55 2016 +0300
803 apparmor: fix oops in profile_unpack() when policy_db is not present
805 BugLink: http://bugs.launchpad.net/bugs/1592547
807 If unpack_dfa() returns NULL due to the dfa not being present,
808 profile_unpack() is not checking if the dfa is not present (NULL).
810 Signed-off-by: John Johansen <john.johansen@canonical.com>
812 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
813 index c841b12..dac2121 100644
814 --- a/security/apparmor/policy_unpack.c
815 +++ b/security/apparmor/policy_unpack.c
816 @@ -583,6 +583,9 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
817 error = PTR_ERR(profile->policy.dfa);
818 profile->policy.dfa = NULL;
820 + } else if (!profile->policy.dfa) {
824 if (!unpack_u32(e, &profile->policy.start[0], "start"))
825 /* default start state */
827 commit de4ca46ec035283928e8fa40797897cefcf6ec3e
828 Author: John Johansen <john.johansen@canonical.com>
829 Date: Wed Jun 22 18:01:08 2016 -0700
831 apparmor: fix module parameters can be changed after policy is locked
833 the policy_lock parameter is a one way switch that prevents policy
834 from being further modified. Unfortunately some of the module parameters
835 can effectively modify policy by turning off enforcement.
837 split policy_admin_capable into a view check and a full admin check,
838 and update the admin check to test the policy_lock parameter.
840 Signed-off-by: John Johansen <john.johansen@canonical.com>
842 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
843 index c28b0f2..52275f0 100644
844 --- a/security/apparmor/include/policy.h
845 +++ b/security/apparmor/include/policy.h
846 @@ -403,6 +403,8 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
847 return profile->audit;
850 +bool policy_view_capable(void);
851 +bool policy_admin_capable(void);
852 bool aa_may_manage_policy(int op);
854 #endif /* __AA_POLICY_H */
855 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
856 index 7798e16..e83eefb 100644
857 --- a/security/apparmor/lsm.c
858 +++ b/security/apparmor/lsm.c
859 @@ -728,51 +728,49 @@ __setup("apparmor=", apparmor_enabled_setup);
860 /* set global flag turning off the ability to load policy */
861 static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
863 - if (!capable(CAP_MAC_ADMIN))
864 + if (!policy_admin_capable())
866 - if (aa_g_lock_policy)
868 return param_set_bool(val, kp);
871 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
873 - if (!capable(CAP_MAC_ADMIN))
874 + if (!policy_view_capable())
876 return param_get_bool(buffer, kp);
879 static int param_set_aabool(const char *val, const struct kernel_param *kp)
881 - if (!capable(CAP_MAC_ADMIN))
882 + if (!policy_admin_capable())
884 return param_set_bool(val, kp);
887 static int param_get_aabool(char *buffer, const struct kernel_param *kp)
889 - if (!capable(CAP_MAC_ADMIN))
890 + if (!policy_view_capable())
892 return param_get_bool(buffer, kp);
895 static int param_set_aauint(const char *val, const struct kernel_param *kp)
897 - if (!capable(CAP_MAC_ADMIN))
898 + if (!policy_admin_capable())
900 return param_set_uint(val, kp);
903 static int param_get_aauint(char *buffer, const struct kernel_param *kp)
905 - if (!capable(CAP_MAC_ADMIN))
906 + if (!policy_view_capable())
908 return param_get_uint(buffer, kp);
911 static int param_get_audit(char *buffer, struct kernel_param *kp)
913 - if (!capable(CAP_MAC_ADMIN))
914 + if (!policy_view_capable())
917 if (!apparmor_enabled)
918 @@ -784,7 +782,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp)
919 static int param_set_audit(const char *val, struct kernel_param *kp)
922 - if (!capable(CAP_MAC_ADMIN))
923 + if (!policy_admin_capable())
926 if (!apparmor_enabled)
927 @@ -805,7 +803,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp)
929 static int param_get_mode(char *buffer, struct kernel_param *kp)
931 - if (!capable(CAP_MAC_ADMIN))
932 + if (!policy_admin_capable())
935 if (!apparmor_enabled)
936 @@ -817,7 +815,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp)
937 static int param_set_mode(const char *val, struct kernel_param *kp)
940 - if (!capable(CAP_MAC_ADMIN))
941 + if (!policy_admin_capable())
944 if (!apparmor_enabled)
945 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
946 index 7807125..179e68d 100644
947 --- a/security/apparmor/policy.c
948 +++ b/security/apparmor/policy.c
949 @@ -918,6 +918,22 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
953 +bool policy_view_capable(void)
955 + struct user_namespace *user_ns = current_user_ns();
956 + bool response = false;
958 + if (ns_capable(user_ns, CAP_MAC_ADMIN))
964 +bool policy_admin_capable(void)
966 + return policy_view_capable() && !aa_g_lock_policy;
970 * aa_may_manage_policy - can the current task manage policy
971 * @op: the policy manipulation operation being done
972 @@ -932,7 +948,7 @@ bool aa_may_manage_policy(int op)
976 - if (!capable(CAP_MAC_ADMIN)) {
977 + if (!policy_admin_capable()) {
978 audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
982 commit 46c339f46b83e4cf8098f599cd182e65e9d054fc
983 Author: Heinrich Schuchardt <xypron.glpk@gmx.de>
984 Date: Fri Jun 10 23:34:26 2016 +0200
986 apparmor: do not expose kernel stack
988 Do not copy uninitalized fields th.td_hilen, th.td_data.
990 Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
991 Signed-off-by: John Johansen <john.johansen@canonical.com>
993 diff --git a/security/apparmor/match.c b/security/apparmor/match.c
994 index 32b72eb..3f900fc 100644
995 --- a/security/apparmor/match.c
996 +++ b/security/apparmor/match.c
997 @@ -63,7 +63,9 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
999 table = kvzalloc(tsize);
1002 + table->td_id = th.td_id;
1003 + table->td_flags = th.td_flags;
1004 + table->td_lolen = th.td_lolen;
1005 if (th.td_flags == YYTD_DATA8)
1006 UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
1009 commit 7e65e8142b2ea4891581173d6e92fc337b02ff8b
1010 Author: John Johansen <john.johansen@canonical.com>
1011 Date: Sat Jul 9 23:46:33 2016 -0700
1013 apparmor: fix arg_size computation for when setprocattr is null terminated
1015 Signed-off-by: John Johansen <john.johansen@canonical.com>
1017 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1018 index e83eefb..ba8207b 100644
1019 --- a/security/apparmor/lsm.c
1020 +++ b/security/apparmor/lsm.c
1021 @@ -529,7 +529,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
1025 - arg_size = size - (args - (char *) value);
1026 + arg_size = size - (args - (largs ? largs : (char *) value));
1027 if (strcmp(name, "current") == 0) {
1028 if (strcmp(command, "changehat") == 0) {
1029 error = aa_setprocattr_changehat(args, arg_size,
1031 commit b661b13237991be6b5cdf0849f137c5ec58217bf
1032 Author: John Johansen <john.johansen@canonical.com>
1033 Date: Mon Oct 4 15:03:36 2010 -0700
1035 UBUNTU: SAUCE: AppArmor: basic networking rules
1037 Base support for network mediation.
1039 Signed-off-by: John Johansen <john.johansen@canonical.com>
1041 diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
1042 index 9cdec70..d5b291e 100644
1043 --- a/security/apparmor/.gitignore
1044 +++ b/security/apparmor/.gitignore
1047 # Generated include files
1052 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
1053 index d693df8..5dbb72f 100644
1054 --- a/security/apparmor/Makefile
1055 +++ b/security/apparmor/Makefile
1056 @@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
1058 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
1059 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
1060 - resource.o sid.o file.o
1061 + resource.o sid.o file.o net.o
1062 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
1064 -clean-files := capability_names.h rlim_names.h
1065 +clean-files := capability_names.h rlim_names.h net_names.h
1068 # Build a lower case string table of capability names
1069 @@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
1070 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
1071 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
1073 +# Build a lower case string table of address family names
1074 +# Transform lines from
1075 +# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
1076 +# #define AF_INET 2 /* Internet IP Protocol */
1081 +# and build the securityfs entries for the mapping.
1082 +# Transforms lines from
1083 +# #define AF_INET 2 /* Internet IP Protocol */
1085 +# #define AA_FS_AF_MASK "local inet"
1086 +quiet_cmd_make-af = GEN $@
1087 +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
1088 + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
1089 + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
1090 + echo "};" >> $@ ;\
1091 + echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
1092 + sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
1093 + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
1095 +# Build a lower case string table of sock type names
1096 +# Transform lines from
1100 +quiet_cmd_make-sock = GEN $@
1101 +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
1102 + sed $^ >>$@ -r -n \
1103 + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
1106 # Build a lower case string table of rlimit names.
1107 # Transforms lines from
1108 @@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
1109 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
1111 $(obj)/capability.o : $(obj)/capability_names.h
1112 +$(obj)/net.o : $(obj)/net_names.h
1113 $(obj)/resource.o : $(obj)/rlim_names.h
1114 $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
1116 @@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
1117 $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
1119 $(call cmd,make-rlim)
1120 +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
1121 + $(srctree)/include/linux/net.h \
1123 + $(call cmd,make-af)
1124 + $(call cmd,make-sock)
1125 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
1126 index 729e595..181d961 100644
1127 --- a/security/apparmor/apparmorfs.c
1128 +++ b/security/apparmor/apparmorfs.c
1129 @@ -807,6 +807,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
1130 AA_FS_DIR("policy", aa_fs_entry_policy),
1131 AA_FS_DIR("domain", aa_fs_entry_domain),
1132 AA_FS_DIR("file", aa_fs_entry_file),
1133 + AA_FS_DIR("network", aa_fs_entry_network),
1134 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
1135 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
1136 AA_FS_DIR("caps", aa_fs_entry_caps),
1137 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
1138 index ba3dfd1..5d3c419 100644
1139 --- a/security/apparmor/include/audit.h
1140 +++ b/security/apparmor/include/audit.h
1141 @@ -125,6 +125,10 @@ struct apparmor_audit_data {
1146 + int type, protocol;
1152 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
1153 new file mode 100644
1154 index 0000000..cb8a121
1156 +++ b/security/apparmor/include/net.h
1159 + * AppArmor security module
1161 + * This file contains AppArmor network mediation definitions.
1163 + * Copyright (C) 1998-2008 Novell/SUSE
1164 + * Copyright 2009-2012 Canonical Ltd.
1166 + * This program is free software; you can redistribute it and/or
1167 + * modify it under the terms of the GNU General Public License as
1168 + * published by the Free Software Foundation, version 2 of the
1175 +#include <net/sock.h>
1177 +#include "apparmorfs.h"
1179 +/* struct aa_net - network confinement data
1180 + * @allowed: basic network families permissions
1181 + * @audit_network: which network permissions to force audit
1182 + * @quiet_network: which network permissions to quiet rejects
1185 + u16 allow[AF_MAX];
1186 + u16 audit[AF_MAX];
1187 + u16 quiet[AF_MAX];
1190 +extern struct aa_fs_entry aa_fs_entry_network[];
1192 +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
1193 + int type, int protocol, struct sock *sk);
1194 +extern int aa_revalidate_sk(int op, struct sock *sk);
1196 +static inline void aa_free_net_rules(struct aa_net *new)
1201 +#endif /* __AA_NET_H */
1202 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
1203 index 52275f0..4fc4dac 100644
1204 --- a/security/apparmor/include/policy.h
1205 +++ b/security/apparmor/include/policy.h
1207 #include "capability.h"
1211 #include "resource.h"
1213 extern const char *const aa_profile_mode_names[];
1214 @@ -176,6 +177,7 @@ struct aa_replacedby {
1215 * @policy: general match rules governing policy
1216 * @file: The set of rules governing basic file access and domain transitions
1217 * @caps: capabilities for the profile
1218 + * @net: network controls for the profile
1219 * @rlimits: rlimits for the profile
1221 * @dents: dentries for the profiles file entries in apparmorfs
1222 @@ -217,6 +219,7 @@ struct aa_profile {
1223 struct aa_policydb policy;
1224 struct aa_file_rules file;
1225 struct aa_caps caps;
1226 + struct aa_net net;
1227 struct aa_rlimit rlimits;
1229 unsigned char *hash;
1230 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1231 index ba8207b..88d3b0a 100644
1232 --- a/security/apparmor/lsm.c
1233 +++ b/security/apparmor/lsm.c
1235 #include "include/context.h"
1236 #include "include/file.h"
1237 #include "include/ipc.h"
1238 +#include "include/net.h"
1239 #include "include/path.h"
1240 #include "include/policy.h"
1241 #include "include/procattr.h"
1242 @@ -584,6 +585,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
1246 +static int apparmor_socket_create(int family, int type, int protocol, int kern)
1248 + struct aa_profile *profile;
1254 + profile = __aa_current_profile();
1255 + if (!unconfined(profile))
1256 + error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
1261 +static int apparmor_socket_bind(struct socket *sock,
1262 + struct sockaddr *address, int addrlen)
1264 + struct sock *sk = sock->sk;
1266 + return aa_revalidate_sk(OP_BIND, sk);
1269 +static int apparmor_socket_connect(struct socket *sock,
1270 + struct sockaddr *address, int addrlen)
1272 + struct sock *sk = sock->sk;
1274 + return aa_revalidate_sk(OP_CONNECT, sk);
1277 +static int apparmor_socket_listen(struct socket *sock, int backlog)
1279 + struct sock *sk = sock->sk;
1281 + return aa_revalidate_sk(OP_LISTEN, sk);
1284 +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
1286 + struct sock *sk = sock->sk;
1288 + return aa_revalidate_sk(OP_ACCEPT, sk);
1291 +static int apparmor_socket_sendmsg(struct socket *sock,
1292 + struct msghdr *msg, int size)
1294 + struct sock *sk = sock->sk;
1296 + return aa_revalidate_sk(OP_SENDMSG, sk);
1299 +static int apparmor_socket_recvmsg(struct socket *sock,
1300 + struct msghdr *msg, int size, int flags)
1302 + struct sock *sk = sock->sk;
1304 + return aa_revalidate_sk(OP_RECVMSG, sk);
1307 +static int apparmor_socket_getsockname(struct socket *sock)
1309 + struct sock *sk = sock->sk;
1311 + return aa_revalidate_sk(OP_GETSOCKNAME, sk);
1314 +static int apparmor_socket_getpeername(struct socket *sock)
1316 + struct sock *sk = sock->sk;
1318 + return aa_revalidate_sk(OP_GETPEERNAME, sk);
1321 +static int apparmor_socket_getsockopt(struct socket *sock, int level,
1324 + struct sock *sk = sock->sk;
1326 + return aa_revalidate_sk(OP_GETSOCKOPT, sk);
1329 +static int apparmor_socket_setsockopt(struct socket *sock, int level,
1332 + struct sock *sk = sock->sk;
1334 + return aa_revalidate_sk(OP_SETSOCKOPT, sk);
1337 +static int apparmor_socket_shutdown(struct socket *sock, int how)
1339 + struct sock *sk = sock->sk;
1341 + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
1344 static struct security_hook_list apparmor_hooks[] = {
1345 LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
1346 LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
1347 @@ -613,6 +712,19 @@ static struct security_hook_list apparmor_hooks[] = {
1348 LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
1349 LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
1351 + LSM_HOOK_INIT(socket_create, apparmor_socket_create),
1352 + LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
1353 + LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
1354 + LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
1355 + LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
1356 + LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
1357 + LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
1358 + LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
1359 + LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
1360 + LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
1361 + LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
1362 + LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
1364 LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
1365 LSM_HOOK_INIT(cred_free, apparmor_cred_free),
1366 LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
1367 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
1368 new file mode 100644
1369 index 0000000..003dd18
1371 +++ b/security/apparmor/net.c
1374 + * AppArmor security module
1376 + * This file contains AppArmor network mediation
1378 + * Copyright (C) 1998-2008 Novell/SUSE
1379 + * Copyright 2009-2012 Canonical Ltd.
1381 + * This program is free software; you can redistribute it and/or
1382 + * modify it under the terms of the GNU General Public License as
1383 + * published by the Free Software Foundation, version 2 of the
1387 +#include "include/apparmor.h"
1388 +#include "include/audit.h"
1389 +#include "include/context.h"
1390 +#include "include/net.h"
1391 +#include "include/policy.h"
1393 +#include "net_names.h"
1395 +struct aa_fs_entry aa_fs_entry_network[] = {
1396 + AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
1400 +/* audit callback for net specific fields */
1401 +static void audit_cb(struct audit_buffer *ab, void *va)
1403 + struct common_audit_data *sa = va;
1405 + audit_log_format(ab, " family=");
1406 + if (address_family_names[sa->u.net->family]) {
1407 + audit_log_string(ab, address_family_names[sa->u.net->family]);
1409 + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
1411 + audit_log_format(ab, " sock_type=");
1412 + if (sock_type_names[sa->aad->net.type]) {
1413 + audit_log_string(ab, sock_type_names[sa->aad->net.type]);
1415 + audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
1417 + audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
1421 + * audit_net - audit network access
1422 + * @profile: profile being enforced (NOT NULL)
1423 + * @op: operation being checked
1424 + * @family: network family
1425 + * @type: network type
1426 + * @protocol: network protocol
1427 + * @sk: socket auditing is being applied to
1428 + * @error: error code for failure else 0
1430 + * Returns: %0 or sa->error else other errorcode on failure
1432 +static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
1433 + int protocol, struct sock *sk, int error)
1435 + int audit_type = AUDIT_APPARMOR_AUTO;
1436 + struct common_audit_data sa;
1437 + struct apparmor_audit_data aad = { };
1438 + struct lsm_network_audit net = { };
1440 + sa.type = LSM_AUDIT_DATA_NET;
1442 + sa.type = LSM_AUDIT_DATA_NONE;
1444 + /* todo fill in socket addr info */
1448 + sa.u.net->family = family;
1449 + sa.u.net->sk = sk;
1450 + sa.aad->net.type = type;
1451 + sa.aad->net.protocol = protocol;
1452 + sa.aad->error = error;
1454 + if (likely(!sa.aad->error)) {
1455 + u16 audit_mask = profile->net.audit[sa.u.net->family];
1456 + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
1457 + !(1 << sa.aad->net.type & audit_mask)))
1459 + audit_type = AUDIT_APPARMOR_AUDIT;
1461 + u16 quiet_mask = profile->net.quiet[sa.u.net->family];
1462 + u16 kill_mask = 0;
1463 + u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
1465 + if (denied & kill_mask)
1466 + audit_type = AUDIT_APPARMOR_KILL;
1468 + if ((denied & quiet_mask) &&
1469 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1470 + AUDIT_MODE(profile) != AUDIT_ALL)
1471 + return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
1474 + return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
1478 + * aa_net_perm - very course network access check
1479 + * @op: operation being checked
1480 + * @profile: profile being enforced (NOT NULL)
1481 + * @family: network family
1482 + * @type: network type
1483 + * @protocol: network protocol
1485 + * Returns: %0 else error if permission denied
1487 +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
1488 + int protocol, struct sock *sk)
1493 + if ((family < 0) || (family >= AF_MAX))
1496 + if ((type < 0) || (type >= SOCK_MAX))
1499 + /* unix domain and netlink sockets are handled by ipc */
1500 + if (family == AF_UNIX || family == AF_NETLINK)
1503 + family_mask = profile->net.allow[family];
1505 + error = (family_mask & (1 << type)) ? 0 : -EACCES;
1507 + return audit_net(profile, op, family, type, protocol, sk, error);
1511 + * aa_revalidate_sk - Revalidate access to a sock
1512 + * @op: operation being checked
1513 + * @sk: sock being revalidated (NOT NULL)
1515 + * Returns: %0 else error if permission denied
1517 +int aa_revalidate_sk(int op, struct sock *sk)
1519 + struct aa_profile *profile;
1522 + /* aa_revalidate_sk should not be called from interrupt context
1523 + * don't mediate these calls as they are not task related
1525 + if (in_interrupt())
1528 + profile = __aa_current_profile();
1529 + if (!unconfined(profile))
1530 + error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
1531 + sk->sk_protocol, sk);
1535 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
1536 index 179e68d..f1a8541 100644
1537 --- a/security/apparmor/policy.c
1538 +++ b/security/apparmor/policy.c
1539 @@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile)
1541 aa_free_file_rules(&profile->file);
1542 aa_free_cap_rules(&profile->caps);
1543 + aa_free_net_rules(&profile->net);
1544 aa_free_rlimit_rules(&profile->rlimits);
1546 kzfree(profile->dirname);
1547 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
1548 index dac2121..0107bc4 100644
1549 --- a/security/apparmor/policy_unpack.c
1550 +++ b/security/apparmor/policy_unpack.c
1551 @@ -193,6 +193,19 @@ fail:
1555 +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
1557 + if (unpack_nameX(e, AA_U16, name)) {
1558 + if (!inbounds(e, sizeof(u16)))
1561 + *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
1562 + e->pos += sizeof(u16);
1568 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
1570 if (unpack_nameX(e, AA_U32, name)) {
1571 @@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
1573 struct aa_profile *profile = NULL;
1574 const char *name = NULL;
1576 int i, error = -EPROTO;
1577 kernel_cap_t tmpcap;
1579 @@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
1580 if (!unpack_rlimits(e, profile))
1583 + size = unpack_array(e, "net_allowed_af");
1586 + for (i = 0; i < size; i++) {
1587 + /* discard extraneous rules that this kernel will
1590 + if (i >= AF_MAX) {
1592 + if (!unpack_u16(e, &tmp, NULL) ||
1593 + !unpack_u16(e, &tmp, NULL) ||
1594 + !unpack_u16(e, &tmp, NULL))
1598 + if (!unpack_u16(e, &profile->net.allow[i], NULL))
1600 + if (!unpack_u16(e, &profile->net.audit[i], NULL))
1602 + if (!unpack_u16(e, &profile->net.quiet[i], NULL))
1605 + if (!unpack_nameX(e, AA_ARRAYEND, NULL))
1609 + * allow unix domain and netlink sockets they are handled
1612 + profile->net.allow[AF_UNIX] = 0xffff;
1613 + profile->net.allow[AF_NETLINK] = 0xffff;
1615 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
1616 /* generic policy dfa - optional and may be NULL */
1617 profile->policy.dfa = unpack_dfa(e);
1619 commit 64c5e24470a219c79c2870c63f18f6bd55648b1b
1620 Author: John Johansen <john.johansen@canonical.com>
1621 Date: Fri Jun 29 17:34:00 2012 -0700
1623 apparmor: Fix quieting of audit messages for network mediation
1625 If a profile specified a quieting of network denials for a given rule by
1626 either the quiet or deny rule qualifiers, the resultant quiet mask for
1627 denied requests was applied incorrectly, resulting in two potential bugs.
1628 1. The misapplied quiet mask would prevent denials from being correctly
1629 tested against the kill mask/mode. Thus network access requests that
1630 should have resulted in the application being killed did not.
1632 2. The actual quieting of the denied network request was not being applied.
1633 This would result in network rejections always being logged even when
1634 they had been specifically marked as quieted.
1636 Signed-off-by: John Johansen <john.johansen@canonical.com>
1638 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
1639 index 003dd18..6e6e5c9 100644
1640 --- a/security/apparmor/net.c
1641 +++ b/security/apparmor/net.c
1642 @@ -88,7 +88,7 @@ static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
1644 u16 quiet_mask = profile->net.quiet[sa.u.net->family];
1646 - u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
1647 + u16 denied = (1 << sa.aad->net.type);
1649 if (denied & kill_mask)
1650 audit_type = AUDIT_APPARMOR_KILL;
1652 commit f7cef61751a2382fb4ea26c18736d7552ffdb24a
1653 Author: John Johansen <john.johansen@canonical.com>
1654 Date: Wed May 16 10:58:05 2012 -0700
1656 UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
1658 Add the ability for apparmor to do mediation of mount operations. Mount
1659 rules require an updated apparmor_parser (2.8 series) for policy compilation.
1661 The basic form of the rules are.
1663 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
1664 [audit] [deny] remount [conds]* [path],
1665 [audit] [deny] umount [conds]* [path],
1666 [audit] [deny] pivotroot [oldroot=<value>] <path>
1668 remount is just a short cut for mount options=remount
1670 where [conds] can be
1674 Example mount commands
1675 mount, # allow all mounts, but not umount or pivotroot
1677 mount fstype=procfs, # allow mounting procfs anywhere
1679 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
1681 mount /dev/sda -> /mnt,
1683 mount /dev/sd** -> /mnt/**,
1685 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
1691 See the apparmor userspace for full documentation
1693 Signed-off-by: John Johansen <john.johansen@canonical.com>
1694 Acked-by: Kees Cook <kees@ubuntu.com>
1696 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
1697 index 5dbb72f..89b3445 100644
1698 --- a/security/apparmor/Makefile
1699 +++ b/security/apparmor/Makefile
1700 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
1702 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
1703 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
1704 - resource.o sid.o file.o net.o
1705 + resource.o sid.o file.o net.o mount.o
1706 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
1708 clean-files := capability_names.h rlim_names.h net_names.h
1709 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
1710 index 181d961..5fb67f6 100644
1711 --- a/security/apparmor/apparmorfs.c
1712 +++ b/security/apparmor/apparmorfs.c
1713 @@ -800,7 +800,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
1715 static struct aa_fs_entry aa_fs_entry_policy[] = {
1716 AA_FS_FILE_BOOLEAN("set_load", 1),
1721 +static struct aa_fs_entry aa_fs_entry_mount[] = {
1722 + AA_FS_FILE_STRING("mask", "mount umount"),
1726 +static struct aa_fs_entry aa_fs_entry_namespaces[] = {
1727 + AA_FS_FILE_BOOLEAN("profile", 1),
1728 + AA_FS_FILE_BOOLEAN("pivot_root", 1),
1732 static struct aa_fs_entry aa_fs_entry_features[] = {
1733 @@ -808,6 +819,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
1734 AA_FS_DIR("domain", aa_fs_entry_domain),
1735 AA_FS_DIR("file", aa_fs_entry_file),
1736 AA_FS_DIR("network", aa_fs_entry_network),
1737 + AA_FS_DIR("mount", aa_fs_entry_mount),
1738 + AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
1739 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
1740 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
1741 AA_FS_DIR("caps", aa_fs_entry_caps),
1742 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
1743 index 3a7f1da..c2a8b8a 100644
1744 --- a/security/apparmor/audit.c
1745 +++ b/security/apparmor/audit.c
1746 @@ -44,6 +44,10 @@ const char *const op_table[] = {
1757 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
1758 index fc3036b..f2a83b4 100644
1759 --- a/security/apparmor/domain.c
1760 +++ b/security/apparmor/domain.c
1761 @@ -236,7 +236,7 @@ static const char *next_name(int xtype, const char *name)
1763 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
1765 -static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
1766 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
1768 struct aa_profile *new_profile = NULL;
1769 struct aa_namespace *ns = profile->ns;
1770 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
1771 index e4ea626..ce6ff6a 100644
1772 --- a/security/apparmor/include/apparmor.h
1773 +++ b/security/apparmor/include/apparmor.h
1775 #define AA_CLASS_NET 4
1776 #define AA_CLASS_RLIMITS 5
1777 #define AA_CLASS_DOMAIN 6
1778 +#define AA_CLASS_MOUNT 7
1780 -#define AA_CLASS_LAST AA_CLASS_DOMAIN
1781 +#define AA_CLASS_LAST AA_CLASS_MOUNT
1783 /* Control parameters settable through module/boot flags */
1784 extern enum audit_mode aa_g_audit;
1785 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
1786 index 5d3c419..b9f1d57 100644
1787 --- a/security/apparmor/include/audit.h
1788 +++ b/security/apparmor/include/audit.h
1789 @@ -72,6 +72,10 @@ enum aa_ops {
1800 @@ -120,6 +124,13 @@ struct apparmor_audit_data {
1804 + const char *src_name;
1806 + const char *trans;
1808 + unsigned long flags;
1814 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
1815 index de04464..a3f70c5 100644
1816 --- a/security/apparmor/include/domain.h
1817 +++ b/security/apparmor/include/domain.h
1818 @@ -23,6 +23,8 @@ struct aa_domain {
1822 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
1824 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
1825 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
1826 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
1827 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
1828 new file mode 100644
1829 index 0000000..a43b1d6
1831 +++ b/security/apparmor/include/mount.h
1834 + * AppArmor security module
1836 + * This file contains AppArmor file mediation function definitions.
1838 + * Copyright 2012 Canonical Ltd.
1840 + * This program is free software; you can redistribute it and/or
1841 + * modify it under the terms of the GNU General Public License as
1842 + * published by the Free Software Foundation, version 2 of the
1846 +#ifndef __AA_MOUNT_H
1847 +#define __AA_MOUNT_H
1849 +#include <linux/fs.h>
1850 +#include <linux/path.h>
1852 +#include "domain.h"
1853 +#include "policy.h"
1856 +#define AA_MAY_PIVOTROOT 0x01
1857 +#define AA_MAY_MOUNT 0x02
1858 +#define AA_MAY_UMOUNT 0x04
1859 +#define AA_AUDIT_DATA 0x40
1860 +#define AA_CONT_MATCH 0x40
1862 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
1864 +int aa_remount(struct aa_profile *profile, const struct path *path,
1865 + unsigned long flags, void *data);
1867 +int aa_bind_mount(struct aa_profile *profile, const struct path *path,
1868 + const char *old_name, unsigned long flags);
1871 +int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
1872 + unsigned long flags);
1874 +int aa_move_mount(struct aa_profile *profile, const struct path *path,
1875 + const char *old_name);
1877 +int aa_new_mount(struct aa_profile *profile, const char *dev_name,
1878 + const struct path *path, const char *type, unsigned long flags,
1881 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
1883 +int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
1884 + const struct path *new_path);
1886 +#endif /* __AA_MOUNT_H */
1887 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1888 index 88d3b0a..432cbd3 100644
1889 --- a/security/apparmor/lsm.c
1890 +++ b/security/apparmor/lsm.c
1892 #include "include/path.h"
1893 #include "include/policy.h"
1894 #include "include/procattr.h"
1895 +#include "include/mount.h"
1897 /* Flag indicating whether initialization completed */
1898 int apparmor_initialized __initdata;
1899 @@ -469,6 +470,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1900 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1903 +static int apparmor_sb_mount(const char *dev_name, const struct path *path,
1904 + const char *type, unsigned long flags, void *data)
1906 + struct aa_profile *profile;
1909 + /* Discard magic */
1910 + if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1911 + flags &= ~MS_MGC_MSK;
1913 + flags &= ~AA_MS_IGNORE_MASK;
1915 + profile = __aa_current_profile();
1916 + if (!unconfined(profile)) {
1917 + if (flags & MS_REMOUNT)
1918 + error = aa_remount(profile, path, flags, data);
1919 + else if (flags & MS_BIND)
1920 + error = aa_bind_mount(profile, path, dev_name, flags);
1921 + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
1923 + error = aa_mount_change_type(profile, path, flags);
1924 + else if (flags & MS_MOVE)
1925 + error = aa_move_mount(profile, path, dev_name);
1927 + error = aa_new_mount(profile, dev_name, path, type,
1933 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
1935 + struct aa_profile *profile;
1938 + profile = __aa_current_profile();
1939 + if (!unconfined(profile))
1940 + error = aa_umount(profile, mnt, flags);
1945 +static int apparmor_sb_pivotroot(const struct path *old_path,
1946 + const struct path *new_path)
1948 + struct aa_profile *profile;
1951 + profile = __aa_current_profile();
1952 + if (!unconfined(profile))
1953 + error = aa_pivotroot(profile, old_path, new_path);
1958 static int apparmor_getprocattr(struct task_struct *task, char *name,
1961 @@ -689,6 +745,10 @@ static struct security_hook_list apparmor_hooks[] = {
1962 LSM_HOOK_INIT(capget, apparmor_capget),
1963 LSM_HOOK_INIT(capable, apparmor_capable),
1965 + LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
1966 + LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
1967 + LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
1969 LSM_HOOK_INIT(path_link, apparmor_path_link),
1970 LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
1971 LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
1972 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
1973 new file mode 100644
1974 index 0000000..9cf9170
1976 +++ b/security/apparmor/mount.c
1979 + * AppArmor security module
1981 + * This file contains AppArmor mediation of files
1983 + * Copyright (C) 1998-2008 Novell/SUSE
1984 + * Copyright 2009-2012 Canonical Ltd.
1986 + * This program is free software; you can redistribute it and/or
1987 + * modify it under the terms of the GNU General Public License as
1988 + * published by the Free Software Foundation, version 2 of the
1992 +#include <linux/fs.h>
1993 +#include <linux/mount.h>
1994 +#include <linux/namei.h>
1996 +#include "include/apparmor.h"
1997 +#include "include/audit.h"
1998 +#include "include/context.h"
1999 +#include "include/domain.h"
2000 +#include "include/file.h"
2001 +#include "include/match.h"
2002 +#include "include/mount.h"
2003 +#include "include/path.h"
2004 +#include "include/policy.h"
2007 +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
2009 + if (flags & MS_RDONLY)
2010 + audit_log_format(ab, "ro");
2012 + audit_log_format(ab, "rw");
2013 + if (flags & MS_NOSUID)
2014 + audit_log_format(ab, ", nosuid");
2015 + if (flags & MS_NODEV)
2016 + audit_log_format(ab, ", nodev");
2017 + if (flags & MS_NOEXEC)
2018 + audit_log_format(ab, ", noexec");
2019 + if (flags & MS_SYNCHRONOUS)
2020 + audit_log_format(ab, ", sync");
2021 + if (flags & MS_REMOUNT)
2022 + audit_log_format(ab, ", remount");
2023 + if (flags & MS_MANDLOCK)
2024 + audit_log_format(ab, ", mand");
2025 + if (flags & MS_DIRSYNC)
2026 + audit_log_format(ab, ", dirsync");
2027 + if (flags & MS_NOATIME)
2028 + audit_log_format(ab, ", noatime");
2029 + if (flags & MS_NODIRATIME)
2030 + audit_log_format(ab, ", nodiratime");
2031 + if (flags & MS_BIND)
2032 + audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
2033 + if (flags & MS_MOVE)
2034 + audit_log_format(ab, ", move");
2035 + if (flags & MS_SILENT)
2036 + audit_log_format(ab, ", silent");
2037 + if (flags & MS_POSIXACL)
2038 + audit_log_format(ab, ", acl");
2039 + if (flags & MS_UNBINDABLE)
2040 + audit_log_format(ab, flags & MS_REC ? ", runbindable" :
2042 + if (flags & MS_PRIVATE)
2043 + audit_log_format(ab, flags & MS_REC ? ", rprivate" :
2045 + if (flags & MS_SLAVE)
2046 + audit_log_format(ab, flags & MS_REC ? ", rslave" :
2048 + if (flags & MS_SHARED)
2049 + audit_log_format(ab, flags & MS_REC ? ", rshared" :
2051 + if (flags & MS_RELATIME)
2052 + audit_log_format(ab, ", relatime");
2053 + if (flags & MS_I_VERSION)
2054 + audit_log_format(ab, ", iversion");
2055 + if (flags & MS_STRICTATIME)
2056 + audit_log_format(ab, ", strictatime");
2057 + if (flags & MS_NOUSER)
2058 + audit_log_format(ab, ", nouser");
2062 + * audit_cb - call back for mount specific audit fields
2063 + * @ab: audit_buffer (NOT NULL)
2064 + * @va: audit struct to audit values of (NOT NULL)
2066 +static void audit_cb(struct audit_buffer *ab, void *va)
2068 + struct common_audit_data *sa = va;
2070 + if (sa->aad->mnt.type) {
2071 + audit_log_format(ab, " fstype=");
2072 + audit_log_untrustedstring(ab, sa->aad->mnt.type);
2074 + if (sa->aad->mnt.src_name) {
2075 + audit_log_format(ab, " srcname=");
2076 + audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
2078 + if (sa->aad->mnt.trans) {
2079 + audit_log_format(ab, " trans=");
2080 + audit_log_untrustedstring(ab, sa->aad->mnt.trans);
2082 + if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
2083 + audit_log_format(ab, " flags=\"");
2084 + audit_mnt_flags(ab, sa->aad->mnt.flags);
2085 + audit_log_format(ab, "\"");
2087 + if (sa->aad->mnt.data) {
2088 + audit_log_format(ab, " options=");
2089 + audit_log_untrustedstring(ab, sa->aad->mnt.data);
2094 + * audit_mount - handle the auditing of mount operations
2095 + * @profile: the profile being enforced (NOT NULL)
2096 + * @gfp: allocation flags
2097 + * @op: operation being mediated (NOT NULL)
2098 + * @name: name of object being mediated (MAYBE NULL)
2099 + * @src_name: src_name of object being mediated (MAYBE_NULL)
2100 + * @type: type of filesystem (MAYBE_NULL)
2101 + * @trans: name of trans (MAYBE NULL)
2102 + * @flags: filesystem idependent mount flags
2103 + * @data: filesystem mount flags
2104 + * @request: permissions requested
2105 + * @perms: the permissions computed for the request (NOT NULL)
2106 + * @info: extra information message (MAYBE NULL)
2107 + * @error: 0 if operation allowed else failure error code
2109 + * Returns: %0 or error on failure
2111 +static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
2112 + const char *name, const char *src_name,
2113 + const char *type, const char *trans,
2114 + unsigned long flags, const void *data, u32 request,
2115 + struct file_perms *perms, const char *info, int error)
2117 + int audit_type = AUDIT_APPARMOR_AUTO;
2118 + struct common_audit_data sa = { };
2119 + struct apparmor_audit_data aad = { };
2121 + if (likely(!error)) {
2122 + u32 mask = perms->audit;
2124 + if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
2127 + /* mask off perms that are not being force audited */
2130 + if (likely(!request))
2132 + audit_type = AUDIT_APPARMOR_AUDIT;
2134 + /* only report permissions that were denied */
2135 + request = request & ~perms->allow;
2137 + if (request & perms->kill)
2138 + audit_type = AUDIT_APPARMOR_KILL;
2140 + /* quiet known rejects, assumes quiet and kill do not overlap */
2141 + if ((request & perms->quiet) &&
2142 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
2143 + AUDIT_MODE(profile) != AUDIT_ALL)
2144 + request &= ~perms->quiet;
2147 + return COMPLAIN_MODE(profile) ?
2148 + complain_error(error) : error;
2151 + sa.type = LSM_AUDIT_DATA_NONE;
2154 + sa.aad->name = name;
2155 + sa.aad->mnt.src_name = src_name;
2156 + sa.aad->mnt.type = type;
2157 + sa.aad->mnt.trans = trans;
2158 + sa.aad->mnt.flags = flags;
2159 + if (data && (perms->audit & AA_AUDIT_DATA))
2160 + sa.aad->mnt.data = data;
2161 + sa.aad->info = info;
2162 + sa.aad->error = error;
2164 + return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
2168 + * match_mnt_flags - Do an ordered match on mount flags
2169 + * @dfa: dfa to match against
2170 + * @state: state to start in
2171 + * @flags: mount flags to match against
2173 + * Mount flags are encoded as an ordered match. This is done instead of
2174 + * checking against a simple bitmask, to allow for logical operations
2177 + * Returns: next state after flags match
2179 +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
2180 + unsigned long flags)
2184 + for (i = 0; i <= 31 ; ++i) {
2185 + if ((1 << i) & flags)
2186 + state = aa_dfa_next(dfa, state, i + 1);
2193 + * compute_mnt_perms - compute mount permission associated with @state
2194 + * @dfa: dfa to match against (NOT NULL)
2195 + * @state: state match finished in
2197 + * Returns: mount permissions
2199 +static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
2200 + unsigned int state)
2202 + struct file_perms perms;
2205 + perms.allow = dfa_user_allow(dfa, state);
2206 + perms.audit = dfa_user_audit(dfa, state);
2207 + perms.quiet = dfa_user_quiet(dfa, state);
2208 + perms.xindex = dfa_user_xindex(dfa, state);
2213 +static const char const *mnt_info_table[] = {
2214 + "match succeeded",
2215 + "failed mntpnt match",
2216 + "failed srcname match",
2217 + "failed type match",
2218 + "failed flags match",
2219 + "failed data match"
2223 + * Returns 0 on success else element that match failed in, this is the
2224 + * index into the mnt_info_table above
2226 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
2227 + const char *mntpnt, const char *devname,
2228 + const char *type, unsigned long flags,
2229 + void *data, bool binary, struct file_perms *perms)
2231 + unsigned int state;
2233 + state = aa_dfa_match(dfa, start, mntpnt);
2234 + state = aa_dfa_null_transition(dfa, state);
2239 + state = aa_dfa_match(dfa, state, devname);
2240 + state = aa_dfa_null_transition(dfa, state);
2245 + state = aa_dfa_match(dfa, state, type);
2246 + state = aa_dfa_null_transition(dfa, state);
2250 + state = match_mnt_flags(dfa, state, flags);
2253 + *perms = compute_mnt_perms(dfa, state);
2254 + if (perms->allow & AA_MAY_MOUNT)
2257 + /* only match data if not binary and the DFA flags data is expected */
2258 + if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
2259 + state = aa_dfa_null_transition(dfa, state);
2263 + state = aa_dfa_match(dfa, state, data);
2266 + *perms = compute_mnt_perms(dfa, state);
2267 + if (perms->allow & AA_MAY_MOUNT)
2271 + /* failed at end of flags match */
2276 + * match_mnt - handle path matching for mount
2277 + * @profile: the confining profile
2278 + * @mntpnt: string for the mntpnt (NOT NULL)
2279 + * @devname: string for the devname/src_name (MAYBE NULL)
2280 + * @type: string for the dev type (MAYBE NULL)
2281 + * @flags: mount flags to match
2282 + * @data: fs mount data (MAYBE NULL)
2283 + * @binary: whether @data is binary
2284 + * @perms: Returns: permission found by the match
2285 + * @info: Returns: infomation string about the match for logging
2287 + * Returns: 0 on success else error
2289 +static int match_mnt(struct aa_profile *profile, const char *mntpnt,
2290 + const char *devname, const char *type,
2291 + unsigned long flags, void *data, bool binary,
2292 + struct file_perms *perms, const char **info)
2296 + if (!profile->policy.dfa)
2299 + pos = do_match_mnt(profile->policy.dfa,
2300 + profile->policy.start[AA_CLASS_MOUNT],
2301 + mntpnt, devname, type, flags, data, binary, perms);
2303 + *info = mnt_info_table[pos];
2310 +static int path_flags(struct aa_profile *profile, const struct path *path)
2312 + return profile->path_flags |
2313 + S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
2316 +int aa_remount(struct aa_profile *profile, const struct path *path,
2317 + unsigned long flags, void *data)
2319 + struct file_perms perms = { };
2320 + const char *name, *info = NULL;
2321 + char *buffer = NULL;
2322 + int binary, error;
2324 + binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
2326 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2331 + error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
2335 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
2336 + NULL, flags, data, AA_MAY_MOUNT, &perms, info,
2343 +int aa_bind_mount(struct aa_profile *profile, const struct path *path,
2344 + const char *dev_name, unsigned long flags)
2346 + struct file_perms perms = { };
2347 + char *buffer = NULL, *old_buffer = NULL;
2348 + const char *name, *old_name = NULL, *info = NULL;
2349 + struct path old_path;
2352 + if (!dev_name || !*dev_name)
2355 + flags &= MS_REC | MS_BIND;
2357 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2362 + error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
2366 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
2367 + &old_buffer, &old_name, &info);
2368 + path_put(&old_path);
2372 + error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
2376 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
2377 + NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
2380 + kfree(old_buffer);
2385 +int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
2386 + unsigned long flags)
2388 + struct file_perms perms = { };
2389 + char *buffer = NULL;
2390 + const char *name, *info = NULL;
2393 + /* These are the flags allowed by do_change_type() */
2394 + flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
2397 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2402 + error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
2406 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
2407 + NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
2414 +int aa_move_mount(struct aa_profile *profile, const struct path *path,
2415 + const char *orig_name)
2417 + struct file_perms perms = { };
2418 + char *buffer = NULL, *old_buffer = NULL;
2419 + const char *name, *old_name = NULL, *info = NULL;
2420 + struct path old_path;
2423 + if (!orig_name || !*orig_name)
2426 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2431 + error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
2435 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
2436 + &old_buffer, &old_name, &info);
2437 + path_put(&old_path);
2441 + error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
2445 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
2446 + NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
2449 + kfree(old_buffer);
2454 +int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
2455 + const struct path *path, const char *type, unsigned long flags,
2458 + struct file_perms perms = { };
2459 + char *buffer = NULL, *dev_buffer = NULL;
2460 + const char *name = NULL, *dev_name = NULL, *info = NULL;
2464 + dev_name = orig_dev_name;
2467 + struct file_system_type *fstype = get_fs_type(type);
2471 + binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
2472 + requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
2473 + put_filesystem(fstype);
2475 + if (requires_dev) {
2476 + struct path dev_path;
2478 + if (!dev_name || !*dev_name) {
2483 + error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
2487 + error = aa_path_name(&dev_path,
2488 + path_flags(profile, &dev_path),
2489 + &dev_buffer, &dev_name, &info);
2490 + path_put(&dev_path);
2496 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2501 + error = match_mnt(profile, name, dev_name, type, flags, data, binary,
2505 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
2506 + type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
2509 + kfree(dev_buffer);
2516 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
2518 + struct file_perms perms = { };
2519 + char *buffer = NULL;
2520 + const char *name, *info = NULL;
2523 + struct path path = { mnt, mnt->mnt_root };
2524 + error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
2529 + if (!error && profile->policy.dfa) {
2530 + unsigned int state;
2531 + state = aa_dfa_match(profile->policy.dfa,
2532 + profile->policy.start[AA_CLASS_MOUNT],
2534 + perms = compute_mnt_perms(profile->policy.dfa, state);
2537 + if (AA_MAY_UMOUNT & ~perms.allow)
2541 + error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
2542 + NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
2548 +int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
2549 + const struct path *new_path)
2551 + struct file_perms perms = { };
2552 + struct aa_profile *target = NULL;
2553 + char *old_buffer = NULL, *new_buffer = NULL;
2554 + const char *old_name, *new_name = NULL, *info = NULL;
2557 + error = aa_path_name(old_path, path_flags(profile, old_path),
2558 + &old_buffer, &old_name, &info);
2562 + error = aa_path_name(new_path, path_flags(profile, new_path),
2563 + &new_buffer, &new_name, &info);
2567 + if (profile->policy.dfa) {
2568 + unsigned int state;
2569 + state = aa_dfa_match(profile->policy.dfa,
2570 + profile->policy.start[AA_CLASS_MOUNT],
2572 + state = aa_dfa_null_transition(profile->policy.dfa, state);
2573 + state = aa_dfa_match(profile->policy.dfa, state, old_name);
2574 + perms = compute_mnt_perms(profile->policy.dfa, state);
2577 + if (AA_MAY_PIVOTROOT & perms.allow) {
2578 + if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
2579 + target = x_table_lookup(profile, perms.xindex);
2583 + error = aa_replace_current_profile(target);
2589 + error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
2590 + old_name, NULL, target ? target->base.name : NULL,
2591 + 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
2592 + aa_put_profile(target);
2593 + kfree(old_buffer);
2594 + kfree(new_buffer);