1 commit 09aa4788d6052c6dc423d939319334ebb5d00847
2 Author: John Johansen <john.johansen@canonical.com>
3 Date: Mon Oct 4 15:03:36 2010 -0700
5 UBUNTU: SAUCE: AppArmor: basic networking rules
7 Base support for network mediation.
9 Signed-off-by: John Johansen <john.johansen@canonical.com>
11 diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
12 index 9cdec70..d5b291e 100644
13 --- a/security/apparmor/.gitignore
14 +++ b/security/apparmor/.gitignore
17 # Generated include files
22 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
23 index d693df8..5dbb72f 100644
24 --- a/security/apparmor/Makefile
25 +++ b/security/apparmor/Makefile
26 @@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
28 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
29 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
30 - resource.o sid.o file.o
31 + resource.o sid.o file.o net.o
32 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
34 -clean-files := capability_names.h rlim_names.h
35 +clean-files := capability_names.h rlim_names.h net_names.h
38 # Build a lower case string table of capability names
39 @@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
40 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
41 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
43 +# Build a lower case string table of address family names
44 +# Transform lines from
45 +# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
46 +# #define AF_INET 2 /* Internet IP Protocol */
51 +# and build the securityfs entries for the mapping.
52 +# Transforms lines from
53 +# #define AF_INET 2 /* Internet IP Protocol */
55 +# #define AA_FS_AF_MASK "local inet"
56 +quiet_cmd_make-af = GEN $@
57 +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
58 + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
59 + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
61 + echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
62 + sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
63 + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
65 +# Build a lower case string table of sock type names
66 +# Transform lines from
70 +quiet_cmd_make-sock = GEN $@
71 +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
73 + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
76 # Build a lower case string table of rlimit names.
77 # Transforms lines from
78 @@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
79 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
81 $(obj)/capability.o : $(obj)/capability_names.h
82 +$(obj)/net.o : $(obj)/net_names.h
83 $(obj)/resource.o : $(obj)/rlim_names.h
84 $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
86 @@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
87 $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
90 +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
91 + $(srctree)/include/linux/net.h \
94 + $(call cmd,make-sock)
95 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
96 index 729e595..181d961 100644
97 --- a/security/apparmor/apparmorfs.c
98 +++ b/security/apparmor/apparmorfs.c
99 @@ -807,6 +807,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
100 AA_FS_DIR("policy", aa_fs_entry_policy),
101 AA_FS_DIR("domain", aa_fs_entry_domain),
102 AA_FS_DIR("file", aa_fs_entry_file),
103 + AA_FS_DIR("network", aa_fs_entry_network),
104 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
105 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
106 AA_FS_DIR("caps", aa_fs_entry_caps),
107 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
108 index ba3dfd1..5d3c419 100644
109 --- a/security/apparmor/include/audit.h
110 +++ b/security/apparmor/include/audit.h
111 @@ -125,6 +125,10 @@ struct apparmor_audit_data {
116 + int type, protocol;
122 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
124 index 0000000..cb8a121
126 +++ b/security/apparmor/include/net.h
129 + * AppArmor security module
131 + * This file contains AppArmor network mediation definitions.
133 + * Copyright (C) 1998-2008 Novell/SUSE
134 + * Copyright 2009-2012 Canonical Ltd.
136 + * This program is free software; you can redistribute it and/or
137 + * modify it under the terms of the GNU General Public License as
138 + * published by the Free Software Foundation, version 2 of the
145 +#include <net/sock.h>
147 +#include "apparmorfs.h"
149 +/* struct aa_net - network confinement data
150 + * @allowed: basic network families permissions
151 + * @audit_network: which network permissions to force audit
152 + * @quiet_network: which network permissions to quiet rejects
160 +extern struct aa_fs_entry aa_fs_entry_network[];
162 +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
163 + int type, int protocol, struct sock *sk);
164 +extern int aa_revalidate_sk(int op, struct sock *sk);
166 +static inline void aa_free_net_rules(struct aa_net *new)
171 +#endif /* __AA_NET_H */
172 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
173 index 52275f0..4fc4dac 100644
174 --- a/security/apparmor/include/policy.h
175 +++ b/security/apparmor/include/policy.h
177 #include "capability.h"
181 #include "resource.h"
183 extern const char *const aa_profile_mode_names[];
184 @@ -176,6 +177,7 @@ struct aa_replacedby {
185 * @policy: general match rules governing policy
186 * @file: The set of rules governing basic file access and domain transitions
187 * @caps: capabilities for the profile
188 + * @net: network controls for the profile
189 * @rlimits: rlimits for the profile
191 * @dents: dentries for the profiles file entries in apparmorfs
192 @@ -217,6 +219,7 @@ struct aa_profile {
193 struct aa_policydb policy;
194 struct aa_file_rules file;
197 struct aa_rlimit rlimits;
200 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
201 index 41b8cb1..d96b5f7 100644
202 --- a/security/apparmor/lsm.c
203 +++ b/security/apparmor/lsm.c
205 #include "include/context.h"
206 #include "include/file.h"
207 #include "include/ipc.h"
208 +#include "include/net.h"
209 #include "include/path.h"
210 #include "include/policy.h"
211 #include "include/procattr.h"
212 @@ -584,6 +585,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
216 +static int apparmor_socket_create(int family, int type, int protocol, int kern)
218 + struct aa_profile *profile;
224 + profile = __aa_current_profile();
225 + if (!unconfined(profile))
226 + error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
231 +static int apparmor_socket_bind(struct socket *sock,
232 + struct sockaddr *address, int addrlen)
234 + struct sock *sk = sock->sk;
236 + return aa_revalidate_sk(OP_BIND, sk);
239 +static int apparmor_socket_connect(struct socket *sock,
240 + struct sockaddr *address, int addrlen)
242 + struct sock *sk = sock->sk;
244 + return aa_revalidate_sk(OP_CONNECT, sk);
247 +static int apparmor_socket_listen(struct socket *sock, int backlog)
249 + struct sock *sk = sock->sk;
251 + return aa_revalidate_sk(OP_LISTEN, sk);
254 +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
256 + struct sock *sk = sock->sk;
258 + return aa_revalidate_sk(OP_ACCEPT, sk);
261 +static int apparmor_socket_sendmsg(struct socket *sock,
262 + struct msghdr *msg, int size)
264 + struct sock *sk = sock->sk;
266 + return aa_revalidate_sk(OP_SENDMSG, sk);
269 +static int apparmor_socket_recvmsg(struct socket *sock,
270 + struct msghdr *msg, int size, int flags)
272 + struct sock *sk = sock->sk;
274 + return aa_revalidate_sk(OP_RECVMSG, sk);
277 +static int apparmor_socket_getsockname(struct socket *sock)
279 + struct sock *sk = sock->sk;
281 + return aa_revalidate_sk(OP_GETSOCKNAME, sk);
284 +static int apparmor_socket_getpeername(struct socket *sock)
286 + struct sock *sk = sock->sk;
288 + return aa_revalidate_sk(OP_GETPEERNAME, sk);
291 +static int apparmor_socket_getsockopt(struct socket *sock, int level,
294 + struct sock *sk = sock->sk;
296 + return aa_revalidate_sk(OP_GETSOCKOPT, sk);
299 +static int apparmor_socket_setsockopt(struct socket *sock, int level,
302 + struct sock *sk = sock->sk;
304 + return aa_revalidate_sk(OP_SETSOCKOPT, sk);
307 +static int apparmor_socket_shutdown(struct socket *sock, int how)
309 + struct sock *sk = sock->sk;
311 + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
314 static struct security_hook_list apparmor_hooks[] = {
315 LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
316 LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
317 @@ -613,6 +712,19 @@ static struct security_hook_list apparmor_hooks[] = {
318 LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
319 LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
321 + LSM_HOOK_INIT(socket_create, apparmor_socket_create),
322 + LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
323 + LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
324 + LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
325 + LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
326 + LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
327 + LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
328 + LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
329 + LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
330 + LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
331 + LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
332 + LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
334 LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
335 LSM_HOOK_INIT(cred_free, apparmor_cred_free),
336 LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
337 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
339 index 0000000..003dd18
341 +++ b/security/apparmor/net.c
344 + * AppArmor security module
346 + * This file contains AppArmor network mediation
348 + * Copyright (C) 1998-2008 Novell/SUSE
349 + * Copyright 2009-2012 Canonical Ltd.
351 + * This program is free software; you can redistribute it and/or
352 + * modify it under the terms of the GNU General Public License as
353 + * published by the Free Software Foundation, version 2 of the
357 +#include "include/apparmor.h"
358 +#include "include/audit.h"
359 +#include "include/context.h"
360 +#include "include/net.h"
361 +#include "include/policy.h"
363 +#include "net_names.h"
365 +struct aa_fs_entry aa_fs_entry_network[] = {
366 + AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
370 +/* audit callback for net specific fields */
371 +static void audit_cb(struct audit_buffer *ab, void *va)
373 + struct common_audit_data *sa = va;
375 + audit_log_format(ab, " family=");
376 + if (address_family_names[sa->u.net->family]) {
377 + audit_log_string(ab, address_family_names[sa->u.net->family]);
379 + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
381 + audit_log_format(ab, " sock_type=");
382 + if (sock_type_names[sa->aad->net.type]) {
383 + audit_log_string(ab, sock_type_names[sa->aad->net.type]);
385 + audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
387 + audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
391 + * audit_net - audit network access
392 + * @profile: profile being enforced (NOT NULL)
393 + * @op: operation being checked
394 + * @family: network family
395 + * @type: network type
396 + * @protocol: network protocol
397 + * @sk: socket auditing is being applied to
398 + * @error: error code for failure else 0
400 + * Returns: %0 or sa->error else other errorcode on failure
402 +static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
403 + int protocol, struct sock *sk, int error)
405 + int audit_type = AUDIT_APPARMOR_AUTO;
406 + struct common_audit_data sa;
407 + struct apparmor_audit_data aad = { };
408 + struct lsm_network_audit net = { };
410 + sa.type = LSM_AUDIT_DATA_NET;
412 + sa.type = LSM_AUDIT_DATA_NONE;
414 + /* todo fill in socket addr info */
418 + sa.u.net->family = family;
420 + sa.aad->net.type = type;
421 + sa.aad->net.protocol = protocol;
422 + sa.aad->error = error;
424 + if (likely(!sa.aad->error)) {
425 + u16 audit_mask = profile->net.audit[sa.u.net->family];
426 + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
427 + !(1 << sa.aad->net.type & audit_mask)))
429 + audit_type = AUDIT_APPARMOR_AUDIT;
431 + u16 quiet_mask = profile->net.quiet[sa.u.net->family];
433 + u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
435 + if (denied & kill_mask)
436 + audit_type = AUDIT_APPARMOR_KILL;
438 + if ((denied & quiet_mask) &&
439 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
440 + AUDIT_MODE(profile) != AUDIT_ALL)
441 + return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
444 + return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
448 + * aa_net_perm - very course network access check
449 + * @op: operation being checked
450 + * @profile: profile being enforced (NOT NULL)
451 + * @family: network family
452 + * @type: network type
453 + * @protocol: network protocol
455 + * Returns: %0 else error if permission denied
457 +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
458 + int protocol, struct sock *sk)
463 + if ((family < 0) || (family >= AF_MAX))
466 + if ((type < 0) || (type >= SOCK_MAX))
469 + /* unix domain and netlink sockets are handled by ipc */
470 + if (family == AF_UNIX || family == AF_NETLINK)
473 + family_mask = profile->net.allow[family];
475 + error = (family_mask & (1 << type)) ? 0 : -EACCES;
477 + return audit_net(profile, op, family, type, protocol, sk, error);
481 + * aa_revalidate_sk - Revalidate access to a sock
482 + * @op: operation being checked
483 + * @sk: sock being revalidated (NOT NULL)
485 + * Returns: %0 else error if permission denied
487 +int aa_revalidate_sk(int op, struct sock *sk)
489 + struct aa_profile *profile;
492 + /* aa_revalidate_sk should not be called from interrupt context
493 + * don't mediate these calls as they are not task related
495 + if (in_interrupt())
498 + profile = __aa_current_profile();
499 + if (!unconfined(profile))
500 + error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
501 + sk->sk_protocol, sk);
505 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
506 index 179e68d..f1a8541 100644
507 --- a/security/apparmor/policy.c
508 +++ b/security/apparmor/policy.c
509 @@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile)
511 aa_free_file_rules(&profile->file);
512 aa_free_cap_rules(&profile->caps);
513 + aa_free_net_rules(&profile->net);
514 aa_free_rlimit_rules(&profile->rlimits);
516 kzfree(profile->dirname);
517 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
518 index 1381206..7dc15ff 100644
519 --- a/security/apparmor/policy_unpack.c
520 +++ b/security/apparmor/policy_unpack.c
521 @@ -193,6 +193,19 @@ fail:
525 +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
527 + if (unpack_nameX(e, AA_U16, name)) {
528 + if (!inbounds(e, sizeof(u16)))
531 + *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
532 + e->pos += sizeof(u16);
538 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
540 if (unpack_nameX(e, AA_U32, name)) {
541 @@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
543 struct aa_profile *profile = NULL;
544 const char *name = NULL;
546 int i, error = -EPROTO;
549 @@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
550 if (!unpack_rlimits(e, profile))
553 + size = unpack_array(e, "net_allowed_af");
556 + for (i = 0; i < size; i++) {
557 + /* discard extraneous rules that this kernel will
562 + if (!unpack_u16(e, &tmp, NULL) ||
563 + !unpack_u16(e, &tmp, NULL) ||
564 + !unpack_u16(e, &tmp, NULL))
568 + if (!unpack_u16(e, &profile->net.allow[i], NULL))
570 + if (!unpack_u16(e, &profile->net.audit[i], NULL))
572 + if (!unpack_u16(e, &profile->net.quiet[i], NULL))
575 + if (!unpack_nameX(e, AA_ARRAYEND, NULL))
579 + * allow unix domain and netlink sockets they are handled
582 + profile->net.allow[AF_UNIX] = 0xffff;
583 + profile->net.allow[AF_NETLINK] = 0xffff;
585 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
586 /* generic policy dfa - optional and may be NULL */
587 profile->policy.dfa = unpack_dfa(e);
589 commit f5c5644745201b5b7d398e841e5045d0a5d14b18
590 Author: John Johansen <john.johansen@canonical.com>
591 Date: Fri Jun 29 17:34:00 2012 -0700
593 apparmor: Fix quieting of audit messages for network mediation
595 If a profile specified a quieting of network denials for a given rule by
596 either the quiet or deny rule qualifiers, the resultant quiet mask for
597 denied requests was applied incorrectly, resulting in two potential bugs.
598 1. The misapplied quiet mask would prevent denials from being correctly
599 tested against the kill mask/mode. Thus network access requests that
600 should have resulted in the application being killed did not.
602 2. The actual quieting of the denied network request was not being applied.
603 This would result in network rejections always being logged even when
604 they had been specifically marked as quieted.
606 Signed-off-by: John Johansen <john.johansen@canonical.com>
608 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
609 index 003dd18..6e6e5c9 100644
610 --- a/security/apparmor/net.c
611 +++ b/security/apparmor/net.c
612 @@ -88,7 +88,7 @@ static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
614 u16 quiet_mask = profile->net.quiet[sa.u.net->family];
616 - u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
617 + u16 denied = (1 << sa.aad->net.type);
619 if (denied & kill_mask)
620 audit_type = AUDIT_APPARMOR_KILL;
622 commit 0269f1631e1496798e5b0a319ff05b1133cfeaa3
623 Author: John Johansen <john.johansen@canonical.com>
624 Date: Wed May 16 10:58:05 2012 -0700
626 UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
628 Add the ability for apparmor to do mediation of mount operations. Mount
629 rules require an updated apparmor_parser (2.8 series) for policy compilation.
631 The basic form of the rules are.
633 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
634 [audit] [deny] remount [conds]* [path],
635 [audit] [deny] umount [conds]* [path],
636 [audit] [deny] pivotroot [oldroot=<value>] <path>
638 remount is just a short cut for mount options=remount
644 Example mount commands
645 mount, # allow all mounts, but not umount or pivotroot
647 mount fstype=procfs, # allow mounting procfs anywhere
649 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
651 mount /dev/sda -> /mnt,
653 mount /dev/sd** -> /mnt/**,
655 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
661 See the apparmor userspace for full documentation
663 Signed-off-by: John Johansen <john.johansen@canonical.com>
664 Acked-by: Kees Cook <kees@ubuntu.com>
666 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
667 index 5dbb72f..89b3445 100644
668 --- a/security/apparmor/Makefile
669 +++ b/security/apparmor/Makefile
670 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
672 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
673 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
674 - resource.o sid.o file.o net.o
675 + resource.o sid.o file.o net.o mount.o
676 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
678 clean-files := capability_names.h rlim_names.h net_names.h
679 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
680 index 181d961..5fb67f6 100644
681 --- a/security/apparmor/apparmorfs.c
682 +++ b/security/apparmor/apparmorfs.c
683 @@ -800,7 +800,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
685 static struct aa_fs_entry aa_fs_entry_policy[] = {
686 AA_FS_FILE_BOOLEAN("set_load", 1),
691 +static struct aa_fs_entry aa_fs_entry_mount[] = {
692 + AA_FS_FILE_STRING("mask", "mount umount"),
696 +static struct aa_fs_entry aa_fs_entry_namespaces[] = {
697 + AA_FS_FILE_BOOLEAN("profile", 1),
698 + AA_FS_FILE_BOOLEAN("pivot_root", 1),
702 static struct aa_fs_entry aa_fs_entry_features[] = {
703 @@ -808,6 +819,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
704 AA_FS_DIR("domain", aa_fs_entry_domain),
705 AA_FS_DIR("file", aa_fs_entry_file),
706 AA_FS_DIR("network", aa_fs_entry_network),
707 + AA_FS_DIR("mount", aa_fs_entry_mount),
708 + AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
709 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
710 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
711 AA_FS_DIR("caps", aa_fs_entry_caps),
712 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
713 index 3a7f1da..c2a8b8a 100644
714 --- a/security/apparmor/audit.c
715 +++ b/security/apparmor/audit.c
716 @@ -44,6 +44,10 @@ const char *const op_table[] = {
727 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
728 index fc3036b..f2a83b4 100644
729 --- a/security/apparmor/domain.c
730 +++ b/security/apparmor/domain.c
731 @@ -236,7 +236,7 @@ static const char *next_name(int xtype, const char *name)
733 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
735 -static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
736 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
738 struct aa_profile *new_profile = NULL;
739 struct aa_namespace *ns = profile->ns;
740 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
741 index 5d721e9..b57da7b 100644
742 --- a/security/apparmor/include/apparmor.h
743 +++ b/security/apparmor/include/apparmor.h
745 #define AA_CLASS_NET 4
746 #define AA_CLASS_RLIMITS 5
747 #define AA_CLASS_DOMAIN 6
748 +#define AA_CLASS_MOUNT 7
750 -#define AA_CLASS_LAST AA_CLASS_DOMAIN
751 +#define AA_CLASS_LAST AA_CLASS_MOUNT
753 /* Control parameters settable through module/boot flags */
754 extern enum audit_mode aa_g_audit;
755 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
756 index 5d3c419..b9f1d57 100644
757 --- a/security/apparmor/include/audit.h
758 +++ b/security/apparmor/include/audit.h
759 @@ -72,6 +72,10 @@ enum aa_ops {
770 @@ -120,6 +124,13 @@ struct apparmor_audit_data {
774 + const char *src_name;
778 + unsigned long flags;
784 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
785 index de04464..a3f70c5 100644
786 --- a/security/apparmor/include/domain.h
787 +++ b/security/apparmor/include/domain.h
788 @@ -23,6 +23,8 @@ struct aa_domain {
792 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
794 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
795 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
796 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
797 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
799 index 0000000..a43b1d6
801 +++ b/security/apparmor/include/mount.h
804 + * AppArmor security module
806 + * This file contains AppArmor file mediation function definitions.
808 + * Copyright 2012 Canonical Ltd.
810 + * This program is free software; you can redistribute it and/or
811 + * modify it under the terms of the GNU General Public License as
812 + * published by the Free Software Foundation, version 2 of the
816 +#ifndef __AA_MOUNT_H
817 +#define __AA_MOUNT_H
819 +#include <linux/fs.h>
820 +#include <linux/path.h>
826 +#define AA_MAY_PIVOTROOT 0x01
827 +#define AA_MAY_MOUNT 0x02
828 +#define AA_MAY_UMOUNT 0x04
829 +#define AA_AUDIT_DATA 0x40
830 +#define AA_CONT_MATCH 0x40
832 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
834 +int aa_remount(struct aa_profile *profile, const struct path *path,
835 + unsigned long flags, void *data);
837 +int aa_bind_mount(struct aa_profile *profile, const struct path *path,
838 + const char *old_name, unsigned long flags);
841 +int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
842 + unsigned long flags);
844 +int aa_move_mount(struct aa_profile *profile, const struct path *path,
845 + const char *old_name);
847 +int aa_new_mount(struct aa_profile *profile, const char *dev_name,
848 + const struct path *path, const char *type, unsigned long flags,
851 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
853 +int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
854 + const struct path *new_path);
856 +#endif /* __AA_MOUNT_H */
857 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
858 index d96b5f7..7a02376 100644
859 --- a/security/apparmor/lsm.c
860 +++ b/security/apparmor/lsm.c
862 #include "include/path.h"
863 #include "include/policy.h"
864 #include "include/procattr.h"
865 +#include "include/mount.h"
867 /* Flag indicating whether initialization completed */
868 int apparmor_initialized __initdata;
869 @@ -469,6 +470,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
870 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
873 +static int apparmor_sb_mount(const char *dev_name, const struct path *path,
874 + const char *type, unsigned long flags, void *data)
876 + struct aa_profile *profile;
879 + /* Discard magic */
880 + if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
881 + flags &= ~MS_MGC_MSK;
883 + flags &= ~AA_MS_IGNORE_MASK;
885 + profile = __aa_current_profile();
886 + if (!unconfined(profile)) {
887 + if (flags & MS_REMOUNT)
888 + error = aa_remount(profile, path, flags, data);
889 + else if (flags & MS_BIND)
890 + error = aa_bind_mount(profile, path, dev_name, flags);
891 + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
893 + error = aa_mount_change_type(profile, path, flags);
894 + else if (flags & MS_MOVE)
895 + error = aa_move_mount(profile, path, dev_name);
897 + error = aa_new_mount(profile, dev_name, path, type,
903 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
905 + struct aa_profile *profile;
908 + profile = __aa_current_profile();
909 + if (!unconfined(profile))
910 + error = aa_umount(profile, mnt, flags);
915 +static int apparmor_sb_pivotroot(const struct path *old_path,
916 + const struct path *new_path)
918 + struct aa_profile *profile;
921 + profile = __aa_current_profile();
922 + if (!unconfined(profile))
923 + error = aa_pivotroot(profile, old_path, new_path);
928 static int apparmor_getprocattr(struct task_struct *task, char *name,
931 @@ -689,6 +745,10 @@ static struct security_hook_list apparmor_hooks[] = {
932 LSM_HOOK_INIT(capget, apparmor_capget),
933 LSM_HOOK_INIT(capable, apparmor_capable),
935 + LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
936 + LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
937 + LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
939 LSM_HOOK_INIT(path_link, apparmor_path_link),
940 LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
941 LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
942 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
944 index 0000000..9cf9170
946 +++ b/security/apparmor/mount.c
949 + * AppArmor security module
951 + * This file contains AppArmor mediation of files
953 + * Copyright (C) 1998-2008 Novell/SUSE
954 + * Copyright 2009-2012 Canonical Ltd.
956 + * This program is free software; you can redistribute it and/or
957 + * modify it under the terms of the GNU General Public License as
958 + * published by the Free Software Foundation, version 2 of the
962 +#include <linux/fs.h>
963 +#include <linux/mount.h>
964 +#include <linux/namei.h>
966 +#include "include/apparmor.h"
967 +#include "include/audit.h"
968 +#include "include/context.h"
969 +#include "include/domain.h"
970 +#include "include/file.h"
971 +#include "include/match.h"
972 +#include "include/mount.h"
973 +#include "include/path.h"
974 +#include "include/policy.h"
977 +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
979 + if (flags & MS_RDONLY)
980 + audit_log_format(ab, "ro");
982 + audit_log_format(ab, "rw");
983 + if (flags & MS_NOSUID)
984 + audit_log_format(ab, ", nosuid");
985 + if (flags & MS_NODEV)
986 + audit_log_format(ab, ", nodev");
987 + if (flags & MS_NOEXEC)
988 + audit_log_format(ab, ", noexec");
989 + if (flags & MS_SYNCHRONOUS)
990 + audit_log_format(ab, ", sync");
991 + if (flags & MS_REMOUNT)
992 + audit_log_format(ab, ", remount");
993 + if (flags & MS_MANDLOCK)
994 + audit_log_format(ab, ", mand");
995 + if (flags & MS_DIRSYNC)
996 + audit_log_format(ab, ", dirsync");
997 + if (flags & MS_NOATIME)
998 + audit_log_format(ab, ", noatime");
999 + if (flags & MS_NODIRATIME)
1000 + audit_log_format(ab, ", nodiratime");
1001 + if (flags & MS_BIND)
1002 + audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
1003 + if (flags & MS_MOVE)
1004 + audit_log_format(ab, ", move");
1005 + if (flags & MS_SILENT)
1006 + audit_log_format(ab, ", silent");
1007 + if (flags & MS_POSIXACL)
1008 + audit_log_format(ab, ", acl");
1009 + if (flags & MS_UNBINDABLE)
1010 + audit_log_format(ab, flags & MS_REC ? ", runbindable" :
1012 + if (flags & MS_PRIVATE)
1013 + audit_log_format(ab, flags & MS_REC ? ", rprivate" :
1015 + if (flags & MS_SLAVE)
1016 + audit_log_format(ab, flags & MS_REC ? ", rslave" :
1018 + if (flags & MS_SHARED)
1019 + audit_log_format(ab, flags & MS_REC ? ", rshared" :
1021 + if (flags & MS_RELATIME)
1022 + audit_log_format(ab, ", relatime");
1023 + if (flags & MS_I_VERSION)
1024 + audit_log_format(ab, ", iversion");
1025 + if (flags & MS_STRICTATIME)
1026 + audit_log_format(ab, ", strictatime");
1027 + if (flags & MS_NOUSER)
1028 + audit_log_format(ab, ", nouser");
1032 + * audit_cb - call back for mount specific audit fields
1033 + * @ab: audit_buffer (NOT NULL)
1034 + * @va: audit struct to audit values of (NOT NULL)
1036 +static void audit_cb(struct audit_buffer *ab, void *va)
1038 + struct common_audit_data *sa = va;
1040 + if (sa->aad->mnt.type) {
1041 + audit_log_format(ab, " fstype=");
1042 + audit_log_untrustedstring(ab, sa->aad->mnt.type);
1044 + if (sa->aad->mnt.src_name) {
1045 + audit_log_format(ab, " srcname=");
1046 + audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
1048 + if (sa->aad->mnt.trans) {
1049 + audit_log_format(ab, " trans=");
1050 + audit_log_untrustedstring(ab, sa->aad->mnt.trans);
1052 + if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
1053 + audit_log_format(ab, " flags=\"");
1054 + audit_mnt_flags(ab, sa->aad->mnt.flags);
1055 + audit_log_format(ab, "\"");
1057 + if (sa->aad->mnt.data) {
1058 + audit_log_format(ab, " options=");
1059 + audit_log_untrustedstring(ab, sa->aad->mnt.data);
1064 + * audit_mount - handle the auditing of mount operations
1065 + * @profile: the profile being enforced (NOT NULL)
1066 + * @gfp: allocation flags
1067 + * @op: operation being mediated (NOT NULL)
1068 + * @name: name of object being mediated (MAYBE NULL)
1069 + * @src_name: src_name of object being mediated (MAYBE_NULL)
1070 + * @type: type of filesystem (MAYBE_NULL)
1071 + * @trans: name of trans (MAYBE NULL)
1072 + * @flags: filesystem idependent mount flags
1073 + * @data: filesystem mount flags
1074 + * @request: permissions requested
1075 + * @perms: the permissions computed for the request (NOT NULL)
1076 + * @info: extra information message (MAYBE NULL)
1077 + * @error: 0 if operation allowed else failure error code
1079 + * Returns: %0 or error on failure
1081 +static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
1082 + const char *name, const char *src_name,
1083 + const char *type, const char *trans,
1084 + unsigned long flags, const void *data, u32 request,
1085 + struct file_perms *perms, const char *info, int error)
1087 + int audit_type = AUDIT_APPARMOR_AUTO;
1088 + struct common_audit_data sa = { };
1089 + struct apparmor_audit_data aad = { };
1091 + if (likely(!error)) {
1092 + u32 mask = perms->audit;
1094 + if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
1097 + /* mask off perms that are not being force audited */
1100 + if (likely(!request))
1102 + audit_type = AUDIT_APPARMOR_AUDIT;
1104 + /* only report permissions that were denied */
1105 + request = request & ~perms->allow;
1107 + if (request & perms->kill)
1108 + audit_type = AUDIT_APPARMOR_KILL;
1110 + /* quiet known rejects, assumes quiet and kill do not overlap */
1111 + if ((request & perms->quiet) &&
1112 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1113 + AUDIT_MODE(profile) != AUDIT_ALL)
1114 + request &= ~perms->quiet;
1117 + return COMPLAIN_MODE(profile) ?
1118 + complain_error(error) : error;
1121 + sa.type = LSM_AUDIT_DATA_NONE;
1124 + sa.aad->name = name;
1125 + sa.aad->mnt.src_name = src_name;
1126 + sa.aad->mnt.type = type;
1127 + sa.aad->mnt.trans = trans;
1128 + sa.aad->mnt.flags = flags;
1129 + if (data && (perms->audit & AA_AUDIT_DATA))
1130 + sa.aad->mnt.data = data;
1131 + sa.aad->info = info;
1132 + sa.aad->error = error;
1134 + return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
1138 + * match_mnt_flags - Do an ordered match on mount flags
1139 + * @dfa: dfa to match against
1140 + * @state: state to start in
1141 + * @flags: mount flags to match against
1143 + * Mount flags are encoded as an ordered match. This is done instead of
1144 + * checking against a simple bitmask, to allow for logical operations
1147 + * Returns: next state after flags match
1149 +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
1150 + unsigned long flags)
1154 + for (i = 0; i <= 31 ; ++i) {
1155 + if ((1 << i) & flags)
1156 + state = aa_dfa_next(dfa, state, i + 1);
1163 + * compute_mnt_perms - compute mount permission associated with @state
1164 + * @dfa: dfa to match against (NOT NULL)
1165 + * @state: state match finished in
1167 + * Returns: mount permissions
1169 +static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
1170 + unsigned int state)
1172 + struct file_perms perms;
1175 + perms.allow = dfa_user_allow(dfa, state);
1176 + perms.audit = dfa_user_audit(dfa, state);
1177 + perms.quiet = dfa_user_quiet(dfa, state);
1178 + perms.xindex = dfa_user_xindex(dfa, state);
1183 +static const char const *mnt_info_table[] = {
1184 + "match succeeded",
1185 + "failed mntpnt match",
1186 + "failed srcname match",
1187 + "failed type match",
1188 + "failed flags match",
1189 + "failed data match"
1193 + * Returns 0 on success else element that match failed in, this is the
1194 + * index into the mnt_info_table above
1196 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
1197 + const char *mntpnt, const char *devname,
1198 + const char *type, unsigned long flags,
1199 + void *data, bool binary, struct file_perms *perms)
1201 + unsigned int state;
1203 + state = aa_dfa_match(dfa, start, mntpnt);
1204 + state = aa_dfa_null_transition(dfa, state);
1209 + state = aa_dfa_match(dfa, state, devname);
1210 + state = aa_dfa_null_transition(dfa, state);
1215 + state = aa_dfa_match(dfa, state, type);
1216 + state = aa_dfa_null_transition(dfa, state);
1220 + state = match_mnt_flags(dfa, state, flags);
1223 + *perms = compute_mnt_perms(dfa, state);
1224 + if (perms->allow & AA_MAY_MOUNT)
1227 + /* only match data if not binary and the DFA flags data is expected */
1228 + if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
1229 + state = aa_dfa_null_transition(dfa, state);
1233 + state = aa_dfa_match(dfa, state, data);
1236 + *perms = compute_mnt_perms(dfa, state);
1237 + if (perms->allow & AA_MAY_MOUNT)
1241 + /* failed at end of flags match */
1246 + * match_mnt - handle path matching for mount
1247 + * @profile: the confining profile
1248 + * @mntpnt: string for the mntpnt (NOT NULL)
1249 + * @devname: string for the devname/src_name (MAYBE NULL)
1250 + * @type: string for the dev type (MAYBE NULL)
1251 + * @flags: mount flags to match
1252 + * @data: fs mount data (MAYBE NULL)
1253 + * @binary: whether @data is binary
1254 + * @perms: Returns: permission found by the match
1255 + * @info: Returns: infomation string about the match for logging
1257 + * Returns: 0 on success else error
1259 +static int match_mnt(struct aa_profile *profile, const char *mntpnt,
1260 + const char *devname, const char *type,
1261 + unsigned long flags, void *data, bool binary,
1262 + struct file_perms *perms, const char **info)
1266 + if (!profile->policy.dfa)
1269 + pos = do_match_mnt(profile->policy.dfa,
1270 + profile->policy.start[AA_CLASS_MOUNT],
1271 + mntpnt, devname, type, flags, data, binary, perms);
1273 + *info = mnt_info_table[pos];
1280 +static int path_flags(struct aa_profile *profile, const struct path *path)
1282 + return profile->path_flags |
1283 + S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
1286 +int aa_remount(struct aa_profile *profile, const struct path *path,
1287 + unsigned long flags, void *data)
1289 + struct file_perms perms = { };
1290 + const char *name, *info = NULL;
1291 + char *buffer = NULL;
1292 + int binary, error;
1294 + binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
1296 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1301 + error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
1305 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1306 + NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1313 +int aa_bind_mount(struct aa_profile *profile, const struct path *path,
1314 + const char *dev_name, unsigned long flags)
1316 + struct file_perms perms = { };
1317 + char *buffer = NULL, *old_buffer = NULL;
1318 + const char *name, *old_name = NULL, *info = NULL;
1319 + struct path old_path;
1322 + if (!dev_name || !*dev_name)
1325 + flags &= MS_REC | MS_BIND;
1327 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1332 + error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1336 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1337 + &old_buffer, &old_name, &info);
1338 + path_put(&old_path);
1342 + error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
1346 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1347 + NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
1350 + kfree(old_buffer);
1355 +int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
1356 + unsigned long flags)
1358 + struct file_perms perms = { };
1359 + char *buffer = NULL;
1360 + const char *name, *info = NULL;
1363 + /* These are the flags allowed by do_change_type() */
1364 + flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
1367 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1372 + error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
1376 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1377 + NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
1384 +int aa_move_mount(struct aa_profile *profile, const struct path *path,
1385 + const char *orig_name)
1387 + struct file_perms perms = { };
1388 + char *buffer = NULL, *old_buffer = NULL;
1389 + const char *name, *old_name = NULL, *info = NULL;
1390 + struct path old_path;
1393 + if (!orig_name || !*orig_name)
1396 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1401 + error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
1405 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1406 + &old_buffer, &old_name, &info);
1407 + path_put(&old_path);
1411 + error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
1415 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1416 + NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
1419 + kfree(old_buffer);
1424 +int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
1425 + const struct path *path, const char *type, unsigned long flags,
1428 + struct file_perms perms = { };
1429 + char *buffer = NULL, *dev_buffer = NULL;
1430 + const char *name = NULL, *dev_name = NULL, *info = NULL;
1434 + dev_name = orig_dev_name;
1437 + struct file_system_type *fstype = get_fs_type(type);
1441 + binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
1442 + requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
1443 + put_filesystem(fstype);
1445 + if (requires_dev) {
1446 + struct path dev_path;
1448 + if (!dev_name || !*dev_name) {
1453 + error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
1457 + error = aa_path_name(&dev_path,
1458 + path_flags(profile, &dev_path),
1459 + &dev_buffer, &dev_name, &info);
1460 + path_put(&dev_path);
1466 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1471 + error = match_mnt(profile, name, dev_name, type, flags, data, binary,
1475 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
1476 + type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1479 + kfree(dev_buffer);
1486 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
1488 + struct file_perms perms = { };
1489 + char *buffer = NULL;
1490 + const char *name, *info = NULL;
1493 + struct path path = { mnt, mnt->mnt_root };
1494 + error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
1499 + if (!error && profile->policy.dfa) {
1500 + unsigned int state;
1501 + state = aa_dfa_match(profile->policy.dfa,
1502 + profile->policy.start[AA_CLASS_MOUNT],
1504 + perms = compute_mnt_perms(profile->policy.dfa, state);
1507 + if (AA_MAY_UMOUNT & ~perms.allow)
1511 + error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
1512 + NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
1518 +int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
1519 + const struct path *new_path)
1521 + struct file_perms perms = { };
1522 + struct aa_profile *target = NULL;
1523 + char *old_buffer = NULL, *new_buffer = NULL;
1524 + const char *old_name, *new_name = NULL, *info = NULL;
1527 + error = aa_path_name(old_path, path_flags(profile, old_path),
1528 + &old_buffer, &old_name, &info);
1532 + error = aa_path_name(new_path, path_flags(profile, new_path),
1533 + &new_buffer, &new_name, &info);
1537 + if (profile->policy.dfa) {
1538 + unsigned int state;
1539 + state = aa_dfa_match(profile->policy.dfa,
1540 + profile->policy.start[AA_CLASS_MOUNT],
1542 + state = aa_dfa_null_transition(profile->policy.dfa, state);
1543 + state = aa_dfa_match(profile->policy.dfa, state, old_name);
1544 + perms = compute_mnt_perms(profile->policy.dfa, state);
1547 + if (AA_MAY_PIVOTROOT & perms.allow) {
1548 + if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
1549 + target = x_table_lookup(profile, perms.xindex);
1553 + error = aa_replace_current_profile(target);
1559 + error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
1560 + old_name, NULL, target ? target->base.name : NULL,
1561 + 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
1562 + aa_put_profile(target);
1563 + kfree(old_buffer);
1564 + kfree(new_buffer);
1569 commit 29fb087c5df8bb8ac354ab58d33c43e68270123b
1570 Author: John Johansen <john.johansen@canonical.com>
1571 Date: Wed Aug 31 21:10:06 2016 -0700
1573 apparmor: fix change_hat not finding hat after policy replacement
1575 After a policy replacement, the task cred may be out of date and need
1576 to be updated. However change_hat is using the stale profiles from
1577 the out of date cred resulting in either: a stale profile being applied
1578 or, incorrect failure when searching for a hat profile as it has been
1579 migrated to the new parent profile.
1581 Fixes: 01e2b670aa898a39259bc85c78e3d74820f4d3b6 (failure to find hat)
1582 Fixes: 898127c34ec03291c86f4ff3856d79e9e18952bc (stale policy being applied)
1583 Signed-off-by: John Johansen <john.johansen@canonical.com>
1585 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
1586 index f2a83b4..dbd68f2 100644
1587 --- a/security/apparmor/domain.c
1588 +++ b/security/apparmor/domain.c
1589 @@ -621,8 +621,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
1590 /* released below */
1591 cred = get_current_cred();
1592 cxt = cred_cxt(cred);
1593 - profile = aa_cred_profile(cred);
1594 - previous_profile = cxt->previous;
1595 + profile = aa_get_newest_profile(aa_cred_profile(cred));
1596 + previous_profile = aa_get_newest_profile(cxt->previous);
1598 if (unconfined(profile)) {
1599 info = "unconfined";
1600 @@ -718,6 +718,8 @@ audit:
1602 aa_put_profile(hat);
1604 + aa_put_profile(profile);
1605 + aa_put_profile(previous_profile);