]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-apparmor.patch
- up to 4.7.6
[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 5833ccff1227fbc8f1bab64351f6747a6c71bdeb
602Author: Geliang Tang <geliangtang@163.com>
603Date: Mon Nov 16 21:46:33 2015 +0800
604
605 apparmor: use list_next_entry instead of list_entry_next
606
607 list_next_entry has been defined in list.h, so I replace list_entry_next
608 with it.
609
610 Signed-off-by: Geliang Tang <geliangtang@163.com>
611 Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
612 Signed-off-by: John Johansen <john.johansen@canonical.com>
613
614diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
615index 0d8dd71..729e595 100644
616--- a/security/apparmor/apparmorfs.c
617+++ b/security/apparmor/apparmorfs.c
618@@ -553,8 +553,6 @@ fail2:
619 }
620
621
622-#define list_entry_next(pos, member) \
623- list_entry(pos->member.next, typeof(*pos), member)
624 #define list_entry_is_head(pos, head, member) (&pos->member == (head))
625
626 /**
627@@ -585,7 +583,7 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root,
628 parent = ns->parent;
629 while (ns != root) {
630 mutex_unlock(&ns->lock);
631- next = list_entry_next(ns, base.list);
632+ next = list_next_entry(ns, base.list);
633 if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
634 mutex_lock(&next->lock);
635 return next;
636@@ -639,7 +637,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
637 parent = rcu_dereference_protected(p->parent,
638 mutex_is_locked(&p->ns->lock));
639 while (parent) {
640- p = list_entry_next(p, base.list);
641+ p = list_next_entry(p, base.list);
642 if (!list_entry_is_head(p, &parent->base.profiles, base.list))
643 return p;
644 p = parent;
645@@ -648,7 +646,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
646 }
647
648 /* is next another profile in the namespace */
649- p = list_entry_next(p, base.list);
650+ p = list_next_entry(p, base.list);
651 if (!list_entry_is_head(p, &ns->base.profiles, base.list))
652 return p;
653
654
655commit 645801f1ddd183109c011e5ecee23ed3fdcae244
656Author: Jeff Mahoney <jeffm@suse.com>
657Date: Fri Nov 6 15:17:30 2015 -0500
658
659 apparmor: allow SYS_CAP_RESOURCE to be sufficient to prlimit another task
660
661 While using AppArmor, SYS_CAP_RESOURCE is insufficient to call prlimit
662 on another task. The only other example of a AppArmor mediating access to
663 another, already running, task (ignoring fork+exec) is ptrace.
664
665 The AppArmor model for ptrace is that one of the following must be true:
666 1) The tracer is unconfined
667 2) The tracer is in complain mode
668 3) The tracer and tracee are confined by the same profile
669 4) The tracer is confined but has SYS_CAP_PTRACE
670
671 1), 2, and 3) are already true for setrlimit.
672
673 We can match the ptrace model just by allowing CAP_SYS_RESOURCE.
674
675 We still test the values of the rlimit since it can always be overridden
676 using a value that means unlimited for a particular resource.
677
678 Signed-off-by: Jeff Mahoney <jeffm@suse.com>
679 Signed-off-by: John Johansen <john.johansen@canonical.com>
680
681diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
682index 748bf0c..67a6072 100644
683--- a/security/apparmor/resource.c
684+++ b/security/apparmor/resource.c
685@@ -101,9 +101,11 @@ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task,
686 /* TODO: extend resource control to handle other (non current)
687 * profiles. AppArmor rules currently have the implicit assumption
688 * that the task is setting the resource of a task confined with
689- * the same profile.
690+ * the same profile or that the task setting the resource of another
691+ * task has CAP_SYS_RESOURCE.
692 */
693- if (profile != task_profile ||
694+ if ((profile != task_profile &&
695+ aa_capable(profile, CAP_SYS_RESOURCE, 1)) ||
696 (profile->rlimits.mask & (1 << resource) &&
697 new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max))
698 error = -EACCES;
699
700commit 2be4aed1f3332d87273eb593944332054f3cffac
701Author: John Johansen <john.johansen@canonical.com>
702Date: Thu Jun 2 02:37:02 2016 -0700
703
704 apparmor: add missing id bounds check on dfa verification
705
706 Signed-off-by: John Johansen <john.johansen@canonical.com>
707
708diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
709index 001c43a..a1c04fe 100644
710--- a/security/apparmor/include/match.h
711+++ b/security/apparmor/include/match.h
712@@ -62,6 +62,7 @@ struct table_set_header {
713 #define YYTD_ID_ACCEPT2 6
714 #define YYTD_ID_NXT 7
715 #define YYTD_ID_TSIZE 8
716+#define YYTD_ID_MAX 8
717
718 #define YYTD_DATA8 1
719 #define YYTD_DATA16 2
720diff --git a/security/apparmor/match.c b/security/apparmor/match.c
721index 727eb42..f9f57c6 100644
722--- a/security/apparmor/match.c
723+++ b/security/apparmor/match.c
724@@ -47,6 +47,8 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
725 * it every time we use td_id as an index
726 */
727 th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
728+ if (th.td_id > YYTD_ID_MAX)
729+ goto out;
730 th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
731 th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
732 blob += sizeof(struct table_header);
733
734commit c7f87d3c3363b1a0c4724e627e5c8e640a883c89
735Author: John Johansen <john.johansen@canonical.com>
736Date: Wed Jun 15 09:57:55 2016 +0300
737
738 apparmor: don't check for vmalloc_addr if kvzalloc() failed
739
740 Signed-off-by: John Johansen <john.johansen@canonical.com>
741
742diff --git a/security/apparmor/match.c b/security/apparmor/match.c
743index f9f57c6..32b72eb 100644
744--- a/security/apparmor/match.c
745+++ b/security/apparmor/match.c
746@@ -75,14 +75,14 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
747 u32, be32_to_cpu);
748 else
749 goto fail;
750+ /* if table was vmalloced make sure the page tables are synced
751+ * before it is used, as it goes live to all cpus.
752+ */
753+ if (is_vmalloc_addr(table))
754+ vm_unmap_aliases();
755 }
756
757 out:
758- /* if table was vmalloced make sure the page tables are synced
759- * before it is used, as it goes live to all cpus.
760- */
761- if (is_vmalloc_addr(table))
762- vm_unmap_aliases();
763 return table;
764 fail:
765 kvfree(table);
766
767commit 0f7e61013dd1e67ebb54d58eee11ab009ceb5ef3
768Author: John Johansen <john.johansen@canonical.com>
769Date: Wed Jun 15 10:00:55 2016 +0300
770
771 apparmor: fix oops in profile_unpack() when policy_db is not present
772
773 BugLink: http://bugs.launchpad.net/bugs/1592547
774
775 If unpack_dfa() returns NULL due to the dfa not being present,
776 profile_unpack() is not checking if the dfa is not present (NULL).
777
778 Signed-off-by: John Johansen <john.johansen@canonical.com>
779
780diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
781index c841b12..dac2121 100644
782--- a/security/apparmor/policy_unpack.c
783+++ b/security/apparmor/policy_unpack.c
784@@ -583,6 +583,9 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
785 error = PTR_ERR(profile->policy.dfa);
786 profile->policy.dfa = NULL;
787 goto fail;
788+ } else if (!profile->policy.dfa) {
789+ error = -EPROTO;
790+ goto fail;
791 }
792 if (!unpack_u32(e, &profile->policy.start[0], "start"))
793 /* default start state */
794
795commit de4ca46ec035283928e8fa40797897cefcf6ec3e
796Author: John Johansen <john.johansen@canonical.com>
797Date: Wed Jun 22 18:01:08 2016 -0700
798
799 apparmor: fix module parameters can be changed after policy is locked
800
801 the policy_lock parameter is a one way switch that prevents policy
802 from being further modified. Unfortunately some of the module parameters
803 can effectively modify policy by turning off enforcement.
804
805 split policy_admin_capable into a view check and a full admin check,
806 and update the admin check to test the policy_lock parameter.
807
808 Signed-off-by: John Johansen <john.johansen@canonical.com>
809
810diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
811index c28b0f2..52275f0 100644
812--- a/security/apparmor/include/policy.h
813+++ b/security/apparmor/include/policy.h
814@@ -403,6 +403,8 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
815 return profile->audit;
816 }
817
818+bool policy_view_capable(void);
819+bool policy_admin_capable(void);
820 bool aa_may_manage_policy(int op);
821
822 #endif /* __AA_POLICY_H */
823diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
824index 7798e16..e83eefb 100644
825--- a/security/apparmor/lsm.c
826+++ b/security/apparmor/lsm.c
827@@ -728,51 +728,49 @@ __setup("apparmor=", apparmor_enabled_setup);
828 /* set global flag turning off the ability to load policy */
829 static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
830 {
831- if (!capable(CAP_MAC_ADMIN))
832+ if (!policy_admin_capable())
833 return -EPERM;
834- if (aa_g_lock_policy)
835- return -EACCES;
836 return param_set_bool(val, kp);
837 }
838
839 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
840 {
841- if (!capable(CAP_MAC_ADMIN))
842+ if (!policy_view_capable())
843 return -EPERM;
844 return param_get_bool(buffer, kp);
845 }
846
847 static int param_set_aabool(const char *val, const struct kernel_param *kp)
848 {
849- if (!capable(CAP_MAC_ADMIN))
850+ if (!policy_admin_capable())
851 return -EPERM;
852 return param_set_bool(val, kp);
853 }
854
855 static int param_get_aabool(char *buffer, const struct kernel_param *kp)
856 {
857- if (!capable(CAP_MAC_ADMIN))
858+ if (!policy_view_capable())
859 return -EPERM;
860 return param_get_bool(buffer, kp);
861 }
862
863 static int param_set_aauint(const char *val, const struct kernel_param *kp)
864 {
865- if (!capable(CAP_MAC_ADMIN))
866+ if (!policy_admin_capable())
867 return -EPERM;
868 return param_set_uint(val, kp);
869 }
870
871 static int param_get_aauint(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_uint(buffer, kp);
877 }
878
879 static int param_get_audit(char *buffer, struct kernel_param *kp)
880 {
881- if (!capable(CAP_MAC_ADMIN))
882+ if (!policy_view_capable())
883 return -EPERM;
884
885 if (!apparmor_enabled)
886@@ -784,7 +782,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp)
887 static int param_set_audit(const char *val, struct kernel_param *kp)
888 {
889 int i;
890- if (!capable(CAP_MAC_ADMIN))
891+ if (!policy_admin_capable())
892 return -EPERM;
893
894 if (!apparmor_enabled)
895@@ -805,7 +803,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp)
896
897 static int param_get_mode(char *buffer, struct kernel_param *kp)
898 {
899- if (!capable(CAP_MAC_ADMIN))
900+ if (!policy_admin_capable())
901 return -EPERM;
902
903 if (!apparmor_enabled)
904@@ -817,7 +815,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp)
905 static int param_set_mode(const char *val, struct kernel_param *kp)
906 {
907 int i;
908- if (!capable(CAP_MAC_ADMIN))
909+ if (!policy_admin_capable())
910 return -EPERM;
911
912 if (!apparmor_enabled)
913diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
914index 7807125..179e68d 100644
915--- a/security/apparmor/policy.c
916+++ b/security/apparmor/policy.c
917@@ -918,6 +918,22 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
918 &sa, NULL);
919 }
920
921+bool policy_view_capable(void)
922+{
923+ struct user_namespace *user_ns = current_user_ns();
924+ bool response = false;
925+
926+ if (ns_capable(user_ns, CAP_MAC_ADMIN))
927+ response = true;
928+
929+ return response;
930+}
931+
932+bool policy_admin_capable(void)
933+{
934+ return policy_view_capable() && !aa_g_lock_policy;
935+}
936+
937 /**
938 * aa_may_manage_policy - can the current task manage policy
939 * @op: the policy manipulation operation being done
940@@ -932,7 +948,7 @@ bool aa_may_manage_policy(int op)
941 return 0;
942 }
943
944- if (!capable(CAP_MAC_ADMIN)) {
945+ if (!policy_admin_capable()) {
946 audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
947 return 0;
948 }
949
950commit 46c339f46b83e4cf8098f599cd182e65e9d054fc
951Author: Heinrich Schuchardt <xypron.glpk@gmx.de>
952Date: Fri Jun 10 23:34:26 2016 +0200
953
954 apparmor: do not expose kernel stack
955
956 Do not copy uninitalized fields th.td_hilen, th.td_data.
957
958 Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
959 Signed-off-by: John Johansen <john.johansen@canonical.com>
960
961diff --git a/security/apparmor/match.c b/security/apparmor/match.c
962index 32b72eb..3f900fc 100644
963--- a/security/apparmor/match.c
964+++ b/security/apparmor/match.c
965@@ -63,7 +63,9 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
966
967 table = kvzalloc(tsize);
968 if (table) {
969- *table = th;
970+ table->td_id = th.td_id;
971+ table->td_flags = th.td_flags;
972+ table->td_lolen = th.td_lolen;
973 if (th.td_flags == YYTD_DATA8)
974 UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
975 u8, byte_to_byte);
976
977commit 7e65e8142b2ea4891581173d6e92fc337b02ff8b
978Author: John Johansen <john.johansen@canonical.com>
979Date: Sat Jul 9 23:46:33 2016 -0700
980
981 apparmor: fix arg_size computation for when setprocattr is null terminated
982
983 Signed-off-by: John Johansen <john.johansen@canonical.com>
984
985diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
986index e83eefb..ba8207b 100644
987--- a/security/apparmor/lsm.c
988+++ b/security/apparmor/lsm.c
989@@ -529,7 +529,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
990 if (!*args)
991 goto out;
992
993- arg_size = size - (args - (char *) value);
994+ arg_size = size - (args - (largs ? largs : (char *) value));
995 if (strcmp(name, "current") == 0) {
996 if (strcmp(command, "changehat") == 0) {
997 error = aa_setprocattr_changehat(args, arg_size,
998
999commit b661b13237991be6b5cdf0849f137c5ec58217bf
1000Author: John Johansen <john.johansen@canonical.com>
1001Date: Mon Oct 4 15:03:36 2010 -0700
1002
1003 UBUNTU: SAUCE: AppArmor: basic networking rules
1004
1005 Base support for network mediation.
1006
1007 Signed-off-by: John Johansen <john.johansen@canonical.com>
5882c9d4 1008
5882c9d4
AM
1009diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
1010index 9cdec70..d5b291e 100644
1011--- a/security/apparmor/.gitignore
1012+++ b/security/apparmor/.gitignore
1013@@ -1,5 +1,6 @@
1014 #
1015 # Generated include files
1016 #
1017+net_names.h
1018 capability_names.h
1019 rlim_names.h
fc63ffa9 1020diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
5882c9d4 1021index d693df8..5dbb72f 100644
fc63ffa9
AM
1022--- a/security/apparmor/Makefile
1023+++ b/security/apparmor/Makefile
5882c9d4 1024@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
ceaf2cfb 1025
fc63ffa9
AM
1026 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
1027 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
1028- resource.o sid.o file.o
1029+ resource.o sid.o file.o net.o
5882c9d4 1030 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
ceaf2cfb 1031
948a1326 1032-clean-files := capability_names.h rlim_names.h
1e8b8f9b 1033+clean-files := capability_names.h rlim_names.h net_names.h
ceaf2cfb 1034
ceaf2cfb 1035
948a1326 1036 # Build a lower case string table of capability names
5882c9d4
AM
1037@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
1038 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
1039 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
948a1326 1040
1e8b8f9b 1041+# Build a lower case string table of address family names
948a1326 1042+# Transform lines from
1e8b8f9b
AM
1043+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
1044+# #define AF_INET 2 /* Internet IP Protocol */
1045+# to
1046+# [1] = "local",
1047+# [2] = "inet",
1048+#
1049+# and build the securityfs entries for the mapping.
1050+# Transforms lines from
1051+# #define AF_INET 2 /* Internet IP Protocol */
948a1326 1052+# to
1e8b8f9b 1053+# #define AA_FS_AF_MASK "local inet"
ceaf2cfb 1054+quiet_cmd_make-af = GEN $@
948a1326 1055+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
1e8b8f9b
AM
1056+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
1057+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
1058+ echo "};" >> $@ ;\
1059+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
1060+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
1061+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
1062+
1063+# Build a lower case string table of sock type names
1064+# Transform lines from
1065+# SOCK_STREAM = 1,
1066+# to
1067+# [1] = "stream",
1068+quiet_cmd_make-sock = GEN $@
1069+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
1070+ sed $^ >>$@ -r -n \
1071+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
948a1326 1072+ echo "};" >> $@
1e8b8f9b
AM
1073
1074 # Build a lower case string table of rlimit names.
1075 # Transforms lines from
5882c9d4 1076@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
1e8b8f9b
AM
1077 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
1078
fc63ffa9 1079 $(obj)/capability.o : $(obj)/capability_names.h
1e8b8f9b 1080+$(obj)/net.o : $(obj)/net_names.h
fc63ffa9 1081 $(obj)/resource.o : $(obj)/rlim_names.h
5882c9d4 1082 $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
1e8b8f9b 1083 $(src)/Makefile
5882c9d4
AM
1084@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
1085 $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
1e8b8f9b 1086 $(src)/Makefile
948a1326 1087 $(call cmd,make-rlim)
1e8b8f9b
AM
1088+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
1089+ $(srctree)/include/linux/net.h \
1090+ $(src)/Makefile
948a1326 1091+ $(call cmd,make-af)
1e8b8f9b
AM
1092+ $(call cmd,make-sock)
1093diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
0776672e 1094index 729e595..181d961 100644
1e8b8f9b
AM
1095--- a/security/apparmor/apparmorfs.c
1096+++ b/security/apparmor/apparmorfs.c
0776672e 1097@@ -807,6 +807,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
5882c9d4 1098 AA_FS_DIR("policy", aa_fs_entry_policy),
1e8b8f9b
AM
1099 AA_FS_DIR("domain", aa_fs_entry_domain),
1100 AA_FS_DIR("file", aa_fs_entry_file),
1101+ AA_FS_DIR("network", aa_fs_entry_network),
1102 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
1103 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
5882c9d4 1104 AA_FS_DIR("caps", aa_fs_entry_caps),
1e8b8f9b 1105diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
c2c0f25c 1106index ba3dfd1..5d3c419 100644
1e8b8f9b
AM
1107--- a/security/apparmor/include/audit.h
1108+++ b/security/apparmor/include/audit.h
c2c0f25c 1109@@ -125,6 +125,10 @@ struct apparmor_audit_data {
1e8b8f9b 1110 u32 denied;
5882c9d4 1111 kuid_t ouid;
1e8b8f9b
AM
1112 } fs;
1113+ struct {
1114+ int type, protocol;
1115+ struct sock *sk;
1116+ } net;
1117 };
1118 };
1119
fc63ffa9 1120diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
ceaf2cfb 1121new file mode 100644
1e8b8f9b 1122index 0000000..cb8a121
ceaf2cfb 1123--- /dev/null
fc63ffa9 1124+++ b/security/apparmor/include/net.h
1e8b8f9b 1125@@ -0,0 +1,44 @@
9474138d
AM
1126+/*
1127+ * AppArmor security module
1128+ *
fc63ffa9 1129+ * This file contains AppArmor network mediation definitions.
9474138d
AM
1130+ *
1131+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 1132+ * Copyright 2009-2012 Canonical Ltd.
9474138d
AM
1133+ *
1134+ * This program is free software; you can redistribute it and/or
1135+ * modify it under the terms of the GNU General Public License as
1136+ * published by the Free Software Foundation, version 2 of the
1137+ * License.
1138+ */
1139+
fc63ffa9
AM
1140+#ifndef __AA_NET_H
1141+#define __AA_NET_H
2380c486 1142+
fc63ffa9 1143+#include <net/sock.h>
9474138d 1144+
1e8b8f9b
AM
1145+#include "apparmorfs.h"
1146+
fc63ffa9
AM
1147+/* struct aa_net - network confinement data
1148+ * @allowed: basic network families permissions
1149+ * @audit_network: which network permissions to force audit
1150+ * @quiet_network: which network permissions to quiet rejects
1151+ */
1152+struct aa_net {
1153+ u16 allow[AF_MAX];
1154+ u16 audit[AF_MAX];
1155+ u16 quiet[AF_MAX];
1156+};
ceaf2cfb 1157+
1e8b8f9b
AM
1158+extern struct aa_fs_entry aa_fs_entry_network[];
1159+
fc63ffa9
AM
1160+extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
1161+ int type, int protocol, struct sock *sk);
1162+extern int aa_revalidate_sk(int op, struct sock *sk);
ceaf2cfb 1163+
fc63ffa9
AM
1164+static inline void aa_free_net_rules(struct aa_net *new)
1165+{
1166+ /* NOP */
ceaf2cfb
AM
1167+}
1168+
fc63ffa9
AM
1169+#endif /* __AA_NET_H */
1170diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
0776672e 1171index 52275f0..4fc4dac 100644
fc63ffa9
AM
1172--- a/security/apparmor/include/policy.h
1173+++ b/security/apparmor/include/policy.h
1174@@ -27,6 +27,7 @@
1175 #include "capability.h"
1176 #include "domain.h"
1177 #include "file.h"
1178+#include "net.h"
1179 #include "resource.h"
1180
5882c9d4
AM
1181 extern const char *const aa_profile_mode_names[];
1182@@ -176,6 +177,7 @@ struct aa_replacedby {
1e8b8f9b 1183 * @policy: general match rules governing policy
fc63ffa9
AM
1184 * @file: The set of rules governing basic file access and domain transitions
1185 * @caps: capabilities for the profile
1186+ * @net: network controls for the profile
1187 * @rlimits: rlimits for the profile
1188 *
5882c9d4
AM
1189 * @dents: dentries for the profiles file entries in apparmorfs
1190@@ -217,6 +219,7 @@ struct aa_profile {
1e8b8f9b 1191 struct aa_policydb policy;
fc63ffa9
AM
1192 struct aa_file_rules file;
1193 struct aa_caps caps;
1194+ struct aa_net net;
1195 struct aa_rlimit rlimits;
fc63ffa9 1196
5882c9d4 1197 unsigned char *hash;
fc63ffa9 1198diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
0776672e 1199index ba8207b..88d3b0a 100644
fc63ffa9
AM
1200--- a/security/apparmor/lsm.c
1201+++ b/security/apparmor/lsm.c
948a1326 1202@@ -32,6 +32,7 @@
fc63ffa9
AM
1203 #include "include/context.h"
1204 #include "include/file.h"
1205 #include "include/ipc.h"
1206+#include "include/net.h"
1207 #include "include/path.h"
1208 #include "include/policy.h"
1209 #include "include/procattr.h"
0776672e 1210@@ -584,6 +585,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
fc63ffa9
AM
1211 return error;
1212 }
1213
1214+static int apparmor_socket_create(int family, int type, int protocol, int kern)
ceaf2cfb 1215+{
fc63ffa9
AM
1216+ struct aa_profile *profile;
1217+ int error = 0;
ceaf2cfb 1218+
fc63ffa9
AM
1219+ if (kern)
1220+ return 0;
ceaf2cfb 1221+
fc63ffa9
AM
1222+ profile = __aa_current_profile();
1223+ if (!unconfined(profile))
1224+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
1225+ NULL);
1226+ return error;
1227+}
ceaf2cfb 1228+
fc63ffa9
AM
1229+static int apparmor_socket_bind(struct socket *sock,
1230+ struct sockaddr *address, int addrlen)
9474138d 1231+{
fc63ffa9 1232+ struct sock *sk = sock->sk;
9474138d 1233+
fc63ffa9
AM
1234+ return aa_revalidate_sk(OP_BIND, sk);
1235+}
ceaf2cfb 1236+
fc63ffa9
AM
1237+static int apparmor_socket_connect(struct socket *sock,
1238+ struct sockaddr *address, int addrlen)
1239+{
1240+ struct sock *sk = sock->sk;
ceaf2cfb 1241+
fc63ffa9 1242+ return aa_revalidate_sk(OP_CONNECT, sk);
9474138d
AM
1243+}
1244+
fc63ffa9 1245+static int apparmor_socket_listen(struct socket *sock, int backlog)
9474138d 1246+{
fc63ffa9
AM
1247+ struct sock *sk = sock->sk;
1248+
1249+ return aa_revalidate_sk(OP_LISTEN, sk);
9474138d
AM
1250+}
1251+
fc63ffa9 1252+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
9474138d 1253+{
fc63ffa9 1254+ struct sock *sk = sock->sk;
9474138d 1255+
fc63ffa9
AM
1256+ return aa_revalidate_sk(OP_ACCEPT, sk);
1257+}
9474138d 1258+
fc63ffa9
AM
1259+static int apparmor_socket_sendmsg(struct socket *sock,
1260+ struct msghdr *msg, int size)
76514441 1261+{
fc63ffa9 1262+ struct sock *sk = sock->sk;
76514441 1263+
fc63ffa9 1264+ return aa_revalidate_sk(OP_SENDMSG, sk);
76514441
AM
1265+}
1266+
fc63ffa9
AM
1267+static int apparmor_socket_recvmsg(struct socket *sock,
1268+ struct msghdr *msg, int size, int flags)
1269+{
1270+ struct sock *sk = sock->sk;
ceaf2cfb 1271+
fc63ffa9
AM
1272+ return aa_revalidate_sk(OP_RECVMSG, sk);
1273+}
ceaf2cfb 1274+
fc63ffa9
AM
1275+static int apparmor_socket_getsockname(struct socket *sock)
1276+{
1277+ struct sock *sk = sock->sk;
ceaf2cfb 1278+
fc63ffa9 1279+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
9474138d
AM
1280+}
1281+
fc63ffa9 1282+static int apparmor_socket_getpeername(struct socket *sock)
9474138d 1283+{
fc63ffa9 1284+ struct sock *sk = sock->sk;
9474138d 1285+
fc63ffa9
AM
1286+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
1287+}
ceaf2cfb 1288+
fc63ffa9
AM
1289+static int apparmor_socket_getsockopt(struct socket *sock, int level,
1290+ int optname)
1291+{
1292+ struct sock *sk = sock->sk;
ceaf2cfb 1293+
fc63ffa9
AM
1294+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
1295+}
ceaf2cfb 1296+
fc63ffa9
AM
1297+static int apparmor_socket_setsockopt(struct socket *sock, int level,
1298+ int optname)
1299+{
1300+ struct sock *sk = sock->sk;
2380c486 1301+
fc63ffa9
AM
1302+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
1303+}
ceaf2cfb 1304+
fc63ffa9
AM
1305+static int apparmor_socket_shutdown(struct socket *sock, int how)
1306+{
1307+ struct sock *sk = sock->sk;
ceaf2cfb 1308+
fc63ffa9 1309+ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
ceaf2cfb 1310+}
948a1326 1311+
c2c0f25c
AM
1312 static struct security_hook_list apparmor_hooks[] = {
1313 LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
1314 LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
0776672e 1315@@ -613,6 +712,19 @@ static struct security_hook_list apparmor_hooks[] = {
c2c0f25c
AM
1316 LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
1317 LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
5d26c04f 1318
c2c0f25c
AM
1319+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
1320+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
1321+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
1322+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
1323+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
1324+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
1325+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
1326+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
1327+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
1328+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
1329+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
1330+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
1331+
1332 LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
1333 LSM_HOOK_INIT(cred_free, apparmor_cred_free),
1334 LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
fc63ffa9 1335diff --git a/security/apparmor/net.c b/security/apparmor/net.c
ceaf2cfb 1336new file mode 100644
2dfbb274 1337index 0000000..003dd18
ceaf2cfb 1338--- /dev/null
fc63ffa9 1339+++ b/security/apparmor/net.c
1e8b8f9b 1340@@ -0,0 +1,162 @@
2380c486 1341+/*
9474138d
AM
1342+ * AppArmor security module
1343+ *
fc63ffa9 1344+ * This file contains AppArmor network mediation
2380c486 1345+ *
9474138d 1346+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 1347+ * Copyright 2009-2012 Canonical Ltd.
2380c486 1348+ *
9474138d
AM
1349+ * This program is free software; you can redistribute it and/or
1350+ * modify it under the terms of the GNU General Public License as
1351+ * published by the Free Software Foundation, version 2 of the
1352+ * License.
2380c486
JR
1353+ */
1354+
9474138d
AM
1355+#include "include/apparmor.h"
1356+#include "include/audit.h"
1357+#include "include/context.h"
fc63ffa9 1358+#include "include/net.h"
9474138d 1359+#include "include/policy.h"
2380c486 1360+
1e8b8f9b
AM
1361+#include "net_names.h"
1362+
1363+struct aa_fs_entry aa_fs_entry_network[] = {
1364+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
1365+ { }
9474138d
AM
1366+};
1367+
fc63ffa9 1368+/* audit callback for net specific fields */
76514441 1369+static void audit_cb(struct audit_buffer *ab, void *va)
9474138d 1370+{
76514441 1371+ struct common_audit_data *sa = va;
9474138d 1372+
fc63ffa9 1373+ audit_log_format(ab, " family=");
1e8b8f9b
AM
1374+ if (address_family_names[sa->u.net->family]) {
1375+ audit_log_string(ab, address_family_names[sa->u.net->family]);
fc63ffa9 1376+ } else {
1e8b8f9b 1377+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
fc63ffa9 1378+ }
fc63ffa9 1379+ audit_log_format(ab, " sock_type=");
1e8b8f9b
AM
1380+ if (sock_type_names[sa->aad->net.type]) {
1381+ audit_log_string(ab, sock_type_names[sa->aad->net.type]);
fc63ffa9 1382+ } else {
1e8b8f9b 1383+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
fc63ffa9 1384+ }
1e8b8f9b 1385+ audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
2380c486
JR
1386+}
1387+
1388+/**
fc63ffa9
AM
1389+ * audit_net - audit network access
1390+ * @profile: profile being enforced (NOT NULL)
1391+ * @op: operation being checked
1392+ * @family: network family
1393+ * @type: network type
1394+ * @protocol: network protocol
1395+ * @sk: socket auditing is being applied to
1396+ * @error: error code for failure else 0
ceaf2cfb 1397+ *
fc63ffa9 1398+ * Returns: %0 or sa->error else other errorcode on failure
2380c486 1399+ */
fc63ffa9
AM
1400+static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
1401+ int protocol, struct sock *sk, int error)
2380c486 1402+{
fc63ffa9
AM
1403+ int audit_type = AUDIT_APPARMOR_AUTO;
1404+ struct common_audit_data sa;
1e8b8f9b
AM
1405+ struct apparmor_audit_data aad = { };
1406+ struct lsm_network_audit net = { };
fc63ffa9 1407+ if (sk) {
0c3ec466 1408+ sa.type = LSM_AUDIT_DATA_NET;
fc63ffa9 1409+ } else {
0c3ec466 1410+ sa.type = LSM_AUDIT_DATA_NONE;
2380c486 1411+ }
fc63ffa9 1412+ /* todo fill in socket addr info */
1e8b8f9b
AM
1413+ sa.aad = &aad;
1414+ sa.u.net = &net;
1415+ sa.aad->op = op,
1416+ sa.u.net->family = family;
1417+ sa.u.net->sk = sk;
1418+ sa.aad->net.type = type;
1419+ sa.aad->net.protocol = protocol;
1420+ sa.aad->error = error;
1421+
1422+ if (likely(!sa.aad->error)) {
1423+ u16 audit_mask = profile->net.audit[sa.u.net->family];
fc63ffa9 1424+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
1e8b8f9b 1425+ !(1 << sa.aad->net.type & audit_mask)))
ceaf2cfb 1426+ return 0;
fc63ffa9
AM
1427+ audit_type = AUDIT_APPARMOR_AUDIT;
1428+ } else {
1e8b8f9b 1429+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
fc63ffa9 1430+ u16 kill_mask = 0;
1e8b8f9b 1431+ u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
9474138d 1432+
fc63ffa9
AM
1433+ if (denied & kill_mask)
1434+ audit_type = AUDIT_APPARMOR_KILL;
9474138d 1435+
fc63ffa9
AM
1436+ if ((denied & quiet_mask) &&
1437+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1438+ AUDIT_MODE(profile) != AUDIT_ALL)
1e8b8f9b 1439+ return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
9474138d
AM
1440+ }
1441+
fc63ffa9 1442+ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
ceaf2cfb
AM
1443+}
1444+
2380c486 1445+/**
fc63ffa9
AM
1446+ * aa_net_perm - very course network access check
1447+ * @op: operation being checked
1448+ * @profile: profile being enforced (NOT NULL)
1449+ * @family: network family
1450+ * @type: network type
1451+ * @protocol: network protocol
2380c486 1452+ *
fc63ffa9 1453+ * Returns: %0 else error if permission denied
2380c486 1454+ */
fc63ffa9
AM
1455+int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
1456+ int protocol, struct sock *sk)
2380c486 1457+{
fc63ffa9
AM
1458+ u16 family_mask;
1459+ int error;
ceaf2cfb 1460+
fc63ffa9
AM
1461+ if ((family < 0) || (family >= AF_MAX))
1462+ return -EINVAL;
ceaf2cfb 1463+
fc63ffa9
AM
1464+ if ((type < 0) || (type >= SOCK_MAX))
1465+ return -EINVAL;
76514441 1466+
fc63ffa9
AM
1467+ /* unix domain and netlink sockets are handled by ipc */
1468+ if (family == AF_UNIX || family == AF_NETLINK)
1469+ return 0;
76514441 1470+
fc63ffa9 1471+ family_mask = profile->net.allow[family];
2380c486 1472+
fc63ffa9 1473+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
ceaf2cfb 1474+
fc63ffa9 1475+ return audit_net(profile, op, family, type, protocol, sk, error);
2380c486
JR
1476+}
1477+
76514441 1478+/**
fc63ffa9
AM
1479+ * aa_revalidate_sk - Revalidate access to a sock
1480+ * @op: operation being checked
1481+ * @sk: sock being revalidated (NOT NULL)
76514441 1482+ *
fc63ffa9 1483+ * Returns: %0 else error if permission denied
76514441 1484+ */
fc63ffa9 1485+int aa_revalidate_sk(int op, struct sock *sk)
2380c486 1486+{
fc63ffa9
AM
1487+ struct aa_profile *profile;
1488+ int error = 0;
2380c486 1489+
fc63ffa9
AM
1490+ /* aa_revalidate_sk should not be called from interrupt context
1491+ * don't mediate these calls as they are not task related
1492+ */
1493+ if (in_interrupt())
1494+ return 0;
ceaf2cfb 1495+
fc63ffa9
AM
1496+ profile = __aa_current_profile();
1497+ if (!unconfined(profile))
1498+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
1499+ sk->sk_protocol, sk);
2380c486 1500+
fc63ffa9 1501+ return error;
2380c486 1502+}
fc63ffa9 1503diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
0776672e 1504index 179e68d..f1a8541 100644
fc63ffa9
AM
1505--- a/security/apparmor/policy.c
1506+++ b/security/apparmor/policy.c
5882c9d4 1507@@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile)
fc63ffa9
AM
1508
1509 aa_free_file_rules(&profile->file);
1510 aa_free_cap_rules(&profile->caps);
1511+ aa_free_net_rules(&profile->net);
1512 aa_free_rlimit_rules(&profile->rlimits);
1513
5882c9d4 1514 kzfree(profile->dirname);
fc63ffa9 1515diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
0776672e 1516index dac2121..0107bc4 100644
fc63ffa9
AM
1517--- a/security/apparmor/policy_unpack.c
1518+++ b/security/apparmor/policy_unpack.c
1e8b8f9b 1519@@ -193,6 +193,19 @@ fail:
fc63ffa9
AM
1520 return 0;
1521 }
1522
1523+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
2380c486 1524+{
fc63ffa9
AM
1525+ if (unpack_nameX(e, AA_U16, name)) {
1526+ if (!inbounds(e, sizeof(u16)))
1527+ return 0;
1528+ if (data)
1529+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
1530+ e->pos += sizeof(u16);
1531+ return 1;
2380c486 1532+ }
2380c486
JR
1533+ return 0;
1534+}
1535+
fc63ffa9
AM
1536 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
1537 {
1538 if (unpack_nameX(e, AA_U32, name)) {
5882c9d4 1539@@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
1540 {
1541 struct aa_profile *profile = NULL;
1542 const char *name = NULL;
2380c486 1543+ size_t size = 0;
1e8b8f9b 1544 int i, error = -EPROTO;
fc63ffa9
AM
1545 kernel_cap_t tmpcap;
1546 u32 tmp;
5882c9d4 1547@@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
1548 if (!unpack_rlimits(e, profile))
1549 goto fail;
1550
ceaf2cfb 1551+ size = unpack_array(e, "net_allowed_af");
2380c486 1552+ if (size) {
2380c486
JR
1553+
1554+ for (i = 0; i < size; i++) {
fc63ffa9
AM
1555+ /* discard extraneous rules that this kernel will
1556+ * never request
1557+ */
1efb82ae 1558+ if (i >= AF_MAX) {
fc63ffa9
AM
1559+ u16 tmp;
1560+ if (!unpack_u16(e, &tmp, NULL) ||
1561+ !unpack_u16(e, &tmp, NULL) ||
1562+ !unpack_u16(e, &tmp, NULL))
1563+ goto fail;
1564+ continue;
1565+ }
76514441 1566+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
2380c486 1567+ goto fail;
ceaf2cfb 1568+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
2380c486 1569+ goto fail;
ceaf2cfb 1570+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
2380c486
JR
1571+ goto fail;
1572+ }
ceaf2cfb 1573+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
2380c486 1574+ goto fail;
2380c486 1575+ }
1e8b8f9b
AM
1576+ /*
1577+ * allow unix domain and netlink sockets they are handled
1578+ * by IPC
1579+ */
76514441
AM
1580+ profile->net.allow[AF_UNIX] = 0xffff;
1581+ profile->net.allow[AF_NETLINK] = 0xffff;
2380c486 1582+
1e8b8f9b
AM
1583 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
1584 /* generic policy dfa - optional and may be NULL */
1585 profile->policy.dfa = unpack_dfa(e);
5882c9d4 1586
0776672e
AM
1587commit 64c5e24470a219c79c2870c63f18f6bd55648b1b
1588Author: John Johansen <john.johansen@canonical.com>
1589Date: Fri Jun 29 17:34:00 2012 -0700
5882c9d4 1590
0776672e
AM
1591 apparmor: Fix quieting of audit messages for network mediation
1592
1593 If a profile specified a quieting of network denials for a given rule by
1594 either the quiet or deny rule qualifiers, the resultant quiet mask for
1595 denied requests was applied incorrectly, resulting in two potential bugs.
1596 1. The misapplied quiet mask would prevent denials from being correctly
1597 tested against the kill mask/mode. Thus network access requests that
1598 should have resulted in the application being killed did not.
1599
1600 2. The actual quieting of the denied network request was not being applied.
1601 This would result in network rejections always being logged even when
1602 they had been specifically marked as quieted.
1603
1604 Signed-off-by: John Johansen <john.johansen@canonical.com>
5882c9d4
AM
1605
1606diff --git a/security/apparmor/net.c b/security/apparmor/net.c
1607index 003dd18..6e6e5c9 100644
1608--- a/security/apparmor/net.c
1609+++ b/security/apparmor/net.c
1610@@ -88,7 +88,7 @@ static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
1611 } else {
1612 u16 quiet_mask = profile->net.quiet[sa.u.net->family];
1613 u16 kill_mask = 0;
1614- u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
1615+ u16 denied = (1 << sa.aad->net.type);
1616
1617 if (denied & kill_mask)
1618 audit_type = AUDIT_APPARMOR_KILL;
5882c9d4 1619
0776672e
AM
1620commit f7cef61751a2382fb4ea26c18736d7552ffdb24a
1621Author: John Johansen <john.johansen@canonical.com>
1622Date: Wed May 16 10:58:05 2012 -0700
1e8b8f9b 1623
0776672e
AM
1624 UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
1625
1626 Add the ability for apparmor to do mediation of mount operations. Mount
1627 rules require an updated apparmor_parser (2.8 series) for policy compilation.
1628
1629 The basic form of the rules are.
1630
1631 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
1632 [audit] [deny] remount [conds]* [path],
1633 [audit] [deny] umount [conds]* [path],
1634 [audit] [deny] pivotroot [oldroot=<value>] <path>
1635
1636 remount is just a short cut for mount options=remount
1637
1638 where [conds] can be
1639 fstype=<expr>
1640 options=<expr>
1641
1642 Example mount commands
1643 mount, # allow all mounts, but not umount or pivotroot
1644
1645 mount fstype=procfs, # allow mounting procfs anywhere
1646
1647 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
1648
1649 mount /dev/sda -> /mnt,
1650
1651 mount /dev/sd** -> /mnt/**,
1652
1653 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
1654
1655 umount,
1656
1657 umount /m*,
1658
1659 See the apparmor userspace for full documentation
1660
1661 Signed-off-by: John Johansen <john.johansen@canonical.com>
1662 Acked-by: Kees Cook <kees@ubuntu.com>
5882c9d4 1663
fc63ffa9 1664diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
5882c9d4 1665index 5dbb72f..89b3445 100644
fc63ffa9
AM
1666--- a/security/apparmor/Makefile
1667+++ b/security/apparmor/Makefile
1e8b8f9b
AM
1668@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
1669
948a1326 1670 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
fc63ffa9 1671 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
1e8b8f9b
AM
1672- resource.o sid.o file.o net.o
1673+ resource.o sid.o file.o net.o mount.o
5882c9d4 1674 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
fc63ffa9 1675
1e8b8f9b 1676 clean-files := capability_names.h rlim_names.h net_names.h
1e8b8f9b 1677diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
0776672e 1678index 181d961..5fb67f6 100644
1e8b8f9b
AM
1679--- a/security/apparmor/apparmorfs.c
1680+++ b/security/apparmor/apparmorfs.c
0776672e 1681@@ -800,7 +800,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
1e8b8f9b 1682
5882c9d4
AM
1683 static struct aa_fs_entry aa_fs_entry_policy[] = {
1684 AA_FS_FILE_BOOLEAN("set_load", 1),
1685- {}
1686+ { }
1687+};
1688+
1e8b8f9b
AM
1689+static struct aa_fs_entry aa_fs_entry_mount[] = {
1690+ AA_FS_FILE_STRING("mask", "mount umount"),
1691+ { }
1692+};
1693+
1694+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
1695+ AA_FS_FILE_BOOLEAN("profile", 1),
1696+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
1697+ { }
5882c9d4
AM
1698 };
1699
1e8b8f9b 1700 static struct aa_fs_entry aa_fs_entry_features[] = {
0776672e 1701@@ -808,6 +819,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
1e8b8f9b
AM
1702 AA_FS_DIR("domain", aa_fs_entry_domain),
1703 AA_FS_DIR("file", aa_fs_entry_file),
1704 AA_FS_DIR("network", aa_fs_entry_network),
1705+ AA_FS_DIR("mount", aa_fs_entry_mount),
1706+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
1707 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
1708 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
5882c9d4 1709 AA_FS_DIR("caps", aa_fs_entry_caps),
1e8b8f9b 1710diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
0776672e 1711index 3a7f1da..c2a8b8a 100644
1e8b8f9b
AM
1712--- a/security/apparmor/audit.c
1713+++ b/security/apparmor/audit.c
1714@@ -44,6 +44,10 @@ const char *const op_table[] = {
1715 "file_mmap",
1716 "file_mprotect",
1717
1718+ "pivotroot",
1719+ "mount",
1720+ "umount",
1721+
1722 "create",
1723 "post_create",
1724 "bind",
1725diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
0776672e 1726index fc3036b..f2a83b4 100644
1e8b8f9b
AM
1727--- a/security/apparmor/domain.c
1728+++ b/security/apparmor/domain.c
c2c0f25c 1729@@ -236,7 +236,7 @@ static const char *next_name(int xtype, const char *name)
1e8b8f9b
AM
1730 *
1731 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
1732 */
1733-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
1734+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
1735 {
1736 struct aa_profile *new_profile = NULL;
1737 struct aa_namespace *ns = profile->ns;
1738diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
c2c0f25c 1739index e4ea626..ce6ff6a 100644
1e8b8f9b
AM
1740--- a/security/apparmor/include/apparmor.h
1741+++ b/security/apparmor/include/apparmor.h
5882c9d4 1742@@ -30,8 +30,9 @@
1e8b8f9b
AM
1743 #define AA_CLASS_NET 4
1744 #define AA_CLASS_RLIMITS 5
1745 #define AA_CLASS_DOMAIN 6
1746+#define AA_CLASS_MOUNT 7
1747
1748-#define AA_CLASS_LAST AA_CLASS_DOMAIN
1749+#define AA_CLASS_LAST AA_CLASS_MOUNT
1750
1751 /* Control parameters settable through module/boot flags */
1752 extern enum audit_mode aa_g_audit;
1753diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
c2c0f25c 1754index 5d3c419..b9f1d57 100644
1e8b8f9b
AM
1755--- a/security/apparmor/include/audit.h
1756+++ b/security/apparmor/include/audit.h
5882c9d4 1757@@ -72,6 +72,10 @@ enum aa_ops {
1e8b8f9b
AM
1758 OP_FMMAP,
1759 OP_FMPROT,
1760
1761+ OP_PIVOTROOT,
1762+ OP_MOUNT,
1763+ OP_UMOUNT,
1764+
1765 OP_CREATE,
1766 OP_POST_CREATE,
1767 OP_BIND,
c2c0f25c 1768@@ -120,6 +124,13 @@ struct apparmor_audit_data {
1e8b8f9b
AM
1769 unsigned long max;
1770 } rlim;
1771 struct {
1772+ const char *src_name;
1773+ const char *type;
1774+ const char *trans;
1775+ const char *data;
1776+ unsigned long flags;
1777+ } mnt;
1778+ struct {
1779 const char *target;
1780 u32 request;
1781 u32 denied;
1782diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
1783index de04464..a3f70c5 100644
1784--- a/security/apparmor/include/domain.h
1785+++ b/security/apparmor/include/domain.h
1786@@ -23,6 +23,8 @@ struct aa_domain {
1787 char **table;
1788 };
1789
1790+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
1791+
1792 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
1793 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
1794 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
1795diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
ceaf2cfb 1796new file mode 100644
0776672e 1797index 0000000..a43b1d6
ceaf2cfb 1798--- /dev/null
1e8b8f9b
AM
1799+++ b/security/apparmor/include/mount.h
1800@@ -0,0 +1,54 @@
2380c486 1801+/*
9474138d
AM
1802+ * AppArmor security module
1803+ *
1e8b8f9b 1804+ * This file contains AppArmor file mediation function definitions.
2380c486 1805+ *
1e8b8f9b 1806+ * Copyright 2012 Canonical Ltd.
2380c486 1807+ *
9474138d
AM
1808+ * This program is free software; you can redistribute it and/or
1809+ * modify it under the terms of the GNU General Public License as
1810+ * published by the Free Software Foundation, version 2 of the
1811+ * License.
2380c486
JR
1812+ */
1813+
1e8b8f9b
AM
1814+#ifndef __AA_MOUNT_H
1815+#define __AA_MOUNT_H
fc63ffa9 1816+
1e8b8f9b
AM
1817+#include <linux/fs.h>
1818+#include <linux/path.h>
2380c486 1819+
1e8b8f9b
AM
1820+#include "domain.h"
1821+#include "policy.h"
76514441 1822+
1e8b8f9b
AM
1823+/* mount perms */
1824+#define AA_MAY_PIVOTROOT 0x01
1825+#define AA_MAY_MOUNT 0x02
1826+#define AA_MAY_UMOUNT 0x04
1827+#define AA_AUDIT_DATA 0x40
1828+#define AA_CONT_MATCH 0x40
fc63ffa9 1829+
1e8b8f9b 1830+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
fc63ffa9 1831+
0776672e 1832+int aa_remount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 1833+ unsigned long flags, void *data);
fc63ffa9 1834+
0776672e 1835+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 1836+ const char *old_name, unsigned long flags);
fc63ffa9 1837+
fc63ffa9 1838+
0776672e 1839+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
1e8b8f9b 1840+ unsigned long flags);
fc63ffa9 1841+
0776672e 1842+int aa_move_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b
AM
1843+ const char *old_name);
1844+
1845+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
0776672e 1846+ const struct path *path, const char *type, unsigned long flags,
1e8b8f9b
AM
1847+ void *data);
1848+
1849+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
1850+
0776672e
AM
1851+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
1852+ const struct path *new_path);
1e8b8f9b
AM
1853+
1854+#endif /* __AA_MOUNT_H */
1855diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
0776672e 1856index 88d3b0a..432cbd3 100644
1e8b8f9b
AM
1857--- a/security/apparmor/lsm.c
1858+++ b/security/apparmor/lsm.c
1859@@ -36,6 +36,7 @@
1860 #include "include/path.h"
1861 #include "include/policy.h"
1862 #include "include/procattr.h"
1863+#include "include/mount.h"
1864
1865 /* Flag indicating whether initialization completed */
1866 int apparmor_initialized __initdata;
0776672e 1867@@ -469,6 +470,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1e8b8f9b
AM
1868 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1869 }
1870
0776672e
AM
1871+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
1872+ const char *type, unsigned long flags, void *data)
2380c486 1873+{
1e8b8f9b
AM
1874+ struct aa_profile *profile;
1875+ int error = 0;
76514441 1876+
1e8b8f9b
AM
1877+ /* Discard magic */
1878+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1879+ flags &= ~MS_MGC_MSK;
2380c486 1880+
1e8b8f9b
AM
1881+ flags &= ~AA_MS_IGNORE_MASK;
1882+
1883+ profile = __aa_current_profile();
1884+ if (!unconfined(profile)) {
1885+ if (flags & MS_REMOUNT)
1886+ error = aa_remount(profile, path, flags, data);
1887+ else if (flags & MS_BIND)
1888+ error = aa_bind_mount(profile, path, dev_name, flags);
1889+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
1890+ MS_UNBINDABLE))
1891+ error = aa_mount_change_type(profile, path, flags);
1892+ else if (flags & MS_MOVE)
1893+ error = aa_move_mount(profile, path, dev_name);
1894+ else
1895+ error = aa_new_mount(profile, dev_name, path, type,
1896+ flags, data);
2380c486 1897+ }
1e8b8f9b
AM
1898+ return error;
1899+}
2380c486 1900+
1e8b8f9b
AM
1901+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
1902+{
1903+ struct aa_profile *profile;
1904+ int error = 0;
1905+
1906+ profile = __aa_current_profile();
1907+ if (!unconfined(profile))
1908+ error = aa_umount(profile, mnt, flags);
1909+
1910+ return error;
2380c486
JR
1911+}
1912+
0776672e
AM
1913+static int apparmor_sb_pivotroot(const struct path *old_path,
1914+ const struct path *new_path)
2380c486 1915+{
1e8b8f9b
AM
1916+ struct aa_profile *profile;
1917+ int error = 0;
1918+
1919+ profile = __aa_current_profile();
1920+ if (!unconfined(profile))
1921+ error = aa_pivotroot(profile, old_path, new_path);
1922+
1923+ return error;
2380c486
JR
1924+}
1925+
1e8b8f9b
AM
1926 static int apparmor_getprocattr(struct task_struct *task, char *name,
1927 char **value)
1928 {
0776672e 1929@@ -689,6 +745,10 @@ static struct security_hook_list apparmor_hooks[] = {
c2c0f25c
AM
1930 LSM_HOOK_INIT(capget, apparmor_capget),
1931 LSM_HOOK_INIT(capable, apparmor_capable),
1e8b8f9b 1932
c2c0f25c
AM
1933+ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
1934+ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
1935+ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
1936+
1937 LSM_HOOK_INIT(path_link, apparmor_path_link),
1938 LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
1939 LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
1e8b8f9b
AM
1940diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
1941new file mode 100644
0776672e 1942index 0000000..9cf9170
1e8b8f9b
AM
1943--- /dev/null
1944+++ b/security/apparmor/mount.c
1945@@ -0,0 +1,620 @@
1946+/*
1947+ * AppArmor security module
fc63ffa9 1948+ *
1e8b8f9b 1949+ * This file contains AppArmor mediation of files
ceaf2cfb 1950+ *
1e8b8f9b
AM
1951+ * Copyright (C) 1998-2008 Novell/SUSE
1952+ * Copyright 2009-2012 Canonical Ltd.
1953+ *
1954+ * This program is free software; you can redistribute it and/or
1955+ * modify it under the terms of the GNU General Public License as
1956+ * published by the Free Software Foundation, version 2 of the
1957+ * License.
ceaf2cfb 1958+ */
2380c486 1959+
1e8b8f9b
AM
1960+#include <linux/fs.h>
1961+#include <linux/mount.h>
1962+#include <linux/namei.h>
2380c486 1963+
1e8b8f9b
AM
1964+#include "include/apparmor.h"
1965+#include "include/audit.h"
1966+#include "include/context.h"
1967+#include "include/domain.h"
1968+#include "include/file.h"
1969+#include "include/match.h"
1970+#include "include/mount.h"
1971+#include "include/path.h"
1972+#include "include/policy.h"
ceaf2cfb 1973+
2380c486 1974+
1e8b8f9b
AM
1975+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
1976+{
1977+ if (flags & MS_RDONLY)
1978+ audit_log_format(ab, "ro");
1979+ else
1980+ audit_log_format(ab, "rw");
1981+ if (flags & MS_NOSUID)
1982+ audit_log_format(ab, ", nosuid");
1983+ if (flags & MS_NODEV)
1984+ audit_log_format(ab, ", nodev");
1985+ if (flags & MS_NOEXEC)
1986+ audit_log_format(ab, ", noexec");
1987+ if (flags & MS_SYNCHRONOUS)
1988+ audit_log_format(ab, ", sync");
1989+ if (flags & MS_REMOUNT)
1990+ audit_log_format(ab, ", remount");
1991+ if (flags & MS_MANDLOCK)
1992+ audit_log_format(ab, ", mand");
1993+ if (flags & MS_DIRSYNC)
1994+ audit_log_format(ab, ", dirsync");
1995+ if (flags & MS_NOATIME)
1996+ audit_log_format(ab, ", noatime");
1997+ if (flags & MS_NODIRATIME)
1998+ audit_log_format(ab, ", nodiratime");
1999+ if (flags & MS_BIND)
2000+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
2001+ if (flags & MS_MOVE)
2002+ audit_log_format(ab, ", move");
2003+ if (flags & MS_SILENT)
2004+ audit_log_format(ab, ", silent");
2005+ if (flags & MS_POSIXACL)
2006+ audit_log_format(ab, ", acl");
2007+ if (flags & MS_UNBINDABLE)
2008+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
2009+ ", unbindable");
2010+ if (flags & MS_PRIVATE)
2011+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
2012+ ", private");
2013+ if (flags & MS_SLAVE)
2014+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
2015+ ", slave");
2016+ if (flags & MS_SHARED)
2017+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
2018+ ", shared");
2019+ if (flags & MS_RELATIME)
2020+ audit_log_format(ab, ", relatime");
2021+ if (flags & MS_I_VERSION)
2022+ audit_log_format(ab, ", iversion");
2023+ if (flags & MS_STRICTATIME)
2024+ audit_log_format(ab, ", strictatime");
2025+ if (flags & MS_NOUSER)
2026+ audit_log_format(ab, ", nouser");
2380c486
JR
2027+}
2028+
ceaf2cfb 2029+/**
1e8b8f9b
AM
2030+ * audit_cb - call back for mount specific audit fields
2031+ * @ab: audit_buffer (NOT NULL)
2032+ * @va: audit struct to audit values of (NOT NULL)
ceaf2cfb 2033+ */
1e8b8f9b 2034+static void audit_cb(struct audit_buffer *ab, void *va)
2380c486 2035+{
1e8b8f9b 2036+ struct common_audit_data *sa = va;
9474138d 2037+
1e8b8f9b
AM
2038+ if (sa->aad->mnt.type) {
2039+ audit_log_format(ab, " fstype=");
2040+ audit_log_untrustedstring(ab, sa->aad->mnt.type);
2041+ }
2042+ if (sa->aad->mnt.src_name) {
2043+ audit_log_format(ab, " srcname=");
2044+ audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
2045+ }
2046+ if (sa->aad->mnt.trans) {
2047+ audit_log_format(ab, " trans=");
2048+ audit_log_untrustedstring(ab, sa->aad->mnt.trans);
2049+ }
2050+ if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
2051+ audit_log_format(ab, " flags=\"");
2052+ audit_mnt_flags(ab, sa->aad->mnt.flags);
2053+ audit_log_format(ab, "\"");
2054+ }
2055+ if (sa->aad->mnt.data) {
2056+ audit_log_format(ab, " options=");
2057+ audit_log_untrustedstring(ab, sa->aad->mnt.data);
2058+ }
9474138d 2059+}
2380c486 2060+
fc63ffa9 2061+/**
1e8b8f9b
AM
2062+ * audit_mount - handle the auditing of mount operations
2063+ * @profile: the profile being enforced (NOT NULL)
2064+ * @gfp: allocation flags
2065+ * @op: operation being mediated (NOT NULL)
2066+ * @name: name of object being mediated (MAYBE NULL)
2067+ * @src_name: src_name of object being mediated (MAYBE_NULL)
2068+ * @type: type of filesystem (MAYBE_NULL)
2069+ * @trans: name of trans (MAYBE NULL)
2070+ * @flags: filesystem idependent mount flags
2071+ * @data: filesystem mount flags
2072+ * @request: permissions requested
2073+ * @perms: the permissions computed for the request (NOT NULL)
2074+ * @info: extra information message (MAYBE NULL)
2075+ * @error: 0 if operation allowed else failure error code
9474138d 2076+ *
1e8b8f9b 2077+ * Returns: %0 or error on failure
76514441 2078+ */
1e8b8f9b
AM
2079+static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
2080+ const char *name, const char *src_name,
2081+ const char *type, const char *trans,
2082+ unsigned long flags, const void *data, u32 request,
2083+ struct file_perms *perms, const char *info, int error)
2380c486 2084+{
1e8b8f9b 2085+ int audit_type = AUDIT_APPARMOR_AUTO;
2dfbb274 2086+ struct common_audit_data sa = { };
1e8b8f9b 2087+ struct apparmor_audit_data aad = { };
9474138d 2088+
1e8b8f9b
AM
2089+ if (likely(!error)) {
2090+ u32 mask = perms->audit;
9474138d 2091+
1e8b8f9b
AM
2092+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
2093+ mask = 0xffff;
76514441 2094+
1e8b8f9b
AM
2095+ /* mask off perms that are not being force audited */
2096+ request &= mask;
fc63ffa9 2097+
1e8b8f9b
AM
2098+ if (likely(!request))
2099+ return 0;
2100+ audit_type = AUDIT_APPARMOR_AUDIT;
2101+ } else {
2102+ /* only report permissions that were denied */
2103+ request = request & ~perms->allow;
2104+
2105+ if (request & perms->kill)
2106+ audit_type = AUDIT_APPARMOR_KILL;
2107+
2108+ /* quiet known rejects, assumes quiet and kill do not overlap */
2109+ if ((request & perms->quiet) &&
2110+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
2111+ AUDIT_MODE(profile) != AUDIT_ALL)
2112+ request &= ~perms->quiet;
2113+
2114+ if (!request)
2115+ return COMPLAIN_MODE(profile) ?
2116+ complain_error(error) : error;
2117+ }
2118+
0c3ec466 2119+ sa.type = LSM_AUDIT_DATA_NONE;
1e8b8f9b
AM
2120+ sa.aad = &aad;
2121+ sa.aad->op = op;
2122+ sa.aad->name = name;
2123+ sa.aad->mnt.src_name = src_name;
2124+ sa.aad->mnt.type = type;
2125+ sa.aad->mnt.trans = trans;
2126+ sa.aad->mnt.flags = flags;
2127+ if (data && (perms->audit & AA_AUDIT_DATA))
2128+ sa.aad->mnt.data = data;
2129+ sa.aad->info = info;
2130+ sa.aad->error = error;
2131+
2132+ return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
76514441
AM
2133+}
2134+
2135+/**
1e8b8f9b
AM
2136+ * match_mnt_flags - Do an ordered match on mount flags
2137+ * @dfa: dfa to match against
2138+ * @state: state to start in
2139+ * @flags: mount flags to match against
76514441 2140+ *
1e8b8f9b
AM
2141+ * Mount flags are encoded as an ordered match. This is done instead of
2142+ * checking against a simple bitmask, to allow for logical operations
2143+ * on the flags.
76514441 2144+ *
1e8b8f9b 2145+ * Returns: next state after flags match
76514441 2146+ */
1e8b8f9b
AM
2147+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
2148+ unsigned long flags)
9474138d 2149+{
1e8b8f9b 2150+ unsigned int i;
fc63ffa9 2151+
1e8b8f9b
AM
2152+ for (i = 0; i <= 31 ; ++i) {
2153+ if ((1 << i) & flags)
2154+ state = aa_dfa_next(dfa, state, i + 1);
2155+ }
2156+
2157+ return state;
9474138d
AM
2158+}
2159+
2160+/**
1e8b8f9b
AM
2161+ * compute_mnt_perms - compute mount permission associated with @state
2162+ * @dfa: dfa to match against (NOT NULL)
2163+ * @state: state match finished in
ceaf2cfb 2164+ *
1e8b8f9b 2165+ * Returns: mount permissions
9474138d 2166+ */
1e8b8f9b
AM
2167+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
2168+ unsigned int state)
9474138d 2169+{
1e8b8f9b 2170+ struct file_perms perms;
2380c486 2171+
1e8b8f9b
AM
2172+ perms.kill = 0;
2173+ perms.allow = dfa_user_allow(dfa, state);
2174+ perms.audit = dfa_user_audit(dfa, state);
2175+ perms.quiet = dfa_user_quiet(dfa, state);
2176+ perms.xindex = dfa_user_xindex(dfa, state);
2177+
2178+ return perms;
2179+}
2180+
2181+static const char const *mnt_info_table[] = {
2182+ "match succeeded",
2183+ "failed mntpnt match",
2184+ "failed srcname match",
2185+ "failed type match",
2186+ "failed flags match",
2187+ "failed data match"
2188+};
2189+
2190+/*
2191+ * Returns 0 on success else element that match failed in, this is the
2192+ * index into the mnt_info_table above
2193+ */
2194+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
2195+ const char *mntpnt, const char *devname,
2196+ const char *type, unsigned long flags,
2197+ void *data, bool binary, struct file_perms *perms)
2198+{
2199+ unsigned int state;
2200+
2201+ state = aa_dfa_match(dfa, start, mntpnt);
2202+ state = aa_dfa_null_transition(dfa, state);
2203+ if (!state)
2204+ return 1;
2205+
2206+ if (devname)
2207+ state = aa_dfa_match(dfa, state, devname);
2208+ state = aa_dfa_null_transition(dfa, state);
2209+ if (!state)
2210+ return 2;
2211+
2212+ if (type)
2213+ state = aa_dfa_match(dfa, state, type);
2214+ state = aa_dfa_null_transition(dfa, state);
2215+ if (!state)
2216+ return 3;
2217+
2218+ state = match_mnt_flags(dfa, state, flags);
2219+ if (!state)
2220+ return 4;
2221+ *perms = compute_mnt_perms(dfa, state);
2222+ if (perms->allow & AA_MAY_MOUNT)
2223+ return 0;
2224+
2225+ /* only match data if not binary and the DFA flags data is expected */
2226+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
2227+ state = aa_dfa_null_transition(dfa, state);
2228+ if (!state)
2229+ return 4;
2230+
2231+ state = aa_dfa_match(dfa, state, data);
2232+ if (!state)
2233+ return 5;
2234+ *perms = compute_mnt_perms(dfa, state);
2235+ if (perms->allow & AA_MAY_MOUNT)
2236+ return 0;
fc63ffa9 2237+ }
1e8b8f9b
AM
2238+
2239+ /* failed at end of flags match */
2240+ return 4;
9474138d
AM
2241+}
2242+
ceaf2cfb 2243+/**
1e8b8f9b
AM
2244+ * match_mnt - handle path matching for mount
2245+ * @profile: the confining profile
2246+ * @mntpnt: string for the mntpnt (NOT NULL)
2247+ * @devname: string for the devname/src_name (MAYBE NULL)
2248+ * @type: string for the dev type (MAYBE NULL)
2249+ * @flags: mount flags to match
2250+ * @data: fs mount data (MAYBE NULL)
2251+ * @binary: whether @data is binary
2252+ * @perms: Returns: permission found by the match
2253+ * @info: Returns: infomation string about the match for logging
fc63ffa9 2254+ *
1e8b8f9b 2255+ * Returns: 0 on success else error
ceaf2cfb 2256+ */
1e8b8f9b
AM
2257+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
2258+ const char *devname, const char *type,
2259+ unsigned long flags, void *data, bool binary,
2260+ struct file_perms *perms, const char **info)
9474138d 2261+{
1e8b8f9b 2262+ int pos;
2380c486 2263+
1e8b8f9b
AM
2264+ if (!profile->policy.dfa)
2265+ return -EACCES;
2266+
2267+ pos = do_match_mnt(profile->policy.dfa,
2268+ profile->policy.start[AA_CLASS_MOUNT],
2269+ mntpnt, devname, type, flags, data, binary, perms);
2270+ if (pos) {
2271+ *info = mnt_info_table[pos];
2272+ return -EACCES;
2273+ }
2380c486 2274+
fc63ffa9 2275+ return 0;
9474138d 2276+}
9474138d 2277+
0776672e 2278+static int path_flags(struct aa_profile *profile, const struct path *path)
1e8b8f9b
AM
2279+{
2280+ return profile->path_flags |
2281+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
2282+}
9474138d 2283+
0776672e 2284+int aa_remount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 2285+ unsigned long flags, void *data)
9474138d 2286+{
1e8b8f9b
AM
2287+ struct file_perms perms = { };
2288+ const char *name, *info = NULL;
2289+ char *buffer = NULL;
2290+ int binary, error;
2291+
2292+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
2293+
2294+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2295+ &info);
2296+ if (error)
2297+ goto audit;
2298+
2299+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
2300+ &perms, &info);
2301+
2302+audit:
2303+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
2304+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
2305+ error);
2306+ kfree(buffer);
2307+
2308+ return error;
9474138d
AM
2309+}
2310+
0776672e 2311+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b 2312+ const char *dev_name, unsigned long flags)
9474138d 2313+{
1e8b8f9b
AM
2314+ struct file_perms perms = { };
2315+ char *buffer = NULL, *old_buffer = NULL;
2316+ const char *name, *old_name = NULL, *info = NULL;
2317+ struct path old_path;
2318+ int error;
2319+
2320+ if (!dev_name || !*dev_name)
2321+ return -EINVAL;
2322+
2323+ flags &= MS_REC | MS_BIND;
2324+
2325+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2326+ &info);
2327+ if (error)
2328+ goto audit;
2329+
2330+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
2331+ if (error)
2332+ goto audit;
2333+
2334+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
2335+ &old_buffer, &old_name, &info);
2336+ path_put(&old_path);
2337+ if (error)
2338+ goto audit;
2339+
2340+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
2341+ &perms, &info);
2342+
2343+audit:
2344+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
2345+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
2346+ info, error);
2347+ kfree(buffer);
2348+ kfree(old_buffer);
2349+
2350+ return error;
9474138d 2351+}
fc63ffa9 2352+
0776672e 2353+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
1e8b8f9b
AM
2354+ unsigned long flags)
2355+{
2356+ struct file_perms perms = { };
2357+ char *buffer = NULL;
2358+ const char *name, *info = NULL;
2359+ int error;
2360+
2361+ /* These are the flags allowed by do_change_type() */
2362+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
2363+ MS_UNBINDABLE);
2364+
2365+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2366+ &info);
fc63ffa9 2367+ if (error)
1e8b8f9b
AM
2368+ goto audit;
2369+
2370+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
2371+ &info);
2372+
2373+audit:
2374+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
2375+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
2376+ error);
2377+ kfree(buffer);
2378+
2379+ return error;
2380+}
2381+
0776672e 2382+int aa_move_mount(struct aa_profile *profile, const struct path *path,
1e8b8f9b
AM
2383+ const char *orig_name)
2384+{
2385+ struct file_perms perms = { };
2386+ char *buffer = NULL, *old_buffer = NULL;
2387+ const char *name, *old_name = NULL, *info = NULL;
2388+ struct path old_path;
2389+ int error;
2390+
2391+ if (!orig_name || !*orig_name)
2392+ return -EINVAL;
2393+
2394+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2395+ &info);
fc63ffa9 2396+ if (error)
1e8b8f9b
AM
2397+ goto audit;
2398+
2399+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
fc63ffa9 2400+ if (error)
1e8b8f9b
AM
2401+ goto audit;
2402+
2403+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
2404+ &old_buffer, &old_name, &info);
2405+ path_put(&old_path);
2406+ if (error)
2407+ goto audit;
2408+
2409+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
2410+ &perms, &info);
2411+
2412+audit:
2413+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
2414+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
2415+ info, error);
2416+ kfree(buffer);
2417+ kfree(old_buffer);
2418+
2419+ return error;
2420+}
2421+
2422+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
0776672e 2423+ const struct path *path, const char *type, unsigned long flags,
1e8b8f9b
AM
2424+ void *data)
2425+{
2426+ struct file_perms perms = { };
2427+ char *buffer = NULL, *dev_buffer = NULL;
2428+ const char *name = NULL, *dev_name = NULL, *info = NULL;
2429+ int binary = 1;
2430+ int error;
2431+
2432+ dev_name = orig_dev_name;
2433+ if (type) {
2434+ int requires_dev;
2435+ struct file_system_type *fstype = get_fs_type(type);
2436+ if (!fstype)
2437+ return -ENODEV;
2438+
2439+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
2440+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
2441+ put_filesystem(fstype);
2442+
2443+ if (requires_dev) {
2444+ struct path dev_path;
2445+
2446+ if (!dev_name || !*dev_name) {
2447+ error = -ENOENT;
2448+ goto out;
2449+ }
2450+
2451+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
2452+ if (error)
2453+ goto audit;
2454+
2455+ error = aa_path_name(&dev_path,
2456+ path_flags(profile, &dev_path),
2457+ &dev_buffer, &dev_name, &info);
2458+ path_put(&dev_path);
2459+ if (error)
2460+ goto audit;
2461+ }
2462+ }
2463+
2464+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
2465+ &info);
2466+ if (error)
2467+ goto audit;
2468+
2469+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
2470+ &perms, &info);
2471+
2472+audit:
2473+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
2474+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
2475+ error);
2476+ kfree(buffer);
2477+ kfree(dev_buffer);
2478+
2479+out:
2480+ return error;
2481+
2482+}
2483+
2484+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
2485+{
2486+ struct file_perms perms = { };
2487+ char *buffer = NULL;
2488+ const char *name, *info = NULL;
2489+ int error;
2490+
2491+ struct path path = { mnt, mnt->mnt_root };
2492+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
2493+ &info);
2494+ if (error)
2495+ goto audit;
2496+
2497+ if (!error && profile->policy.dfa) {
2498+ unsigned int state;
2499+ state = aa_dfa_match(profile->policy.dfa,
2500+ profile->policy.start[AA_CLASS_MOUNT],
2501+ name);
2502+ perms = compute_mnt_perms(profile->policy.dfa, state);
2503+ }
2504+
2505+ if (AA_MAY_UMOUNT & ~perms.allow)
2506+ error = -EACCES;
2507+
2508+audit:
2509+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
2510+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
2511+ kfree(buffer);
2512+
2513+ return error;
2514+}
2515+
0776672e
AM
2516+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
2517+ const struct path *new_path)
1e8b8f9b
AM
2518+{
2519+ struct file_perms perms = { };
2520+ struct aa_profile *target = NULL;
2521+ char *old_buffer = NULL, *new_buffer = NULL;
2522+ const char *old_name, *new_name = NULL, *info = NULL;
2523+ int error;
2524+
2525+ error = aa_path_name(old_path, path_flags(profile, old_path),
2526+ &old_buffer, &old_name, &info);
2527+ if (error)
2528+ goto audit;
2529+
2530+ error = aa_path_name(new_path, path_flags(profile, new_path),
2531+ &new_buffer, &new_name, &info);
2532+ if (error)
2533+ goto audit;
2534+
2535+ if (profile->policy.dfa) {
2536+ unsigned int state;
2537+ state = aa_dfa_match(profile->policy.dfa,
2538+ profile->policy.start[AA_CLASS_MOUNT],
2539+ new_name);
2540+ state = aa_dfa_null_transition(profile->policy.dfa, state);
2541+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
2542+ perms = compute_mnt_perms(profile->policy.dfa, state);
2543+ }
2544+
2545+ if (AA_MAY_PIVOTROOT & perms.allow) {
2546+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
2547+ target = x_table_lookup(profile, perms.xindex);
2548+ if (!target)
2549+ error = -ENOENT;
2550+ else
2551+ error = aa_replace_current_profile(target);
2552+ }
2553+ } else
2554+ error = -EACCES;
2555+
2556+audit:
2557+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
2558+ old_name, NULL, target ? target->base.name : NULL,
2559+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
2560+ aa_put_profile(target);
2561+ kfree(old_buffer);
2562+ kfree(new_buffer);
2563+
2564+ return error;
2565+}
This page took 0.502568 seconds and 4 git commands to generate.