]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-apparmor.patch
- up to 4.7.1
[packages/kernel.git] / kernel-apparmor.patch
CommitLineData
0776672e
AM
1commit 5ea33f587f5f7324c40c5986286d0f38307923bb
2Author: John Johansen <john.johansen@canonical.com>
3Date: Mon Apr 11 16:55:10 2016 -0700
1e8b8f9b 4
0776672e
AM
5 apparmor: fix refcount bug in profile replacement
6
7 Signed-off-by: John Johansen <john.johansen@canonical.com>
8 Acked-by: Seth Arnold <seth.arnold@canonical.com>
76514441 9
0776672e
AM
10diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
11index 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);
18- } else
19- aa_put_profile(newest);
20+ }
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);
26 } else {
27 /* aafs interface uses replacedby */
28 rcu_assign_pointer(ent->new->replacedby->profile,
29
30commit f65b1c9b72442e6166332c04f332e4b4d4797887
31Author: John Johansen <john.johansen@canonical.com>
32Date: Mon Apr 11 16:57:19 2016 -0700
33
34 apparmor: fix replacement bug that adds new child to old parent
35
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
41 following error.
42
43 AppArmor: policy_destroy: internal error, policy '<profile/name>' still
44 contains profiles
45
46 Signed-off-by: John Johansen <john.johansen@canonical.com>
47 Acked-by: Seth Arnold <seth.arnold@canonical.com>
48
49diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
50index 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);
60 } else {
61 /* aafs interface uses replacedby */
62
63commit b6669bef20c9d934bc6498e79fffa220f6226518
64Author: John Johansen <john.johansen@canonical.com>
65Date: Sun Jun 8 11:20:54 2014 -0700
66
67 apparmor: fix uninitialized lsm_audit member
68
69 BugLink: http://bugs.launchpad.net/bugs/1268727
70
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
73
74 BUG: unable to handle kernel paging request at 0000002fbead7d08
75 IP: [<ffffffff8171153e>] _raw_spin_lock+0xe/0x50
76 PGD 1e3f35067 PUD 0
77 Oops: 0002 [#1] SMP
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
92 Stack:
93 ffff880212987b98 ffffffff81075f17 ffffffff8130966f 0000000000000009
94 0000000000000000 0000000000000000 ffff880212987bd0 ffffffff81075f7c
95 0000000000000292 ffff880212987c08 ffff8800d8c6b800 0000000000000026
96 Call Trace:
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
112
113 Signed-off-by: John Johansen <john.johansen@canonical.com>
114 Acked-by: Seth Arnold <seth.arnold@canonical.com>
115
116diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
117index 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,
121
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);
127
128 if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
129 return complain_error(sa->aad->error);
130diff --git a/security/apparmor/file.c b/security/apparmor/file.c
131index 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;
140+ sa.u.tsk = NULL;
141 sa.aad = &aad;
142 aad.op = op,
143 aad.fs.request = request;
144
145commit aeab4cbfb86d0faeeb709e8201672e0662aa2c6f
146Author: John Johansen <john.johansen@canonical.com>
147Date: Fri Jul 25 04:02:03 2014 -0700
148
149 apparmor: exec should not be returning ENOENT when it denies
150
151 The current behavior is confusing as it causes exec failures to report
152 the executable is missing instead of identifying that apparmor
153 caused the failure.
154
155 Signed-off-by: John Johansen <john.johansen@canonical.com>
156 Acked-by: Seth Arnold <seth.arnold@canonical.com>
157
158diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
159index 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";
165 } else {
166- error = -ENOENT;
167+ error = -EACCES;
168 info = "profile not found";
169 /* remove MAY_EXEC to audit as failure */
170 perms.allow &= ~MAY_EXEC;
171
172commit 752e4263021d90cf23c262f2fd3ebfd6dbccd455
173Author: John Johansen <john.johansen@canonical.com>
174Date: Fri Jul 25 04:01:56 2014 -0700
175
176 apparmor: fix update the mtime of the profile file on replacement
177
178 Signed-off-by: John Johansen <john.johansen@canonical.com>
179 Acked-by: Seth Arnold <seth.arnold@canonical.com>
180
181diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
182index 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,
186
187 for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
188 new->dents[i] = old->dents[i];
189+ if (new->dents[i])
190+ new->dents[i]->d_inode->i_mtime = CURRENT_TIME;
191 old->dents[i] = NULL;
192 }
193 }
194
195commit 0c67233b18406dc7a8629faf8f9452feace6fb13
196Author: John Johansen <john.johansen@canonical.com>
197Date: Fri Jul 25 04:02:08 2014 -0700
198
199 apparmor: fix disconnected bind mnts reconnection
200
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
203 a root.
204
205 BugLink: http://bugs.launchpad.net/bugs/1319984
206
207 Signed-off-by: John Johansen <john.johansen@canonical.com>
208 Acked-by: Seth Arnold <seth.arnold@canonical.com>
209
210diff --git a/security/apparmor/path.c b/security/apparmor/path.c
211index 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,
215 error = -EACCES;
216 if (*res == '/')
217 *name = res + 1;
218- }
219+ } else if (*res != '/')
220+ /* CONNECT_PATH with missing root */
221+ error = prepend(name, *name - buf, "/", 1);
222+
223 }
224
225 out:
226
227commit 30c2b759b4f456e97e859ca550666c8abe84ff3c
228Author: John Johansen <john.johansen@canonical.com>
229Date: Fri Jul 25 04:02:10 2014 -0700
230
231 apparmor: internal paths should be treated as disconnected
232
233 Internal mounts are not mounted anywhere and as such should be treated
234 as disconnected paths.
235
236 Signed-off-by: John Johansen <john.johansen@canonical.com>
237 Acked-by: Seth Arnold <seth.arnold@canonical.com>
238
239diff --git a/security/apparmor/path.c b/security/apparmor/path.c
240index f261678..a8fc7d0 100644
241--- a/security/apparmor/path.c
242+++ b/security/apparmor/path.c
243@@ -25,7 +25,6 @@
244 #include "include/path.h"
245 #include "include/policy.h"
246
247-
248 /* modified from dcache.c */
249 static int prepend(char **buffer, int buflen, const char *str, int namelen)
250 {
251@@ -39,6 +38,38 @@ static int prepend(char **buffer, int buflen, const char *str, int namelen)
252
253 #define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
254
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.
258+ * Unless
259+ * specifically directed to connect the path,
260+ * OR
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
264+ * namespace root.
265+ */
266+static int disconnect(const struct path *path, char *buf, char **name,
267+ int flags)
268+{
269+ int error = 0;
270+
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
275+ * with '/'
276+ */
277+ error = -EACCES;
278+ if (**name == '/')
279+ *name = *name + 1;
280+ } else if (**name != '/')
281+ /* CONNECT_PATH with missing root */
282+ error = prepend(name, *name - buf, "/", 1);
283+
284+ return error;
285+}
286+
287 /**
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
292 */
293 return prepend(name, *name - buf, "/proc", 5);
294- }
295+ } else
296+ return disconnect(path, buf, name, flags);
297 return 0;
298 }
299
300@@ -120,32 +152,8 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
301 goto out;
302 }
303
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.
307- * Unless
308- * specifically directed to connect the path,
309- * OR
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
313- * namespace root.
314- */
315- if (!connected) {
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
320- * with '/'
321- */
322- error = -EACCES;
323- if (*res == '/')
324- *name = res + 1;
325- } else if (*res != '/')
326- /* CONNECT_PATH with missing root */
327- error = prepend(name, *name - buf, "/", 1);
328-
329- }
330+ if (!connected)
331+ error = disconnect(path, buf, name, flags);
332
333 out:
334 return error;
335
336commit 35f89b597a40c870f93a068bc92a7ef4f9b16a66
337Author: John Johansen <john.johansen@canonical.com>
338Date: Sat Apr 16 13:59:02 2016 -0700
339
340 apparmor: fix put() parent ref after updating the active ref
341
342 Signed-off-by: John Johansen <john.johansen@canonical.com>
343 Acked-by: Seth Arnold <seth.arnold@canonical.com>
344
345diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
346index 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);
356 }
357 /* aafs interface uses replacedby */
358 rcu_assign_pointer(ent->new->replacedby->profile,
359
360commit 7b1ec6a04ca57fabe250f1102f2803dea7fbd03b
361Author: John Johansen <john.johansen@canonical.com>
362Date: Sat Apr 16 14:16:50 2016 -0700
363
364 apparmor: fix log failures for all profiles in a set
365
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.
370
371 Signed-off-by: John Johansen <john.johansen@canonical.com>
372 Acked-by: Seth Arnold <seth.arnold@canonical.com>
373
374diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
375index 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,
379 */
380 ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
381 {
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)
388 /* released below */
389 ns = aa_prepare_namespace(ns_name);
390 if (!ns) {
391- info = "failed to prepare namespace";
392- error = -ENOMEM;
393- name = ns_name;
394- goto fail;
395+ error = audit_policy(op, GFP_KERNEL, ns_name,
396+ "failed to prepare namespace", -ENOMEM);
397+ goto free;
398 }
399
400 mutex_lock(&ns->lock);
401 /* setup parent and ns info */
402 list_for_each_entry(ent, &lh, list) {
403 struct aa_policy *policy;
404-
405- name = ent->new->base.hname;
406 error = __lookup_replace(ns, ent->new->base.hname, noreplace,
407 &ent->old, &info);
408 if (error)
409@@ -1121,7 +1118,6 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
410 if (!p) {
411 error = -ENOENT;
412 info = "parent does not exist";
413- name = ent->new->base.hname;
414 goto fail_lock;
415 }
416 rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
417@@ -1214,9 +1210,22 @@ out:
418
419 fail_lock:
420 mutex_unlock(&ns->lock);
421-fail:
422- error = audit_policy(op, GFP_KERNEL, name, info, error);
423
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) {
430+ if (tmp == ent) {
431+ info = "unchecked profile in failed atomic policy load";
432+ /* skip entry that caused failure */
433+ continue;
434+ }
435+ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
436+ audit_policy(op, GFP_KERNEL, tmp->new->base.hname, info, error);
437+ }
438+free:
439 list_for_each_entry_safe(ent, tmp, &lh, list) {
440 list_del_init(&ent->list);
441 aa_load_ent_free(ent);
442
443commit 4c475747a31b0637f0d47cb9bddaf2c6efb02854
444Author: John Johansen <john.johansen@canonical.com>
445Date: Sat Apr 16 14:19:38 2016 -0700
446
447 apparmor: fix audit full profile hname on successful load
448
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.
453
454 Signed-off-by: John Johansen <john.johansen@canonical.com>
455 Acked-by: Seth Arnold <seth.arnold@canonical.com>
456
457diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
458index 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;
464
465- audit_policy(op, GFP_ATOMIC, ent->new->base.name, NULL, error);
466+ audit_policy(op, GFP_ATOMIC, ent->new->base.hname, NULL, error);
467
468 if (ent->old) {
469 __replace_profile(ent->old, ent->new, 1);
470
471commit 430741dd766291d2e618b04e918ee6da844c230a
472Author: John Johansen <john.johansen@canonical.com>
473Date: Wed Apr 20 14:18:18 2016 -0700
474
475 apparmor: ensure the target profile name is always audited
476
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:
480
481 Since it is always based on new_profile just drop the target var
482 and conditionally report based on new_profile.
483
484 Signed-off-by: John Johansen <john.johansen@canonical.com>
485 Acked-by: Seth Arnold <seth.arnold@canonical.com>
486
487diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
488index 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
494 };
495- const char *name = NULL, *target = NULL, *info = NULL;
496+ const char *name = NULL, *info = NULL;
497 int error = 0;
498
499 if (bprm->cred_prepared)
500@@ -399,6 +399,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
501 if (cxt->onexec) {
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))
506 goto audit;
507
508@@ -413,7 +414,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
509
510 if (!(cp.allow & AA_MAY_ONEXEC))
511 goto audit;
512- new_profile = aa_get_newest_profile(cxt->onexec);
513 goto apply;
514 }
515
516@@ -445,10 +445,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
517 if (!new_profile) {
518 error = -ENOMEM;
519 info = "could not create null profile";
520- } else {
521+ } else
522 error = -EACCES;
523- target = new_profile->base.hname;
524- }
525 perms.xindex |= AA_X_UNSAFE;
526 } else
527 /* fail exec */
528@@ -459,7 +457,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
529 * fail the exec.
530 */
531 if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) {
532- aa_put_profile(new_profile);
533 error = -EPERM;
534 goto cleanup;
535 }
536@@ -474,10 +471,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
537
538 if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
539 error = may_change_ptraced_domain(new_profile);
540- if (error) {
541- aa_put_profile(new_profile);
542+ if (error)
543 goto audit;
544- }
545 }
546
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;
550 }
551 apply:
552- target = new_profile->base.hname;
553 /* when transitioning profiles clear unsafe personality bits */
554 bprm->per_clear |= PER_CLEAR_ON_SETID;
555
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;
561
562 /* clear out all temporary/transitional state from the context */
563 aa_clear_task_cxt_trans(cxt);
564
565 audit:
566 error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
567- name, target, cond.uid, info, error);
568+ name,
569+ new_profile ? new_profile->base.hname : NULL,
570+ cond.uid, info, error);
571
572 cleanup:
573+ aa_put_profile(new_profile);
574 aa_put_profile(profile);
575 kfree(buffer);
576
577
578commit 06763d057300b3d5bbe1894acfe236cf193bab78
579Author: John Johansen <john.johansen@canonical.com>
580Date: Thu Mar 17 12:02:54 2016 -0700
581
582 apparmor: check that xindex is in trans_table bounds
583
584 Signed-off-by: John Johansen <john.johansen@canonical.com>
585 Acked-by: Seth Arnold <seth.arnold@canonical.com>
586
587diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
588index 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)
592 int index, xtype;
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)
597 return 0;
598 return 1;
599 }
600
0776672e
AM
601commit e13f968d154ba9d6a2c4f82f33d3312a63430b54
602Author: John Johansen <john.johansen@canonical.com>
603Date: Wed Dec 16 18:09:10 2015 -0800
604
605 apparmor: fix refcount race when finding a child profile
606
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.
610
611 Protect against this by repeating the lookup if the profiles refcount
612 is 0 and is one its way to deletion.
613
614 Signed-off-by: John Johansen <john.johansen@canonical.com>
615 Acked-by: Seth Arnold <seth.arnold@canonical.com>
616
617diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
618index 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;
623
624 rcu_read_lock();
625- profile = aa_get_profile(__find_child(&parent->base.profiles, name));
626+ do {
627+ profile = __find_child(&parent->base.profiles, name);
628+ } while (profile && !aa_get_profile_not0(profile));
629 rcu_read_unlock();
630
631 /* refcount released by caller */
632
633commit 5833ccff1227fbc8f1bab64351f6747a6c71bdeb
634Author: Geliang Tang <geliangtang@163.com>
635Date: Mon Nov 16 21:46:33 2015 +0800
636
637 apparmor: use list_next_entry instead of list_entry_next
638
639 list_next_entry has been defined in list.h, so I replace list_entry_next
640 with it.
641
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>
645
646diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
647index 0d8dd71..729e595 100644
648--- a/security/apparmor/apparmorfs.c
649+++ b/security/apparmor/apparmorfs.c
650@@ -553,8 +553,6 @@ fail2:
651 }
652
653
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))
657
658 /**
659@@ -585,7 +583,7 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root,
660 parent = ns->parent;
661 while (ns != 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);
667 return next;
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));
671 while (parent) {
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))
675 return p;
676 p = parent;
677@@ -648,7 +646,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
678 }
679
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))
684 return p;
685
686
687commit 645801f1ddd183109c011e5ecee23ed3fdcae244
688Author: Jeff Mahoney <jeffm@suse.com>
689Date: Fri Nov 6 15:17:30 2015 -0500
690
691 apparmor: allow SYS_CAP_RESOURCE to be sufficient to prlimit another task
692
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.
696
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
702
703 1), 2, and 3) are already true for setrlimit.
704
705 We can match the ptrace model just by allowing CAP_SYS_RESOURCE.
706
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.
709
710 Signed-off-by: Jeff Mahoney <jeffm@suse.com>
711 Signed-off-by: John Johansen <john.johansen@canonical.com>
712
713diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
714index 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.
724 */
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))
730 error = -EACCES;
731
732commit 2be4aed1f3332d87273eb593944332054f3cffac
733Author: John Johansen <john.johansen@canonical.com>
734Date: Thu Jun 2 02:37:02 2016 -0700
735
736 apparmor: add missing id bounds check on dfa verification
737
738 Signed-off-by: John Johansen <john.johansen@canonical.com>
739
740diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
741index 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
749
750 #define YYTD_DATA8 1
751 #define YYTD_DATA16 2
752diff --git a/security/apparmor/match.c b/security/apparmor/match.c
753index 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
758 */
759 th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
760+ if (th.td_id > YYTD_ID_MAX)
761+ goto out;
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);
765
766commit c7f87d3c3363b1a0c4724e627e5c8e640a883c89
767Author: John Johansen <john.johansen@canonical.com>
768Date: Wed Jun 15 09:57:55 2016 +0300
769
770 apparmor: don't check for vmalloc_addr if kvzalloc() failed
771
772 Signed-off-by: John Johansen <john.johansen@canonical.com>
773
774diff --git a/security/apparmor/match.c b/security/apparmor/match.c
775index 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)
779 u32, be32_to_cpu);
780 else
781 goto fail;
782+ /* if table was vmalloced make sure the page tables are synced
783+ * before it is used, as it goes live to all cpus.
784+ */
785+ if (is_vmalloc_addr(table))
786+ vm_unmap_aliases();
787 }
788
789 out:
790- /* if table was vmalloced make sure the page tables are synced
791- * before it is used, as it goes live to all cpus.
792- */
793- if (is_vmalloc_addr(table))
794- vm_unmap_aliases();
795 return table;
796 fail:
797 kvfree(table);
798
799commit 0f7e61013dd1e67ebb54d58eee11ab009ceb5ef3
800Author: John Johansen <john.johansen@canonical.com>
801Date: Wed Jun 15 10:00:55 2016 +0300
802
803 apparmor: fix oops in profile_unpack() when policy_db is not present
804
805 BugLink: http://bugs.launchpad.net/bugs/1592547
806
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).
809
810 Signed-off-by: John Johansen <john.johansen@canonical.com>
811
812diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
813index 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;
819 goto fail;
820+ } else if (!profile->policy.dfa) {
821+ error = -EPROTO;
822+ goto fail;
823 }
824 if (!unpack_u32(e, &profile->policy.start[0], "start"))
825 /* default start state */
826
827commit de4ca46ec035283928e8fa40797897cefcf6ec3e
828Author: John Johansen <john.johansen@canonical.com>
829Date: Wed Jun 22 18:01:08 2016 -0700
830
831 apparmor: fix module parameters can be changed after policy is locked
832
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.
836
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.
839
840 Signed-off-by: John Johansen <john.johansen@canonical.com>
841
842diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
843index 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;
848 }
849
850+bool policy_view_capable(void);
851+bool policy_admin_capable(void);
852 bool aa_may_manage_policy(int op);
853
854 #endif /* __AA_POLICY_H */
855diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
856index 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)
862 {
863- if (!capable(CAP_MAC_ADMIN))
864+ if (!policy_admin_capable())
865 return -EPERM;
866- if (aa_g_lock_policy)
867- return -EACCES;
868 return param_set_bool(val, kp);
869 }
870
871 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
872 {
873- if (!capable(CAP_MAC_ADMIN))
874+ if (!policy_view_capable())
875 return -EPERM;
876 return param_get_bool(buffer, kp);
877 }
878
879 static int param_set_aabool(const char *val, const struct kernel_param *kp)
880 {
881- if (!capable(CAP_MAC_ADMIN))
882+ if (!policy_admin_capable())
883 return -EPERM;
884 return param_set_bool(val, kp);
885 }
886
887 static int param_get_aabool(char *buffer, const struct kernel_param *kp)
888 {
889- if (!capable(CAP_MAC_ADMIN))
890+ if (!policy_view_capable())
891 return -EPERM;
892 return param_get_bool(buffer, kp);
893 }
894
895 static int param_set_aauint(const char *val, const struct kernel_param *kp)
896 {
897- if (!capable(CAP_MAC_ADMIN))
898+ if (!policy_admin_capable())
899 return -EPERM;
900 return param_set_uint(val, kp);
901 }
902
903 static int param_get_aauint(char *buffer, const struct kernel_param *kp)
904 {
905- if (!capable(CAP_MAC_ADMIN))
906+ if (!policy_view_capable())
907 return -EPERM;
908 return param_get_uint(buffer, kp);
909 }
910
911 static int param_get_audit(char *buffer, struct kernel_param *kp)
912 {
913- if (!capable(CAP_MAC_ADMIN))
914+ if (!policy_view_capable())
915 return -EPERM;
916
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)
920 {
921 int i;
922- if (!capable(CAP_MAC_ADMIN))
923+ if (!policy_admin_capable())
924 return -EPERM;
925
926 if (!apparmor_enabled)
927@@ -805,7 +803,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp)
928
929 static int param_get_mode(char *buffer, struct kernel_param *kp)
930 {
931- if (!capable(CAP_MAC_ADMIN))
932+ if (!policy_admin_capable())
933 return -EPERM;
934
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)
938 {
939 int i;
940- if (!capable(CAP_MAC_ADMIN))
941+ if (!policy_admin_capable())
942 return -EPERM;
943
944 if (!apparmor_enabled)
945diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
946index 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,
950 &sa, NULL);
951 }
952
953+bool policy_view_capable(void)
954+{
955+ struct user_namespace *user_ns = current_user_ns();
956+ bool response = false;
957+
958+ if (ns_capable(user_ns, CAP_MAC_ADMIN))
959+ response = true;
960+
961+ return response;
962+}
963+
964+bool policy_admin_capable(void)
965+{
966+ return policy_view_capable() && !aa_g_lock_policy;
967+}
968+
969 /**
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)
973 return 0;
974 }
975
976- if (!capable(CAP_MAC_ADMIN)) {
977+ if (!policy_admin_capable()) {
978 audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
979 return 0;
980 }
981
982commit 46c339f46b83e4cf8098f599cd182e65e9d054fc
983Author: Heinrich Schuchardt <xypron.glpk@gmx.de>
984Date: Fri Jun 10 23:34:26 2016 +0200
985
986 apparmor: do not expose kernel stack
987
988 Do not copy uninitalized fields th.td_hilen, th.td_data.
989
990 Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
991 Signed-off-by: John Johansen <john.johansen@canonical.com>
992
993diff --git a/security/apparmor/match.c b/security/apparmor/match.c
994index 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)
998
999 table = kvzalloc(tsize);
1000 if (table) {
1001- *table = th;
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,
1007 u8, byte_to_byte);
1008
1009commit 7e65e8142b2ea4891581173d6e92fc337b02ff8b
1010Author: John Johansen <john.johansen@canonical.com>
1011Date: Sat Jul 9 23:46:33 2016 -0700
1012
1013 apparmor: fix arg_size computation for when setprocattr is null terminated
1014
1015 Signed-off-by: John Johansen <john.johansen@canonical.com>
1016
1017diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1018index 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,
1022 if (!*args)
1023 goto out;
1024
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,
1030
1031commit b661b13237991be6b5cdf0849f137c5ec58217bf
1032Author: John Johansen <john.johansen@canonical.com>
1033Date: Mon Oct 4 15:03:36 2010 -0700
1034
1035 UBUNTU: SAUCE: AppArmor: basic networking rules
1036
1037 Base support for network mediation.
1038
1039 Signed-off-by: John Johansen <john.johansen@canonical.com>
5882c9d4 1040
5882c9d4
AM
1041diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
1042index 9cdec70..d5b291e 100644
1043--- a/security/apparmor/.gitignore
1044+++ b/security/apparmor/.gitignore
1045@@ -1,5 +1,6 @@
1046 #
1047 # Generated include files
1048 #
1049+net_names.h
1050 capability_names.h
1051 rlim_names.h
fc63ffa9 1052diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
5882c9d4 1053index d693df8..5dbb72f 100644
fc63ffa9
AM
1054--- a/security/apparmor/Makefile
1055+++ b/security/apparmor/Makefile
5882c9d4 1056@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
ceaf2cfb 1057
fc63ffa9
AM
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
5882c9d4 1062 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
ceaf2cfb 1063
948a1326 1064-clean-files := capability_names.h rlim_names.h
1e8b8f9b 1065+clean-files := capability_names.h rlim_names.h net_names.h
ceaf2cfb 1066
ceaf2cfb 1067
948a1326 1068 # Build a lower case string table of capability names
5882c9d4
AM
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/' >> $@
948a1326 1072
1e8b8f9b 1073+# Build a lower case string table of address family names
948a1326 1074+# Transform lines from
1e8b8f9b
AM
1075+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
1076+# #define AF_INET 2 /* Internet IP Protocol */
1077+# to
1078+# [1] = "local",
1079+# [2] = "inet",
1080+#
1081+# and build the securityfs entries for the mapping.
1082+# Transforms lines from
1083+# #define AF_INET 2 /* Internet IP Protocol */
948a1326 1084+# to
1e8b8f9b 1085+# #define AA_FS_AF_MASK "local inet"
ceaf2cfb 1086+quiet_cmd_make-af = GEN $@
948a1326 1087+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
1e8b8f9b
AM
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/' >> $@
1094+
1095+# Build a lower case string table of sock type names
1096+# Transform lines from
1097+# SOCK_STREAM = 1,
1098+# to
1099+# [1] = "stream",
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';\
948a1326 1104+ echo "};" >> $@
1e8b8f9b
AM
1105
1106 # Build a lower case string table of rlimit names.
1107 # Transforms lines from
5882c9d4 1108@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
1e8b8f9b
AM
1109 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
1110
fc63ffa9 1111 $(obj)/capability.o : $(obj)/capability_names.h
1e8b8f9b 1112+$(obj)/net.o : $(obj)/net_names.h
fc63ffa9 1113 $(obj)/resource.o : $(obj)/rlim_names.h
5882c9d4 1114 $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
1e8b8f9b 1115 $(src)/Makefile
5882c9d4
AM
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 \
1e8b8f9b 1118 $(src)/Makefile
948a1326 1119 $(call cmd,make-rlim)
1e8b8f9b
AM
1120+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
1121+ $(srctree)/include/linux/net.h \
1122+ $(src)/Makefile
948a1326 1123+ $(call cmd,make-af)
1e8b8f9b
AM
1124+ $(call cmd,make-sock)
1125diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
0776672e 1126index 729e595..181d961 100644
1e8b8f9b
AM
1127--- a/security/apparmor/apparmorfs.c
1128+++ b/security/apparmor/apparmorfs.c
0776672e 1129@@ -807,6 +807,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
5882c9d4 1130 AA_FS_DIR("policy", aa_fs_entry_policy),
1e8b8f9b
AM
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),
5882c9d4 1136 AA_FS_DIR("caps", aa_fs_entry_caps),
1e8b8f9b 1137diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
c2c0f25c 1138index ba3dfd1..5d3c419 100644
1e8b8f9b
AM
1139--- a/security/apparmor/include/audit.h
1140+++ b/security/apparmor/include/audit.h
c2c0f25c 1141@@ -125,6 +125,10 @@ struct apparmor_audit_data {
1e8b8f9b 1142 u32 denied;
5882c9d4 1143 kuid_t ouid;
1e8b8f9b
AM
1144 } fs;
1145+ struct {
1146+ int type, protocol;
1147+ struct sock *sk;
1148+ } net;
1149 };
1150 };
1151
fc63ffa9 1152diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
ceaf2cfb 1153new file mode 100644
1e8b8f9b 1154index 0000000..cb8a121
ceaf2cfb 1155--- /dev/null
fc63ffa9 1156+++ b/security/apparmor/include/net.h
1e8b8f9b 1157@@ -0,0 +1,44 @@
9474138d
AM
1158+/*
1159+ * AppArmor security module
1160+ *
fc63ffa9 1161+ * This file contains AppArmor network mediation definitions.
9474138d
AM
1162+ *
1163+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 1164+ * Copyright 2009-2012 Canonical Ltd.
9474138d
AM
1165+ *
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
1169+ * License.
1170+ */
1171+
fc63ffa9
AM
1172+#ifndef __AA_NET_H
1173+#define __AA_NET_H
2380c486 1174+
fc63ffa9 1175+#include <net/sock.h>
9474138d 1176+
1e8b8f9b
AM
1177+#include "apparmorfs.h"
1178+
fc63ffa9
AM
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
1183+ */
1184+struct aa_net {
1185+ u16 allow[AF_MAX];
1186+ u16 audit[AF_MAX];
1187+ u16 quiet[AF_MAX];
1188+};
ceaf2cfb 1189+
1e8b8f9b
AM
1190+extern struct aa_fs_entry aa_fs_entry_network[];
1191+
fc63ffa9
AM
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);
ceaf2cfb 1195+
fc63ffa9
AM
1196+static inline void aa_free_net_rules(struct aa_net *new)
1197+{
1198+ /* NOP */
ceaf2cfb
AM
1199+}
1200+
fc63ffa9
AM
1201+#endif /* __AA_NET_H */
1202diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
0776672e 1203index 52275f0..4fc4dac 100644
fc63ffa9
AM
1204--- a/security/apparmor/include/policy.h
1205+++ b/security/apparmor/include/policy.h
1206@@ -27,6 +27,7 @@
1207 #include "capability.h"
1208 #include "domain.h"
1209 #include "file.h"
1210+#include "net.h"
1211 #include "resource.h"
1212
5882c9d4
AM
1213 extern const char *const aa_profile_mode_names[];
1214@@ -176,6 +177,7 @@ struct aa_replacedby {
1e8b8f9b 1215 * @policy: general match rules governing policy
fc63ffa9
AM
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
1220 *
5882c9d4
AM
1221 * @dents: dentries for the profiles file entries in apparmorfs
1222@@ -217,6 +219,7 @@ struct aa_profile {
1e8b8f9b 1223 struct aa_policydb policy;
fc63ffa9
AM
1224 struct aa_file_rules file;
1225 struct aa_caps caps;
1226+ struct aa_net net;
1227 struct aa_rlimit rlimits;
fc63ffa9 1228
5882c9d4 1229 unsigned char *hash;
fc63ffa9 1230diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
0776672e 1231index ba8207b..88d3b0a 100644
fc63ffa9
AM
1232--- a/security/apparmor/lsm.c
1233+++ b/security/apparmor/lsm.c
948a1326 1234@@ -32,6 +32,7 @@
fc63ffa9
AM
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"
0776672e 1242@@ -584,6 +585,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
fc63ffa9
AM
1243 return error;
1244 }
1245
1246+static int apparmor_socket_create(int family, int type, int protocol, int kern)
ceaf2cfb 1247+{
fc63ffa9
AM
1248+ struct aa_profile *profile;
1249+ int error = 0;
ceaf2cfb 1250+
fc63ffa9
AM
1251+ if (kern)
1252+ return 0;
ceaf2cfb 1253+
fc63ffa9
AM
1254+ profile = __aa_current_profile();
1255+ if (!unconfined(profile))
1256+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
1257+ NULL);
1258+ return error;
1259+}
ceaf2cfb 1260+
fc63ffa9
AM
1261+static int apparmor_socket_bind(struct socket *sock,
1262+ struct sockaddr *address, int addrlen)
9474138d 1263+{
fc63ffa9 1264+ struct sock *sk = sock->sk;
9474138d 1265+
fc63ffa9
AM
1266+ return aa_revalidate_sk(OP_BIND, sk);
1267+}
ceaf2cfb 1268+
fc63ffa9
AM
1269+static int apparmor_socket_connect(struct socket *sock,
1270+ struct sockaddr *address, int addrlen)
1271+{
1272+ struct sock *sk = sock->sk;
ceaf2cfb 1273+
fc63ffa9 1274+ return aa_revalidate_sk(OP_CONNECT, sk);
9474138d
AM
1275+}
1276+
fc63ffa9 1277+static int apparmor_socket_listen(struct socket *sock, int backlog)
9474138d 1278+{
fc63ffa9
AM
1279+ struct sock *sk = sock->sk;
1280+
1281+ return aa_revalidate_sk(OP_LISTEN, sk);
9474138d
AM
1282+}
1283+
fc63ffa9 1284+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
9474138d 1285+{
fc63ffa9 1286+ struct sock *sk = sock->sk;
9474138d 1287+
fc63ffa9
AM
1288+ return aa_revalidate_sk(OP_ACCEPT, sk);
1289+}
9474138d 1290+
fc63ffa9
AM
1291+static int apparmor_socket_sendmsg(struct socket *sock,
1292+ struct msghdr *msg, int size)
76514441 1293+{
fc63ffa9 1294+ struct sock *sk = sock->sk;
76514441 1295+
fc63ffa9 1296+ return aa_revalidate_sk(OP_SENDMSG, sk);
76514441
AM
1297+}
1298+
fc63ffa9
AM
1299+static int apparmor_socket_recvmsg(struct socket *sock,
1300+ struct msghdr *msg, int size, int flags)
1301+{
1302+ struct sock *sk = sock->sk;
ceaf2cfb 1303+
fc63ffa9
AM
1304+ return aa_revalidate_sk(OP_RECVMSG, sk);
1305+}
ceaf2cfb 1306+
fc63ffa9
AM
1307+static int apparmor_socket_getsockname(struct socket *sock)
1308+{
1309+ struct sock *sk = sock->sk;
ceaf2cfb 1310+
fc63ffa9 1311+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
9474138d
AM
1312+}
1313+
fc63ffa9 1314+static int apparmor_socket_getpeername(struct socket *sock)
9474138d 1315+{
fc63ffa9 1316+ struct sock *sk = sock->sk;
9474138d 1317+
fc63ffa9
AM
1318+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
1319+}
ceaf2cfb 1320+
fc63ffa9
AM
1321+static int apparmor_socket_getsockopt(struct socket *sock, int level,
1322+ int optname)
1323+{
1324+ struct sock *sk = sock->sk;
ceaf2cfb 1325+
fc63ffa9
AM
1326+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
1327+}
ceaf2cfb 1328+
fc63ffa9
AM
1329+static int apparmor_socket_setsockopt(struct socket *sock, int level,
1330+ int optname)
1331+{
1332+ struct sock *sk = sock->sk;
2380c486 1333+
fc63ffa9
AM
1334+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
1335+}
ceaf2cfb 1336+
fc63ffa9
AM
1337+static int apparmor_socket_shutdown(struct socket *sock, int how)
1338+{
1339+ struct sock *sk = sock->sk;
ceaf2cfb 1340+
fc63ffa9 1341+ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
ceaf2cfb 1342+}
948a1326 1343+
c2c0f25c
AM
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),
0776672e 1347@@ -613,6 +712,19 @@ static struct security_hook_list apparmor_hooks[] = {
c2c0f25c
AM
1348 LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
1349 LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
5d26c04f 1350
c2c0f25c
AM
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),
1363+
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),
fc63ffa9 1367diff --git a/security/apparmor/net.c b/security/apparmor/net.c
ceaf2cfb 1368new file mode 100644
2dfbb274 1369index 0000000..003dd18
ceaf2cfb 1370--- /dev/null
fc63ffa9 1371+++ b/security/apparmor/net.c
1e8b8f9b 1372@@ -0,0 +1,162 @@
2380c486 1373+/*
9474138d
AM
1374+ * AppArmor security module
1375+ *
fc63ffa9 1376+ * This file contains AppArmor network mediation
2380c486 1377+ *
9474138d 1378+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 1379+ * Copyright 2009-2012 Canonical Ltd.
2380c486 1380+ *
9474138d
AM
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
1384+ * License.
2380c486
JR
1385+ */
1386+
9474138d
AM
1387+#include "include/apparmor.h"
1388+#include "include/audit.h"
1389+#include "include/context.h"
fc63ffa9 1390+#include "include/net.h"
9474138d 1391+#include "include/policy.h"
2380c486 1392+
1e8b8f9b
AM
1393+#include "net_names.h"
1394+
1395+struct aa_fs_entry aa_fs_entry_network[] = {
1396+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
1397+ { }
9474138d
AM
1398+};
1399+
fc63ffa9 1400+/* audit callback for net specific fields */
76514441 1401+static void audit_cb(struct audit_buffer *ab, void *va)
9474138d 1402+{
76514441 1403+ struct common_audit_data *sa = va;
9474138d 1404+
fc63ffa9 1405+ audit_log_format(ab, " family=");
1e8b8f9b
AM
1406+ if (address_family_names[sa->u.net->family]) {
1407+ audit_log_string(ab, address_family_names[sa->u.net->family]);
fc63ffa9 1408+ } else {
1e8b8f9b 1409+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
fc63ffa9 1410+ }
fc63ffa9 1411+ audit_log_format(ab, " sock_type=");
1e8b8f9b
AM
1412+ if (sock_type_names[sa->aad->net.type]) {
1413+ audit_log_string(ab, sock_type_names[sa->aad->net.type]);
fc63ffa9 1414+ } else {
1e8b8f9b 1415+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
fc63ffa9 1416+ }
1e8b8f9b 1417+ audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
2380c486
JR
1418+}
1419+
1420+/**
fc63ffa9
AM
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
ceaf2cfb 1429+ *
fc63ffa9 1430+ * Returns: %0 or sa->error else other errorcode on failure
2380c486 1431+ */
fc63ffa9
AM
1432+static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
1433+ int protocol, struct sock *sk, int error)
2380c486 1434+{
fc63ffa9
AM
1435+ int audit_type = AUDIT_APPARMOR_AUTO;
1436+ struct common_audit_data sa;
1e8b8f9b
AM
1437+ struct apparmor_audit_data aad = { };
1438+ struct lsm_network_audit net = { };
fc63ffa9 1439+ if (sk) {
0c3ec466 1440+ sa.type = LSM_AUDIT_DATA_NET;
fc63ffa9 1441+ } else {
0c3ec466 1442+ sa.type = LSM_AUDIT_DATA_NONE;
2380c486 1443+ }
fc63ffa9 1444+ /* todo fill in socket addr info */
1e8b8f9b
AM
1445+ sa.aad = &aad;
1446+ sa.u.net = &net;
1447+ sa.aad->op = op,
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;
1453+
1454+ if (likely(!sa.aad->error)) {
1455+ u16 audit_mask = profile->net.audit[sa.u.net->family];
fc63ffa9 1456+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
1e8b8f9b 1457+ !(1 << sa.aad->net.type & audit_mask)))
ceaf2cfb 1458+ return 0;
fc63ffa9
AM
1459+ audit_type = AUDIT_APPARMOR_AUDIT;
1460+ } else {
1e8b8f9b 1461+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
fc63ffa9 1462+ u16 kill_mask = 0;
1e8b8f9b 1463+ u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
9474138d 1464+
fc63ffa9
AM
1465+ if (denied & kill_mask)
1466+ audit_type = AUDIT_APPARMOR_KILL;
9474138d 1467+
fc63ffa9
AM
1468+ if ((denied & quiet_mask) &&
1469+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1470+ AUDIT_MODE(profile) != AUDIT_ALL)
1e8b8f9b 1471+ return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
9474138d
AM
1472+ }
1473+
fc63ffa9 1474+ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
ceaf2cfb
AM
1475+}
1476+
2380c486 1477+/**
fc63ffa9
AM
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
2380c486 1484+ *
fc63ffa9 1485+ * Returns: %0 else error if permission denied
2380c486 1486+ */
fc63ffa9
AM
1487+int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
1488+ int protocol, struct sock *sk)
2380c486 1489+{
fc63ffa9
AM
1490+ u16 family_mask;
1491+ int error;
ceaf2cfb 1492+
fc63ffa9
AM
1493+ if ((family < 0) || (family >= AF_MAX))
1494+ return -EINVAL;
ceaf2cfb 1495+
fc63ffa9
AM
1496+ if ((type < 0) || (type >= SOCK_MAX))
1497+ return -EINVAL;
76514441 1498+
fc63ffa9
AM
1499+ /* unix domain and netlink sockets are handled by ipc */
1500+ if (family == AF_UNIX || family == AF_NETLINK)
1501+ return 0;
76514441 1502+
fc63ffa9 1503+ family_mask = profile->net.allow[family];
2380c486 1504+
fc63ffa9 1505+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
ceaf2cfb 1506+
fc63ffa9 1507+ return audit_net(profile, op, family, type, protocol, sk, error);
2380c486
JR
1508+}
1509+
76514441 1510+/**
fc63ffa9
AM
1511+ * aa_revalidate_sk - Revalidate access to a sock
1512+ * @op: operation being checked
1513+ * @sk: sock being revalidated (NOT NULL)
76514441 1514+ *
fc63ffa9 1515+ * Returns: %0 else error if permission denied
76514441 1516+ */
fc63ffa9 1517+int aa_revalidate_sk(int op, struct sock *sk)
2380c486 1518+{
fc63ffa9
AM
1519+ struct aa_profile *profile;
1520+ int error = 0;
2380c486 1521+
fc63ffa9
AM
1522+ /* aa_revalidate_sk should not be called from interrupt context
1523+ * don't mediate these calls as they are not task related
1524+ */
1525+ if (in_interrupt())
1526+ return 0;
ceaf2cfb 1527+
fc63ffa9
AM
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);
2380c486 1532+
fc63ffa9 1533+ return error;
2380c486 1534+}
fc63ffa9 1535diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
0776672e 1536index 179e68d..f1a8541 100644
fc63ffa9
AM
1537--- a/security/apparmor/policy.c
1538+++ b/security/apparmor/policy.c
5882c9d4 1539@@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile)
fc63ffa9
AM
1540
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);
1545
5882c9d4 1546 kzfree(profile->dirname);
fc63ffa9 1547diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
0776672e 1548index dac2121..0107bc4 100644
fc63ffa9
AM
1549--- a/security/apparmor/policy_unpack.c
1550+++ b/security/apparmor/policy_unpack.c
1e8b8f9b 1551@@ -193,6 +193,19 @@ fail:
fc63ffa9
AM
1552 return 0;
1553 }
1554
1555+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
2380c486 1556+{
fc63ffa9
AM
1557+ if (unpack_nameX(e, AA_U16, name)) {
1558+ if (!inbounds(e, sizeof(u16)))
1559+ return 0;
1560+ if (data)
1561+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
1562+ e->pos += sizeof(u16);
1563+ return 1;
2380c486 1564+ }
2380c486
JR
1565+ return 0;
1566+}
1567+
fc63ffa9
AM
1568 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
1569 {
1570 if (unpack_nameX(e, AA_U32, name)) {
5882c9d4 1571@@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
1572 {
1573 struct aa_profile *profile = NULL;
1574 const char *name = NULL;
2380c486 1575+ size_t size = 0;
1e8b8f9b 1576 int i, error = -EPROTO;
fc63ffa9
AM
1577 kernel_cap_t tmpcap;
1578 u32 tmp;
5882c9d4 1579@@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
1580 if (!unpack_rlimits(e, profile))
1581 goto fail;
1582
ceaf2cfb 1583+ size = unpack_array(e, "net_allowed_af");
2380c486 1584+ if (size) {
2380c486
JR
1585+
1586+ for (i = 0; i < size; i++) {
fc63ffa9
AM
1587+ /* discard extraneous rules that this kernel will
1588+ * never request
1589+ */
1efb82ae 1590+ if (i >= AF_MAX) {
fc63ffa9
AM
1591+ u16 tmp;
1592+ if (!unpack_u16(e, &tmp, NULL) ||
1593+ !unpack_u16(e, &tmp, NULL) ||
1594+ !unpack_u16(e, &tmp, NULL))
1595+ goto fail;
1596+ continue;
1597+ }
76514441 1598+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
2380c486 1599+ goto fail;
ceaf2cfb 1600+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
2380c486 1601+ goto fail;
ceaf2cfb 1602+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
2380c486
JR
1603+ goto fail;
1604+ }
ceaf2cfb 1605+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
2380c486 1606+ goto fail;
2380c486 1607+ }
1e8b8f9b
AM
1608+ /*
1609+ * allow unix domain and netlink sockets they are handled
1610+ * by IPC
1611+ */
76514441
AM
1612+ profile->net.allow[AF_UNIX] = 0xffff;
1613+ profile->net.allow[AF_NETLINK] = 0xffff;
2380c486 1614+
1e8b8f9b
AM
1615 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
1616 /* generic policy dfa - optional and may be NULL */
1617 profile->policy.dfa = unpack_dfa(e);
5882c9d4 1618
0776672e
AM
1619commit 64c5e24470a219c79c2870c63f18f6bd55648b1b
1620Author: John Johansen <john.johansen@canonical.com>
1621Date: Fri Jun 29 17:34:00 2012 -0700
5882c9d4 1622
0776672e
AM
1623 apparmor: Fix quieting of audit messages for network mediation
1624
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.
1631
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.
1635
1636 Signed-off-by: John Johansen <john.johansen@canonical.com>
5882c9d4
AM
1637
1638diff --git a/security/apparmor/net.c b/security/apparmor/net.c
1639index 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,
1643 } else {
1644 u16 quiet_mask = profile->net.quiet[sa.u.net->family];
1645 u16 kill_mask = 0;
1646- u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
1647+ u16 denied = (1 << sa.aad->net.type);
1648
1649 if (denied & kill_mask)
1650 audit_type = AUDIT_APPARMOR_KILL;
5882c9d4 1651
0776672e
AM
1652commit f7cef61751a2382fb4ea26c18736d7552ffdb24a
1653Author: John Johansen <john.johansen@canonical.com>
1654Date: Wed May 16 10:58:05 2012 -0700
1e8b8f9b 1655
0776672e
AM
1656 UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
1657
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.
1660
1661 The basic form of the rules are.
1662
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>
1667
1668 remount is just a short cut for mount options=remount
1669
1670 where [conds] can be
1671 fstype=<expr>
1672 options=<expr>
1673
1674 Example mount commands
1675 mount, # allow all mounts, but not umount or pivotroot
1676
1677 mount fstype=procfs, # allow mounting procfs anywhere
1678
1679 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
1680
1681 mount /dev/sda -> /mnt,
1682
1683 mount /dev/sd** -> /mnt/**,
1684
1685 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
1686
1687 umount,
1688
1689 umount /m*,
1690
1691 See the apparmor userspace for full documentation
1692
1693 Signed-off-by: John Johansen <john.johansen@canonical.com>
1694 Acked-by: Kees Cook <kees@ubuntu.com>
5882c9d4 1695
fc63ffa9 1696diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
5882c9d4 1697index 5dbb72f..89b3445 100644
fc63ffa9
AM
1698--- a/security/apparmor/Makefile
1699+++ b/security/apparmor/Makefile
1e8b8f9b
AM
1700@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
1701
948a1326 1702 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
fc63ffa9 1703 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
1e8b8f9b
AM
1704- resource.o sid.o file.o net.o
1705+ resource.o sid.o file.o net.o mount.o
5882c9d4 1706 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
fc63ffa9 1707
1e8b8f9b 1708 clean-files := capability_names.h rlim_names.h net_names.h
1e8b8f9b 1709diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
0776672e 1710index 181d961..5fb67f6 100644
1e8b8f9b
AM
1711--- a/security/apparmor/apparmorfs.c
1712+++ b/security/apparmor/apparmorfs.c
0776672e 1713@@ -800,7 +800,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
1e8b8f9b 1714
5882c9d4
AM
1715 static struct aa_fs_entry aa_fs_entry_policy[] = {
1716 AA_FS_FILE_BOOLEAN("set_load", 1),
1717- {}
1718+ { }
1719+};
1720+
1e8b8f9b
AM
1721+static struct aa_fs_entry aa_fs_entry_mount[] = {
1722+ AA_FS_FILE_STRING("mask", "mount umount"),
1723+ { }
1724+};
1725+
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),
1729+ { }
5882c9d4
AM
1730 };
1731
1e8b8f9b 1732 static struct aa_fs_entry aa_fs_entry_features[] = {
0776672e 1733@@ -808,6 +819,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
1e8b8f9b
AM
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),
5882c9d4 1741 AA_FS_DIR("caps", aa_fs_entry_caps),
1e8b8f9b 1742diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
0776672e 1743index 3a7f1da..c2a8b8a 100644
1e8b8f9b
AM
1744--- a/security/apparmor/audit.c
1745+++ b/security/apparmor/audit.c
1746@@ -44,6 +44,10 @@ const char *const op_table[] = {
1747 "file_mmap",
1748 "file_mprotect",
1749
1750+ "pivotroot",
1751+ "mount",
1752+ "umount",
1753+
1754 "create",
1755 "post_create",
1756 "bind",
1757diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
0776672e 1758index fc3036b..f2a83b4 100644
1e8b8f9b
AM
1759--- a/security/apparmor/domain.c
1760+++ b/security/apparmor/domain.c
c2c0f25c 1761@@ -236,7 +236,7 @@ static const char *next_name(int xtype, const char *name)
1e8b8f9b
AM
1762 *
1763 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
1764 */
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)
1767 {
1768 struct aa_profile *new_profile = NULL;
1769 struct aa_namespace *ns = profile->ns;
1770diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
c2c0f25c 1771index e4ea626..ce6ff6a 100644
1e8b8f9b
AM
1772--- a/security/apparmor/include/apparmor.h
1773+++ b/security/apparmor/include/apparmor.h
5882c9d4 1774@@ -30,8 +30,9 @@
1e8b8f9b
AM
1775 #define AA_CLASS_NET 4
1776 #define AA_CLASS_RLIMITS 5
1777 #define AA_CLASS_DOMAIN 6
1778+#define AA_CLASS_MOUNT 7
1779
1780-#define AA_CLASS_LAST AA_CLASS_DOMAIN
1781+#define AA_CLASS_LAST AA_CLASS_MOUNT
1782
1783 /* Control parameters settable through module/boot flags */
1784 extern enum audit_mode aa_g_audit;
1785diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
c2c0f25c 1786index 5d3c419..b9f1d57 100644
1e8b8f9b
AM
1787--- a/security/apparmor/include/audit.h
1788+++ b/security/apparmor/include/audit.h
5882c9d4 1789@@ -72,6 +72,10 @@ enum aa_ops {
1e8b8f9b
AM
1790 OP_FMMAP,
1791 OP_FMPROT,
1792
1793+ OP_PIVOTROOT,
1794+ OP_MOUNT,
1795+ OP_UMOUNT,
1796+
1797 OP_CREATE,
1798 OP_POST_CREATE,
1799 OP_BIND,
c2c0f25c 1800@@ -120,6 +124,13 @@ struct apparmor_audit_data {
1e8b8f9b
AM
1801 unsigned long max;
1802 } rlim;
1803 struct {
1804+ const char *src_name;
1805+ const char *type;
1806+ const char *trans;
1807+ const char *data;
1808+ unsigned long flags;
1809+ } mnt;
1810+ struct {
1811 const char *target;
1812 u32 request;
1813 u32 denied;
1814diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
1815index 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 {
1819 char **table;
1820 };
1821
1822+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
1823+
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);
1827diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
ceaf2cfb 1828new file mode 100644
0776672e 1829index 0000000..a43b1d6
ceaf2cfb 1830--- /dev/null
1e8b8f9b
AM
1831+++ b/security/apparmor/include/mount.h
1832@@ -0,0 +1,54 @@
2380c486 1833+/*
9474138d
AM
1834+ * AppArmor security module
1835+ *
1e8b8f9b 1836+ * This file contains AppArmor file mediation function definitions.
2380c486 1837+ *
1e8b8f9b 1838+ * Copyright 2012 Canonical Ltd.
2380c486 1839+ *
9474138d
AM
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
1843+ * License.
2380c486
JR
1844+ */
1845+
1e8b8f9b
AM
1846+#ifndef __AA_MOUNT_H
1847+#define __AA_MOUNT_H
fc63ffa9 1848+
1e8b8f9b
AM
1849+#include <linux/fs.h>
1850+#include <linux/path.h>
2380c486 1851+
1e8b8f9b
AM
1852+#include "domain.h"
1853+#include "policy.h"
76514441 1854+
1e8b8f9b
AM
1855+/* mount perms */
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
fc63ffa9 1861+
1e8b8f9b 1862+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
fc63ffa9 1863+
0776672e 1864+int aa_remount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 1865+ unsigned long flags, void *data);
fc63ffa9 1866+
0776672e 1867+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 1868+ const char *old_name, unsigned long flags);
fc63ffa9 1869+
fc63ffa9 1870+
0776672e 1871+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
1e8b8f9b 1872+ unsigned long flags);
fc63ffa9 1873+
0776672e 1874+int aa_move_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b
AM
1875+ const char *old_name);
1876+
1877+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
0776672e 1878+ const struct path *path, const char *type, unsigned long flags,
1e8b8f9b
AM
1879+ void *data);
1880+
1881+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
1882+
0776672e
AM
1883+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
1884+ const struct path *new_path);
1e8b8f9b
AM
1885+
1886+#endif /* __AA_MOUNT_H */
1887diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
0776672e 1888index 88d3b0a..432cbd3 100644
1e8b8f9b
AM
1889--- a/security/apparmor/lsm.c
1890+++ b/security/apparmor/lsm.c
1891@@ -36,6 +36,7 @@
1892 #include "include/path.h"
1893 #include "include/policy.h"
1894 #include "include/procattr.h"
1895+#include "include/mount.h"
1896
1897 /* Flag indicating whether initialization completed */
1898 int apparmor_initialized __initdata;
0776672e 1899@@ -469,6 +470,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1e8b8f9b
AM
1900 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1901 }
1902
0776672e
AM
1903+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
1904+ const char *type, unsigned long flags, void *data)
2380c486 1905+{
1e8b8f9b
AM
1906+ struct aa_profile *profile;
1907+ int error = 0;
76514441 1908+
1e8b8f9b
AM
1909+ /* Discard magic */
1910+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1911+ flags &= ~MS_MGC_MSK;
2380c486 1912+
1e8b8f9b
AM
1913+ flags &= ~AA_MS_IGNORE_MASK;
1914+
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 |
1922+ MS_UNBINDABLE))
1923+ error = aa_mount_change_type(profile, path, flags);
1924+ else if (flags & MS_MOVE)
1925+ error = aa_move_mount(profile, path, dev_name);
1926+ else
1927+ error = aa_new_mount(profile, dev_name, path, type,
1928+ flags, data);
2380c486 1929+ }
1e8b8f9b
AM
1930+ return error;
1931+}
2380c486 1932+
1e8b8f9b
AM
1933+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
1934+{
1935+ struct aa_profile *profile;
1936+ int error = 0;
1937+
1938+ profile = __aa_current_profile();
1939+ if (!unconfined(profile))
1940+ error = aa_umount(profile, mnt, flags);
1941+
1942+ return error;
2380c486
JR
1943+}
1944+
0776672e
AM
1945+static int apparmor_sb_pivotroot(const struct path *old_path,
1946+ const struct path *new_path)
2380c486 1947+{
1e8b8f9b
AM
1948+ struct aa_profile *profile;
1949+ int error = 0;
1950+
1951+ profile = __aa_current_profile();
1952+ if (!unconfined(profile))
1953+ error = aa_pivotroot(profile, old_path, new_path);
1954+
1955+ return error;
2380c486
JR
1956+}
1957+
1e8b8f9b
AM
1958 static int apparmor_getprocattr(struct task_struct *task, char *name,
1959 char **value)
1960 {
0776672e 1961@@ -689,6 +745,10 @@ static struct security_hook_list apparmor_hooks[] = {
c2c0f25c
AM
1962 LSM_HOOK_INIT(capget, apparmor_capget),
1963 LSM_HOOK_INIT(capable, apparmor_capable),
1e8b8f9b 1964
c2c0f25c
AM
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),
1968+
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),
1e8b8f9b
AM
1972diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
1973new file mode 100644
0776672e 1974index 0000000..9cf9170
1e8b8f9b
AM
1975--- /dev/null
1976+++ b/security/apparmor/mount.c
1977@@ -0,0 +1,620 @@
1978+/*
1979+ * AppArmor security module
fc63ffa9 1980+ *
1e8b8f9b 1981+ * This file contains AppArmor mediation of files
ceaf2cfb 1982+ *
1e8b8f9b
AM
1983+ * Copyright (C) 1998-2008 Novell/SUSE
1984+ * Copyright 2009-2012 Canonical Ltd.
1985+ *
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
1989+ * License.
ceaf2cfb 1990+ */
2380c486 1991+
1e8b8f9b
AM
1992+#include <linux/fs.h>
1993+#include <linux/mount.h>
1994+#include <linux/namei.h>
2380c486 1995+
1e8b8f9b
AM
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"
ceaf2cfb 2005+
2380c486 2006+
1e8b8f9b
AM
2007+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
2008+{
2009+ if (flags & MS_RDONLY)
2010+ audit_log_format(ab, "ro");
2011+ else
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" :
2041+ ", unbindable");
2042+ if (flags & MS_PRIVATE)
2043+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
2044+ ", private");
2045+ if (flags & MS_SLAVE)
2046+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
2047+ ", slave");
2048+ if (flags & MS_SHARED)
2049+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
2050+ ", shared");
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");
2380c486
JR
2059+}
2060+
ceaf2cfb 2061+/**
1e8b8f9b
AM
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)
ceaf2cfb 2065+ */
1e8b8f9b 2066+static void audit_cb(struct audit_buffer *ab, void *va)
2380c486 2067+{
1e8b8f9b 2068+ struct common_audit_data *sa = va;
9474138d 2069+
1e8b8f9b
AM
2070+ if (sa->aad->mnt.type) {
2071+ audit_log_format(ab, " fstype=");
2072+ audit_log_untrustedstring(ab, sa->aad->mnt.type);
2073+ }
2074+ if (sa->aad->mnt.src_name) {
2075+ audit_log_format(ab, " srcname=");
2076+ audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
2077+ }
2078+ if (sa->aad->mnt.trans) {
2079+ audit_log_format(ab, " trans=");
2080+ audit_log_untrustedstring(ab, sa->aad->mnt.trans);
2081+ }
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, "\"");
2086+ }
2087+ if (sa->aad->mnt.data) {
2088+ audit_log_format(ab, " options=");
2089+ audit_log_untrustedstring(ab, sa->aad->mnt.data);
2090+ }
9474138d 2091+}
2380c486 2092+
fc63ffa9 2093+/**
1e8b8f9b
AM
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
9474138d 2108+ *
1e8b8f9b 2109+ * Returns: %0 or error on failure
76514441 2110+ */
1e8b8f9b
AM
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)
2380c486 2116+{
1e8b8f9b 2117+ int audit_type = AUDIT_APPARMOR_AUTO;
2dfbb274 2118+ struct common_audit_data sa = { };
1e8b8f9b 2119+ struct apparmor_audit_data aad = { };
9474138d 2120+
1e8b8f9b
AM
2121+ if (likely(!error)) {
2122+ u32 mask = perms->audit;
9474138d 2123+
1e8b8f9b
AM
2124+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
2125+ mask = 0xffff;
76514441 2126+
1e8b8f9b
AM
2127+ /* mask off perms that are not being force audited */
2128+ request &= mask;
fc63ffa9 2129+
1e8b8f9b
AM
2130+ if (likely(!request))
2131+ return 0;
2132+ audit_type = AUDIT_APPARMOR_AUDIT;
2133+ } else {
2134+ /* only report permissions that were denied */
2135+ request = request & ~perms->allow;
2136+
2137+ if (request & perms->kill)
2138+ audit_type = AUDIT_APPARMOR_KILL;
2139+
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;
2145+
2146+ if (!request)
2147+ return COMPLAIN_MODE(profile) ?
2148+ complain_error(error) : error;
2149+ }
2150+
0c3ec466 2151+ sa.type = LSM_AUDIT_DATA_NONE;
1e8b8f9b
AM
2152+ sa.aad = &aad;
2153+ sa.aad->op = op;
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;
2163+
2164+ return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
76514441
AM
2165+}
2166+
2167+/**
1e8b8f9b
AM
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
76514441 2172+ *
1e8b8f9b
AM
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
2175+ * on the flags.
76514441 2176+ *
1e8b8f9b 2177+ * Returns: next state after flags match
76514441 2178+ */
1e8b8f9b
AM
2179+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
2180+ unsigned long flags)
9474138d 2181+{
1e8b8f9b 2182+ unsigned int i;
fc63ffa9 2183+
1e8b8f9b
AM
2184+ for (i = 0; i <= 31 ; ++i) {
2185+ if ((1 << i) & flags)
2186+ state = aa_dfa_next(dfa, state, i + 1);
2187+ }
2188+
2189+ return state;
9474138d
AM
2190+}
2191+
2192+/**
1e8b8f9b
AM
2193+ * compute_mnt_perms - compute mount permission associated with @state
2194+ * @dfa: dfa to match against (NOT NULL)
2195+ * @state: state match finished in
ceaf2cfb 2196+ *
1e8b8f9b 2197+ * Returns: mount permissions
9474138d 2198+ */
1e8b8f9b
AM
2199+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
2200+ unsigned int state)
9474138d 2201+{
1e8b8f9b 2202+ struct file_perms perms;
2380c486 2203+
1e8b8f9b
AM
2204+ perms.kill = 0;
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);
2209+
2210+ return perms;
2211+}
2212+
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"
2220+};
2221+
2222+/*
2223+ * Returns 0 on success else element that match failed in, this is the
2224+ * index into the mnt_info_table above
2225+ */
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)
2230+{
2231+ unsigned int state;
2232+
2233+ state = aa_dfa_match(dfa, start, mntpnt);
2234+ state = aa_dfa_null_transition(dfa, state);
2235+ if (!state)
2236+ return 1;
2237+
2238+ if (devname)
2239+ state = aa_dfa_match(dfa, state, devname);
2240+ state = aa_dfa_null_transition(dfa, state);
2241+ if (!state)
2242+ return 2;
2243+
2244+ if (type)
2245+ state = aa_dfa_match(dfa, state, type);
2246+ state = aa_dfa_null_transition(dfa, state);
2247+ if (!state)
2248+ return 3;
2249+
2250+ state = match_mnt_flags(dfa, state, flags);
2251+ if (!state)
2252+ return 4;
2253+ *perms = compute_mnt_perms(dfa, state);
2254+ if (perms->allow & AA_MAY_MOUNT)
2255+ return 0;
2256+
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);
2260+ if (!state)
2261+ return 4;
2262+
2263+ state = aa_dfa_match(dfa, state, data);
2264+ if (!state)
2265+ return 5;
2266+ *perms = compute_mnt_perms(dfa, state);
2267+ if (perms->allow & AA_MAY_MOUNT)
2268+ return 0;
fc63ffa9 2269+ }
1e8b8f9b
AM
2270+
2271+ /* failed at end of flags match */
2272+ return 4;
9474138d
AM
2273+}
2274+
ceaf2cfb 2275+/**
1e8b8f9b
AM
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
fc63ffa9 2286+ *
1e8b8f9b 2287+ * Returns: 0 on success else error
ceaf2cfb 2288+ */
1e8b8f9b
AM
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)
9474138d 2293+{
1e8b8f9b 2294+ int pos;
2380c486 2295+
1e8b8f9b
AM
2296+ if (!profile->policy.dfa)
2297+ return -EACCES;
2298+
2299+ pos = do_match_mnt(profile->policy.dfa,
2300+ profile->policy.start[AA_CLASS_MOUNT],
2301+ mntpnt, devname, type, flags, data, binary, perms);
2302+ if (pos) {
2303+ *info = mnt_info_table[pos];
2304+ return -EACCES;
2305+ }
2380c486 2306+
fc63ffa9 2307+ return 0;
9474138d 2308+}
9474138d 2309+
0776672e 2310+static int path_flags(struct aa_profile *profile, const struct path *path)
1e8b8f9b
AM
2311+{
2312+ return profile->path_flags |
2313+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
2314+}
9474138d 2315+
0776672e 2316+int aa_remount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 2317+ unsigned long flags, void *data)
9474138d 2318+{
1e8b8f9b
AM
2319+ struct file_perms perms = { };
2320+ const char *name, *info = NULL;
2321+ char *buffer = NULL;
2322+ int binary, error;
2323+
2324+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
2325+
2326+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2327+ &info);
2328+ if (error)
2329+ goto audit;
2330+
2331+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
2332+ &perms, &info);
2333+
2334+audit:
2335+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
2336+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
2337+ error);
2338+ kfree(buffer);
2339+
2340+ return error;
9474138d
AM
2341+}
2342+
0776672e 2343+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 2344+ const char *dev_name, unsigned long flags)
9474138d 2345+{
1e8b8f9b
AM
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;
2350+ int error;
2351+
2352+ if (!dev_name || !*dev_name)
2353+ return -EINVAL;
2354+
2355+ flags &= MS_REC | MS_BIND;
2356+
2357+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2358+ &info);
2359+ if (error)
2360+ goto audit;
2361+
2362+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
2363+ if (error)
2364+ goto audit;
2365+
2366+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
2367+ &old_buffer, &old_name, &info);
2368+ path_put(&old_path);
2369+ if (error)
2370+ goto audit;
2371+
2372+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
2373+ &perms, &info);
2374+
2375+audit:
2376+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
2377+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
2378+ info, error);
2379+ kfree(buffer);
2380+ kfree(old_buffer);
2381+
2382+ return error;
9474138d 2383+}
fc63ffa9 2384+
0776672e 2385+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
1e8b8f9b
AM
2386+ unsigned long flags)
2387+{
2388+ struct file_perms perms = { };
2389+ char *buffer = NULL;
2390+ const char *name, *info = NULL;
2391+ int error;
2392+
2393+ /* These are the flags allowed by do_change_type() */
2394+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
2395+ MS_UNBINDABLE);
2396+
2397+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2398+ &info);
fc63ffa9 2399+ if (error)
1e8b8f9b
AM
2400+ goto audit;
2401+
2402+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
2403+ &info);
2404+
2405+audit:
2406+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
2407+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
2408+ error);
2409+ kfree(buffer);
2410+
2411+ return error;
2412+}
2413+
0776672e 2414+int aa_move_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b
AM
2415+ const char *orig_name)
2416+{
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;
2421+ int error;
2422+
2423+ if (!orig_name || !*orig_name)
2424+ return -EINVAL;
2425+
2426+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2427+ &info);
fc63ffa9 2428+ if (error)
1e8b8f9b
AM
2429+ goto audit;
2430+
2431+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
fc63ffa9 2432+ if (error)
1e8b8f9b
AM
2433+ goto audit;
2434+
2435+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
2436+ &old_buffer, &old_name, &info);
2437+ path_put(&old_path);
2438+ if (error)
2439+ goto audit;
2440+
2441+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
2442+ &perms, &info);
2443+
2444+audit:
2445+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
2446+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
2447+ info, error);
2448+ kfree(buffer);
2449+ kfree(old_buffer);
2450+
2451+ return error;
2452+}
2453+
2454+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
0776672e 2455+ const struct path *path, const char *type, unsigned long flags,
1e8b8f9b
AM
2456+ void *data)
2457+{
2458+ struct file_perms perms = { };
2459+ char *buffer = NULL, *dev_buffer = NULL;
2460+ const char *name = NULL, *dev_name = NULL, *info = NULL;
2461+ int binary = 1;
2462+ int error;
2463+
2464+ dev_name = orig_dev_name;
2465+ if (type) {
2466+ int requires_dev;
2467+ struct file_system_type *fstype = get_fs_type(type);
2468+ if (!fstype)
2469+ return -ENODEV;
2470+
2471+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
2472+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
2473+ put_filesystem(fstype);
2474+
2475+ if (requires_dev) {
2476+ struct path dev_path;
2477+
2478+ if (!dev_name || !*dev_name) {
2479+ error = -ENOENT;
2480+ goto out;
2481+ }
2482+
2483+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
2484+ if (error)
2485+ goto audit;
2486+
2487+ error = aa_path_name(&dev_path,
2488+ path_flags(profile, &dev_path),
2489+ &dev_buffer, &dev_name, &info);
2490+ path_put(&dev_path);
2491+ if (error)
2492+ goto audit;
2493+ }
2494+ }
2495+
2496+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2497+ &info);
2498+ if (error)
2499+ goto audit;
2500+
2501+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
2502+ &perms, &info);
2503+
2504+audit:
2505+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
2506+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
2507+ error);
2508+ kfree(buffer);
2509+ kfree(dev_buffer);
2510+
2511+out:
2512+ return error;
2513+
2514+}
2515+
2516+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
2517+{
2518+ struct file_perms perms = { };
2519+ char *buffer = NULL;
2520+ const char *name, *info = NULL;
2521+ int error;
2522+
2523+ struct path path = { mnt, mnt->mnt_root };
2524+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
2525+ &info);
2526+ if (error)
2527+ goto audit;
2528+
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],
2533+ name);
2534+ perms = compute_mnt_perms(profile->policy.dfa, state);
2535+ }
2536+
2537+ if (AA_MAY_UMOUNT & ~perms.allow)
2538+ error = -EACCES;
2539+
2540+audit:
2541+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
2542+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
2543+ kfree(buffer);
2544+
2545+ return error;
2546+}
2547+
0776672e
AM
2548+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
2549+ const struct path *new_path)
1e8b8f9b
AM
2550+{
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;
2555+ int error;
2556+
2557+ error = aa_path_name(old_path, path_flags(profile, old_path),
2558+ &old_buffer, &old_name, &info);
2559+ if (error)
2560+ goto audit;
2561+
2562+ error = aa_path_name(new_path, path_flags(profile, new_path),
2563+ &new_buffer, &new_name, &info);
2564+ if (error)
2565+ goto audit;
2566+
2567+ if (profile->policy.dfa) {
2568+ unsigned int state;
2569+ state = aa_dfa_match(profile->policy.dfa,
2570+ profile->policy.start[AA_CLASS_MOUNT],
2571+ new_name);
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);
2575+ }
2576+
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);
2580+ if (!target)
2581+ error = -ENOENT;
2582+ else
2583+ error = aa_replace_current_profile(target);
2584+ }
2585+ } else
2586+ error = -EACCES;
2587+
2588+audit:
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);
2595+
2596+ return error;
2597+}
This page took 0.519271 seconds and 4 git commands to generate.