1 From 8de755e4dfdbc40bfcaca848ae6b5aeaf0ede0e8 Mon Sep 17 00:00:00 2001
2 From: John Johansen <john.johansen@canonical.com>
3 Date: Thu, 22 Jul 2010 02:32:02 -0700
4 Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: Add profile introspection file
7 Add the dynamic profiles file to the interace, to allow load policy
10 Signed-off-by: John Johansen <john.johansen@canonical.com>
11 Acked-by: Kees Cook <kees@ubuntu.com>
12 Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
14 security/apparmor/apparmorfs.c | 227 ++++++++++++++++++++++++++++++++++++++++
15 1 file changed, 227 insertions(+)
17 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
18 index 16c15ec..89bdc62 100644
19 --- a/security/apparmor/apparmorfs.c
20 +++ b/security/apparmor/apparmorfs.c
21 @@ -182,6 +182,232 @@ const struct file_operations aa_fs_seq_file_ops = {
22 .release = single_release,
26 + * __next_namespace - find the next namespace to list
27 + * @root: root namespace to stop search at (NOT NULL)
28 + * @ns: current ns position (NOT NULL)
30 + * Find the next namespace from @ns under @root and handle all locking needed
31 + * while switching current namespace.
33 + * Returns: next namespace or NULL if at last namespace under @root
34 + * NOTE: will not unlock root->lock
36 +static struct aa_namespace *__next_namespace(struct aa_namespace *root,
37 + struct aa_namespace *ns)
39 + struct aa_namespace *parent;
41 + /* is next namespace a child */
42 + if (!list_empty(&ns->sub_ns)) {
43 + struct aa_namespace *next;
44 + next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
45 + read_lock(&next->lock);
49 + /* check if the next ns is a sibling, parent, gp, .. */
50 + parent = ns->parent;
52 + read_unlock(&ns->lock);
53 + list_for_each_entry_continue(ns, &parent->sub_ns, base.list) {
54 + read_lock(&ns->lock);
60 + parent = parent->parent;
67 + * __first_profile - find the first profile in a namespace
68 + * @root: namespace that is root of profiles being displayed (NOT NULL)
69 + * @ns: namespace to start in (NOT NULL)
71 + * Returns: unrefcounted profile or NULL if no profile
73 +static struct aa_profile *__first_profile(struct aa_namespace *root,
74 + struct aa_namespace *ns)
76 + for ( ; ns; ns = __next_namespace(root, ns)) {
77 + if (!list_empty(&ns->base.profiles))
78 + return list_first_entry(&ns->base.profiles,
79 + struct aa_profile, base.list);
85 + * __next_profile - step to the next profile in a profile tree
86 + * @profile: current profile in tree (NOT NULL)
88 + * Perform a depth first taversal on the profile tree in a namespace
90 + * Returns: next profile or NULL if done
91 + * Requires: profile->ns.lock to be held
93 +static struct aa_profile *__next_profile(struct aa_profile *p)
95 + struct aa_profile *parent;
96 + struct aa_namespace *ns = p->ns;
98 + /* is next profile a child */
99 + if (!list_empty(&p->base.profiles))
100 + return list_first_entry(&p->base.profiles, typeof(*p),
103 + /* is next profile a sibling, parent sibling, gp, subling, .. */
104 + parent = p->parent;
106 + list_for_each_entry_continue(p, &parent->base.profiles,
110 + parent = parent->parent;
113 + /* is next another profile in the namespace */
114 + list_for_each_entry_continue(p, &ns->base.profiles, base.list)
121 + * next_profile - step to the next profile in where ever it may be
122 + * @root: root namespace (NOT NULL)
123 + * @profile: current profile (NOT NULL)
125 + * Returns: next profile or NULL if there isn't one
127 +static struct aa_profile *next_profile(struct aa_namespace *root,
128 + struct aa_profile *profile)
130 + struct aa_profile *next = __next_profile(profile);
134 + /* finished all profiles in namespace move to next namespace */
135 + return __first_profile(root, __next_namespace(root, profile->ns));
139 + * p_start - start a depth first traversal of profile tree
140 + * @f: seq_file to fill
141 + * @pos: current position
143 + * Returns: first profile under current namespace or NULL if none found
145 + * acquires first ns->lock
147 +static void *p_start(struct seq_file *f, loff_t *pos)
148 + __acquires(root->lock)
150 + struct aa_profile *profile = NULL;
151 + struct aa_namespace *root = aa_current_profile()->ns;
153 + f->private = aa_get_namespace(root);
156 + /* find the first profile */
157 + read_lock(&root->lock);
158 + profile = __first_profile(root, root);
160 + /* skip to position */
161 + for (; profile && l > 0; l--)
162 + profile = next_profile(root, profile);
168 + * p_next - read the next profile entry
169 + * @f: seq_file to fill
170 + * @p: profile previously returned
171 + * @pos: current position
173 + * Returns: next profile after @p or NULL if none
175 + * may acquire/release locks in namespace tree as necessary
177 +static void *p_next(struct seq_file *f, void *p, loff_t *pos)
179 + struct aa_profile *profile = p;
180 + struct aa_namespace *root = f->private;
183 + return next_profile(root, profile);
187 + * p_stop - stop depth first traversal
188 + * @f: seq_file we are filling
189 + * @p: the last profile writen
191 + * Release all locking done by p_start/p_next on namespace tree
193 +static void p_stop(struct seq_file *f, void *p)
194 + __releases(root->lock)
196 + struct aa_profile *profile = p;
197 + struct aa_namespace *root = f->private, *ns;
200 + for (ns = profile->ns; ns && ns != root; ns = ns->parent)
201 + read_unlock(&ns->lock);
203 + read_unlock(&root->lock);
204 + aa_put_namespace(root);
208 + * seq_show_profile - show a profile entry
209 + * @f: seq_file to file
210 + * @p: current position (profile) (NOT NULL)
212 + * Returns: error on failure
214 +static int seq_show_profile(struct seq_file *f, void *p)
216 + struct aa_profile *profile = (struct aa_profile *)p;
217 + struct aa_namespace *root = f->private;
219 + if (profile->ns != root)
220 + seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
221 + seq_printf(f, "%s (%s)\n", profile->base.hname,
222 + COMPLAIN_MODE(profile) ? "complain" : "enforce");
227 +static const struct seq_operations aa_fs_profiles_op = {
231 + .show = seq_show_profile,
234 +static int profiles_open(struct inode *inode, struct file *file)
236 + return seq_open(file, &aa_fs_profiles_op);
239 +static int profiles_release(struct inode *inode, struct file *file)
241 + return seq_release(inode, file);
244 +const struct file_operations aa_fs_profiles_fops = {
245 + .open = profiles_open,
247 + .llseek = seq_lseek,
248 + .release = profiles_release,
251 /** Base file system setup **/
253 static struct aa_fs_entry aa_fs_entry_file[] = {
254 @@ -210,6 +436,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = {
255 AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
256 AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
257 AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
258 + AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
259 AA_FS_DIR("features", aa_fs_entry_features),
265 From 423e2cb454d75d6185eecd0c1b5cf6ccc2d8482d Mon Sep 17 00:00:00 2001
266 From: John Johansen <john.johansen@canonical.com>
267 Date: Mon, 4 Oct 2010 15:03:36 -0700
268 Subject: [PATCH 2/3] UBUNTU: SAUCE: AppArmor: basic networking rules
270 Base support for network mediation.
272 Signed-off-by: John Johansen <john.johansen@canonical.com>
274 security/apparmor/.gitignore | 2 +-
275 security/apparmor/Makefile | 42 +++++++++-
276 security/apparmor/apparmorfs.c | 1 +
277 security/apparmor/include/audit.h | 4 +
278 security/apparmor/include/net.h | 44 ++++++++++
279 security/apparmor/include/policy.h | 3 +
280 security/apparmor/lsm.c | 112 +++++++++++++++++++++++++
281 security/apparmor/net.c | 162 ++++++++++++++++++++++++++++++++++++
282 security/apparmor/policy.c | 1 +
283 security/apparmor/policy_unpack.c | 46 ++++++++++
284 10 files changed, 414 insertions(+), 3 deletions(-)
285 create mode 100644 security/apparmor/include/net.h
286 create mode 100644 security/apparmor/net.c
288 diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
289 index 4d995ae..d5b291e 100644
290 --- a/security/apparmor/.gitignore
291 +++ b/security/apparmor/.gitignore
294 # Generated include files
300 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
301 index 806bd19..19daa85 100644
302 --- a/security/apparmor/Makefile
303 +++ b/security/apparmor/Makefile
304 @@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
306 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
307 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
308 - resource.o sid.o file.o
309 + resource.o sid.o file.o net.o
311 -clean-files := capability_names.h rlim_names.h
312 +clean-files := capability_names.h rlim_names.h net_names.h
315 # Build a lower case string table of capability names
316 @@ -20,6 +20,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
317 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
320 +# Build a lower case string table of address family names
321 +# Transform lines from
322 +# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
323 +# #define AF_INET 2 /* Internet IP Protocol */
328 +# and build the securityfs entries for the mapping.
329 +# Transforms lines from
330 +# #define AF_INET 2 /* Internet IP Protocol */
332 +# #define AA_FS_AF_MASK "local inet"
333 +quiet_cmd_make-af = GEN $@
334 +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
335 + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
336 + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
338 + echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
339 + sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
340 + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
342 +# Build a lower case string table of sock type names
343 +# Transform lines from
347 +quiet_cmd_make-sock = GEN $@
348 +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
349 + sed $^ >>$@ -r -n \
350 + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
353 # Build a lower case string table of rlimit names.
354 # Transforms lines from
355 @@ -56,6 +88,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
356 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
358 $(obj)/capability.o : $(obj)/capability_names.h
359 +$(obj)/net.o : $(obj)/net_names.h
360 $(obj)/resource.o : $(obj)/rlim_names.h
361 $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
363 @@ -63,3 +96,8 @@ $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
364 $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \
366 $(call cmd,make-rlim)
367 +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
368 + $(srctree)/include/linux/net.h \
370 + $(call cmd,make-af)
371 + $(call cmd,make-sock)
372 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
373 index 89bdc62..c66315d 100644
374 --- a/security/apparmor/apparmorfs.c
375 +++ b/security/apparmor/apparmorfs.c
376 @@ -427,6 +427,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
377 static struct aa_fs_entry aa_fs_entry_features[] = {
378 AA_FS_DIR("domain", aa_fs_entry_domain),
379 AA_FS_DIR("file", aa_fs_entry_file),
380 + AA_FS_DIR("network", aa_fs_entry_network),
381 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
382 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
384 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
385 index 3868b1e..c1ff09c 100644
386 --- a/security/apparmor/include/audit.h
387 +++ b/security/apparmor/include/audit.h
388 @@ -126,6 +126,10 @@ struct apparmor_audit_data {
393 + int type, protocol;
399 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
401 index 0000000..cb8a121
403 +++ b/security/apparmor/include/net.h
406 + * AppArmor security module
408 + * This file contains AppArmor network mediation definitions.
410 + * Copyright (C) 1998-2008 Novell/SUSE
411 + * Copyright 2009-2012 Canonical Ltd.
413 + * This program is free software; you can redistribute it and/or
414 + * modify it under the terms of the GNU General Public License as
415 + * published by the Free Software Foundation, version 2 of the
422 +#include <net/sock.h>
424 +#include "apparmorfs.h"
426 +/* struct aa_net - network confinement data
427 + * @allowed: basic network families permissions
428 + * @audit_network: which network permissions to force audit
429 + * @quiet_network: which network permissions to quiet rejects
437 +extern struct aa_fs_entry aa_fs_entry_network[];
439 +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
440 + int type, int protocol, struct sock *sk);
441 +extern int aa_revalidate_sk(int op, struct sock *sk);
443 +static inline void aa_free_net_rules(struct aa_net *new)
448 +#endif /* __AA_NET_H */
449 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
450 index bda4569..eb13a73 100644
451 --- a/security/apparmor/include/policy.h
452 +++ b/security/apparmor/include/policy.h
454 #include "capability.h"
458 #include "resource.h"
460 extern const char *const profile_mode_names[];
461 @@ -157,6 +158,7 @@ struct aa_policydb {
462 * @policy: general match rules governing policy
463 * @file: The set of rules governing basic file access and domain transitions
464 * @caps: capabilities for the profile
465 + * @net: network controls for the profile
466 * @rlimits: rlimits for the profile
468 * The AppArmor profile contains the basic confinement data. Each profile
469 @@ -194,6 +196,7 @@ struct aa_profile {
470 struct aa_policydb policy;
471 struct aa_file_rules file;
474 struct aa_rlimit rlimits;
477 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
478 index ad05d39..3cde194 100644
479 --- a/security/apparmor/lsm.c
480 +++ b/security/apparmor/lsm.c
482 #include "include/context.h"
483 #include "include/file.h"
484 #include "include/ipc.h"
485 +#include "include/net.h"
486 #include "include/path.h"
487 #include "include/policy.h"
488 #include "include/procattr.h"
489 @@ -622,6 +623,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
493 +static int apparmor_socket_create(int family, int type, int protocol, int kern)
495 + struct aa_profile *profile;
501 + profile = __aa_current_profile();
502 + if (!unconfined(profile))
503 + error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
508 +static int apparmor_socket_bind(struct socket *sock,
509 + struct sockaddr *address, int addrlen)
511 + struct sock *sk = sock->sk;
513 + return aa_revalidate_sk(OP_BIND, sk);
516 +static int apparmor_socket_connect(struct socket *sock,
517 + struct sockaddr *address, int addrlen)
519 + struct sock *sk = sock->sk;
521 + return aa_revalidate_sk(OP_CONNECT, sk);
524 +static int apparmor_socket_listen(struct socket *sock, int backlog)
526 + struct sock *sk = sock->sk;
528 + return aa_revalidate_sk(OP_LISTEN, sk);
531 +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
533 + struct sock *sk = sock->sk;
535 + return aa_revalidate_sk(OP_ACCEPT, sk);
538 +static int apparmor_socket_sendmsg(struct socket *sock,
539 + struct msghdr *msg, int size)
541 + struct sock *sk = sock->sk;
543 + return aa_revalidate_sk(OP_SENDMSG, sk);
546 +static int apparmor_socket_recvmsg(struct socket *sock,
547 + struct msghdr *msg, int size, int flags)
549 + struct sock *sk = sock->sk;
551 + return aa_revalidate_sk(OP_RECVMSG, sk);
554 +static int apparmor_socket_getsockname(struct socket *sock)
556 + struct sock *sk = sock->sk;
558 + return aa_revalidate_sk(OP_GETSOCKNAME, sk);
561 +static int apparmor_socket_getpeername(struct socket *sock)
563 + struct sock *sk = sock->sk;
565 + return aa_revalidate_sk(OP_GETPEERNAME, sk);
568 +static int apparmor_socket_getsockopt(struct socket *sock, int level,
571 + struct sock *sk = sock->sk;
573 + return aa_revalidate_sk(OP_GETSOCKOPT, sk);
576 +static int apparmor_socket_setsockopt(struct socket *sock, int level,
579 + struct sock *sk = sock->sk;
581 + return aa_revalidate_sk(OP_SETSOCKOPT, sk);
584 +static int apparmor_socket_shutdown(struct socket *sock, int how)
586 + struct sock *sk = sock->sk;
588 + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
591 static struct security_operations apparmor_ops = {
594 @@ -653,6 +752,19 @@ static struct security_operations apparmor_ops = {
595 .getprocattr = apparmor_getprocattr,
596 .setprocattr = apparmor_setprocattr,
598 + .socket_create = apparmor_socket_create,
599 + .socket_bind = apparmor_socket_bind,
600 + .socket_connect = apparmor_socket_connect,
601 + .socket_listen = apparmor_socket_listen,
602 + .socket_accept = apparmor_socket_accept,
603 + .socket_sendmsg = apparmor_socket_sendmsg,
604 + .socket_recvmsg = apparmor_socket_recvmsg,
605 + .socket_getsockname = apparmor_socket_getsockname,
606 + .socket_getpeername = apparmor_socket_getpeername,
607 + .socket_getsockopt = apparmor_socket_getsockopt,
608 + .socket_setsockopt = apparmor_socket_setsockopt,
609 + .socket_shutdown = apparmor_socket_shutdown,
611 .cred_alloc_blank = apparmor_cred_alloc_blank,
612 .cred_free = apparmor_cred_free,
613 .cred_prepare = apparmor_cred_prepare,
614 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
616 index 0000000..084232b
618 +++ b/security/apparmor/net.c
621 + * AppArmor security module
623 + * This file contains AppArmor network mediation
625 + * Copyright (C) 1998-2008 Novell/SUSE
626 + * Copyright 2009-2012 Canonical Ltd.
628 + * This program is free software; you can redistribute it and/or
629 + * modify it under the terms of the GNU General Public License as
630 + * published by the Free Software Foundation, version 2 of the
634 +#include "include/apparmor.h"
635 +#include "include/audit.h"
636 +#include "include/context.h"
637 +#include "include/net.h"
638 +#include "include/policy.h"
640 +#include "net_names.h"
642 +struct aa_fs_entry aa_fs_entry_network[] = {
643 + AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
647 +/* audit callback for net specific fields */
648 +static void audit_cb(struct audit_buffer *ab, void *va)
650 + struct common_audit_data *sa = va;
652 + audit_log_format(ab, " family=");
653 + if (address_family_names[sa->u.net->family]) {
654 + audit_log_string(ab, address_family_names[sa->u.net->family]);
656 + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
658 + audit_log_format(ab, " sock_type=");
659 + if (sock_type_names[sa->aad->net.type]) {
660 + audit_log_string(ab, sock_type_names[sa->aad->net.type]);
662 + audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
664 + audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
668 + * audit_net - audit network access
669 + * @profile: profile being enforced (NOT NULL)
670 + * @op: operation being checked
671 + * @family: network family
672 + * @type: network type
673 + * @protocol: network protocol
674 + * @sk: socket auditing is being applied to
675 + * @error: error code for failure else 0
677 + * Returns: %0 or sa->error else other errorcode on failure
679 +static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
680 + int protocol, struct sock *sk, int error)
682 + int audit_type = AUDIT_APPARMOR_AUTO;
683 + struct common_audit_data sa;
684 + struct apparmor_audit_data aad = { };
685 + struct lsm_network_audit net = { };
687 + COMMON_AUDIT_DATA_INIT(&sa, NET);
689 + COMMON_AUDIT_DATA_INIT(&sa, NONE);
691 + /* todo fill in socket addr info */
695 + sa.u.net->family = family;
697 + sa.aad->net.type = type;
698 + sa.aad->net.protocol = protocol;
699 + sa.aad->error = error;
701 + if (likely(!sa.aad->error)) {
702 + u16 audit_mask = profile->net.audit[sa.u.net->family];
703 + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
704 + !(1 << sa.aad->net.type & audit_mask)))
706 + audit_type = AUDIT_APPARMOR_AUDIT;
708 + u16 quiet_mask = profile->net.quiet[sa.u.net->family];
710 + u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
712 + if (denied & kill_mask)
713 + audit_type = AUDIT_APPARMOR_KILL;
715 + if ((denied & quiet_mask) &&
716 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
717 + AUDIT_MODE(profile) != AUDIT_ALL)
718 + return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
721 + return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
725 + * aa_net_perm - very course network access check
726 + * @op: operation being checked
727 + * @profile: profile being enforced (NOT NULL)
728 + * @family: network family
729 + * @type: network type
730 + * @protocol: network protocol
732 + * Returns: %0 else error if permission denied
734 +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
735 + int protocol, struct sock *sk)
740 + if ((family < 0) || (family >= AF_MAX))
743 + if ((type < 0) || (type >= SOCK_MAX))
746 + /* unix domain and netlink sockets are handled by ipc */
747 + if (family == AF_UNIX || family == AF_NETLINK)
750 + family_mask = profile->net.allow[family];
752 + error = (family_mask & (1 << type)) ? 0 : -EACCES;
754 + return audit_net(profile, op, family, type, protocol, sk, error);
758 + * aa_revalidate_sk - Revalidate access to a sock
759 + * @op: operation being checked
760 + * @sk: sock being revalidated (NOT NULL)
762 + * Returns: %0 else error if permission denied
764 +int aa_revalidate_sk(int op, struct sock *sk)
766 + struct aa_profile *profile;
769 + /* aa_revalidate_sk should not be called from interrupt context
770 + * don't mediate these calls as they are not task related
772 + if (in_interrupt())
775 + profile = __aa_current_profile();
776 + if (!unconfined(profile))
777 + error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
778 + sk->sk_protocol, sk);
782 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
783 index f1f7506..b8100a7 100644
784 --- a/security/apparmor/policy.c
785 +++ b/security/apparmor/policy.c
786 @@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile)
788 aa_free_file_rules(&profile->file);
789 aa_free_cap_rules(&profile->caps);
790 + aa_free_net_rules(&profile->net);
791 aa_free_rlimit_rules(&profile->rlimits);
793 aa_free_sid(profile->sid);
794 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
795 index deab7c7..8f8e9c1 100644
796 --- a/security/apparmor/policy_unpack.c
797 +++ b/security/apparmor/policy_unpack.c
798 @@ -193,6 +193,19 @@ fail:
802 +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
804 + if (unpack_nameX(e, AA_U16, name)) {
805 + if (!inbounds(e, sizeof(u16)))
808 + *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
809 + e->pos += sizeof(u16);
815 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
817 if (unpack_nameX(e, AA_U32, name)) {
818 @@ -471,6 +484,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
820 struct aa_profile *profile = NULL;
821 const char *name = NULL;
823 int i, error = -EPROTO;
826 @@ -564,6 +578,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
827 if (!unpack_rlimits(e, profile))
830 + size = unpack_array(e, "net_allowed_af");
833 + for (i = 0; i < size; i++) {
834 + /* discard extraneous rules that this kernel will
839 + if (!unpack_u16(e, &tmp, NULL) ||
840 + !unpack_u16(e, &tmp, NULL) ||
841 + !unpack_u16(e, &tmp, NULL))
845 + if (!unpack_u16(e, &profile->net.allow[i], NULL))
847 + if (!unpack_u16(e, &profile->net.audit[i], NULL))
849 + if (!unpack_u16(e, &profile->net.quiet[i], NULL))
852 + if (!unpack_nameX(e, AA_ARRAYEND, NULL))
856 + * allow unix domain and netlink sockets they are handled
859 + profile->net.allow[AF_UNIX] = 0xffff;
860 + profile->net.allow[AF_NETLINK] = 0xffff;
862 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
863 /* generic policy dfa - optional and may be NULL */
864 profile->policy.dfa = unpack_dfa(e);
868 From a94d5e11c0484af59e5feebf144cc48c186892ad Mon Sep 17 00:00:00 2001
869 From: John Johansen <john.johansen@canonical.com>
870 Date: Wed, 16 May 2012 10:58:05 -0700
871 Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate
874 Add the ability for apparmor to do mediation of mount operations. Mount
875 rules require an updated apparmor_parser (2.8 series) for policy compilation.
877 The basic form of the rules are.
879 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
880 [audit] [deny] remount [conds]* [path],
881 [audit] [deny] umount [conds]* [path],
882 [audit] [deny] pivotroot [oldroot=<value>] <path>
884 remount is just a short cut for mount options=remount
890 Example mount commands
891 mount, # allow all mounts, but not umount or pivotroot
893 mount fstype=procfs, # allow mounting procfs anywhere
895 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
897 mount /dev/sda -> /mnt,
899 mount /dev/sd** -> /mnt/**,
901 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
907 See the apparmor userspace for full documentation
909 Signed-off-by: John Johansen <john.johansen@canonical.com>
910 Acked-by: Kees Cook <kees@ubuntu.com>
912 security/apparmor/Makefile | 2 +-
913 security/apparmor/apparmorfs.c | 13 +
914 security/apparmor/audit.c | 4 +
915 security/apparmor/domain.c | 2 +-
916 security/apparmor/include/apparmor.h | 3 +-
917 security/apparmor/include/audit.h | 11 +
918 security/apparmor/include/domain.h | 2 +
919 security/apparmor/include/mount.h | 54 +++
920 security/apparmor/lsm.c | 59 ++++
921 security/apparmor/mount.c | 620 ++++++++++++++++++++++++++++++++++
922 10 files changed, 767 insertions(+), 3 deletions(-)
923 create mode 100644 security/apparmor/include/mount.h
924 create mode 100644 security/apparmor/mount.c
926 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
927 index 19daa85..63e0a4c 100644
928 --- a/security/apparmor/Makefile
929 +++ b/security/apparmor/Makefile
930 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
932 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
933 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
934 - resource.o sid.o file.o net.o
935 + resource.o sid.o file.o net.o mount.o
937 clean-files := capability_names.h rlim_names.h net_names.h
939 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
940 index c66315d..ff19009 100644
941 --- a/security/apparmor/apparmorfs.c
942 +++ b/security/apparmor/apparmorfs.c
943 @@ -424,10 +424,23 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
947 +static struct aa_fs_entry aa_fs_entry_mount[] = {
948 + AA_FS_FILE_STRING("mask", "mount umount"),
952 +static struct aa_fs_entry aa_fs_entry_namespaces[] = {
953 + AA_FS_FILE_BOOLEAN("profile", 1),
954 + AA_FS_FILE_BOOLEAN("pivot_root", 1),
958 static struct aa_fs_entry aa_fs_entry_features[] = {
959 AA_FS_DIR("domain", aa_fs_entry_domain),
960 AA_FS_DIR("file", aa_fs_entry_file),
961 AA_FS_DIR("network", aa_fs_entry_network),
962 + AA_FS_DIR("mount", aa_fs_entry_mount),
963 + AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
964 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
965 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
967 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
968 index cc3520d..b9f5ee9 100644
969 --- a/security/apparmor/audit.c
970 +++ b/security/apparmor/audit.c
971 @@ -44,6 +44,10 @@ const char *const op_table[] = {
982 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
983 index 6327685..dfdc47b 100644
984 --- a/security/apparmor/domain.c
985 +++ b/security/apparmor/domain.c
986 @@ -242,7 +242,7 @@ static const char *next_name(int xtype, const char *name)
988 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
990 -static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
991 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
993 struct aa_profile *new_profile = NULL;
994 struct aa_namespace *ns = profile->ns;
995 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
996 index 40aedd9..e243d96 100644
997 --- a/security/apparmor/include/apparmor.h
998 +++ b/security/apparmor/include/apparmor.h
1000 #define AA_CLASS_NET 4
1001 #define AA_CLASS_RLIMITS 5
1002 #define AA_CLASS_DOMAIN 6
1003 +#define AA_CLASS_MOUNT 7
1005 -#define AA_CLASS_LAST AA_CLASS_DOMAIN
1006 +#define AA_CLASS_LAST AA_CLASS_MOUNT
1008 /* Control parameters settable through module/boot flags */
1009 extern enum audit_mode aa_g_audit;
1010 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
1011 index c1ff09c..7b90900c 100644
1012 --- a/security/apparmor/include/audit.h
1013 +++ b/security/apparmor/include/audit.h
1014 @@ -73,6 +73,10 @@ enum aa_ops {
1025 @@ -121,6 +125,13 @@ struct apparmor_audit_data {
1029 + const char *src_name;
1031 + const char *trans;
1033 + unsigned long flags;
1039 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
1040 index de04464..a3f70c5 100644
1041 --- a/security/apparmor/include/domain.h
1042 +++ b/security/apparmor/include/domain.h
1043 @@ -23,6 +23,8 @@ struct aa_domain {
1047 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
1049 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
1050 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
1051 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
1052 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
1053 new file mode 100644
1054 index 0000000..bc17a53
1056 +++ b/security/apparmor/include/mount.h
1059 + * AppArmor security module
1061 + * This file contains AppArmor file mediation function definitions.
1063 + * Copyright 2012 Canonical Ltd.
1065 + * This program is free software; you can redistribute it and/or
1066 + * modify it under the terms of the GNU General Public License as
1067 + * published by the Free Software Foundation, version 2 of the
1071 +#ifndef __AA_MOUNT_H
1072 +#define __AA_MOUNT_H
1074 +#include <linux/fs.h>
1075 +#include <linux/path.h>
1077 +#include "domain.h"
1078 +#include "policy.h"
1081 +#define AA_MAY_PIVOTROOT 0x01
1082 +#define AA_MAY_MOUNT 0x02
1083 +#define AA_MAY_UMOUNT 0x04
1084 +#define AA_AUDIT_DATA 0x40
1085 +#define AA_CONT_MATCH 0x40
1087 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
1089 +int aa_remount(struct aa_profile *profile, struct path *path,
1090 + unsigned long flags, void *data);
1092 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
1093 + const char *old_name, unsigned long flags);
1096 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1097 + unsigned long flags);
1099 +int aa_move_mount(struct aa_profile *profile, struct path *path,
1100 + const char *old_name);
1102 +int aa_new_mount(struct aa_profile *profile, const char *dev_name,
1103 + struct path *path, const char *type, unsigned long flags,
1106 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
1108 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1109 + struct path *new_path);
1111 +#endif /* __AA_MOUNT_H */
1112 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1113 index 3cde194..4512cc6 100644
1114 --- a/security/apparmor/lsm.c
1115 +++ b/security/apparmor/lsm.c
1117 #include "include/path.h"
1118 #include "include/policy.h"
1119 #include "include/procattr.h"
1120 +#include "include/mount.h"
1122 /* Flag indicating whether initialization completed */
1123 int apparmor_initialized __initdata;
1124 @@ -512,6 +513,60 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1125 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1128 +static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
1129 + unsigned long flags, void *data)
1131 + struct aa_profile *profile;
1134 + /* Discard magic */
1135 + if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1136 + flags &= ~MS_MGC_MSK;
1138 + flags &= ~AA_MS_IGNORE_MASK;
1140 + profile = __aa_current_profile();
1141 + if (!unconfined(profile)) {
1142 + if (flags & MS_REMOUNT)
1143 + error = aa_remount(profile, path, flags, data);
1144 + else if (flags & MS_BIND)
1145 + error = aa_bind_mount(profile, path, dev_name, flags);
1146 + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
1148 + error = aa_mount_change_type(profile, path, flags);
1149 + else if (flags & MS_MOVE)
1150 + error = aa_move_mount(profile, path, dev_name);
1152 + error = aa_new_mount(profile, dev_name, path, type,
1158 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
1160 + struct aa_profile *profile;
1163 + profile = __aa_current_profile();
1164 + if (!unconfined(profile))
1165 + error = aa_umount(profile, mnt, flags);
1170 +static int apparmor_sb_pivotroot(struct path *old_path, struct path *new_path)
1172 + struct aa_profile *profile;
1175 + profile = __aa_current_profile();
1176 + if (!unconfined(profile))
1177 + error = aa_pivotroot(profile, old_path, new_path);
1182 static int apparmor_getprocattr(struct task_struct *task, char *name,
1185 @@ -729,6 +784,10 @@ static struct security_operations apparmor_ops = {
1186 .capget = apparmor_capget,
1187 .capable = apparmor_capable,
1189 + .sb_mount = apparmor_sb_mount,
1190 + .sb_umount = apparmor_sb_umount,
1191 + .sb_pivotroot = apparmor_sb_pivotroot,
1193 .path_link = apparmor_path_link,
1194 .path_unlink = apparmor_path_unlink,
1195 .path_symlink = apparmor_path_symlink,
1196 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
1197 new file mode 100644
1198 index 0000000..63d8493
1200 +++ b/security/apparmor/mount.c
1203 + * AppArmor security module
1205 + * This file contains AppArmor mediation of files
1207 + * Copyright (C) 1998-2008 Novell/SUSE
1208 + * Copyright 2009-2012 Canonical Ltd.
1210 + * This program is free software; you can redistribute it and/or
1211 + * modify it under the terms of the GNU General Public License as
1212 + * published by the Free Software Foundation, version 2 of the
1216 +#include <linux/fs.h>
1217 +#include <linux/mount.h>
1218 +#include <linux/namei.h>
1220 +#include "include/apparmor.h"
1221 +#include "include/audit.h"
1222 +#include "include/context.h"
1223 +#include "include/domain.h"
1224 +#include "include/file.h"
1225 +#include "include/match.h"
1226 +#include "include/mount.h"
1227 +#include "include/path.h"
1228 +#include "include/policy.h"
1231 +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
1233 + if (flags & MS_RDONLY)
1234 + audit_log_format(ab, "ro");
1236 + audit_log_format(ab, "rw");
1237 + if (flags & MS_NOSUID)
1238 + audit_log_format(ab, ", nosuid");
1239 + if (flags & MS_NODEV)
1240 + audit_log_format(ab, ", nodev");
1241 + if (flags & MS_NOEXEC)
1242 + audit_log_format(ab, ", noexec");
1243 + if (flags & MS_SYNCHRONOUS)
1244 + audit_log_format(ab, ", sync");
1245 + if (flags & MS_REMOUNT)
1246 + audit_log_format(ab, ", remount");
1247 + if (flags & MS_MANDLOCK)
1248 + audit_log_format(ab, ", mand");
1249 + if (flags & MS_DIRSYNC)
1250 + audit_log_format(ab, ", dirsync");
1251 + if (flags & MS_NOATIME)
1252 + audit_log_format(ab, ", noatime");
1253 + if (flags & MS_NODIRATIME)
1254 + audit_log_format(ab, ", nodiratime");
1255 + if (flags & MS_BIND)
1256 + audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
1257 + if (flags & MS_MOVE)
1258 + audit_log_format(ab, ", move");
1259 + if (flags & MS_SILENT)
1260 + audit_log_format(ab, ", silent");
1261 + if (flags & MS_POSIXACL)
1262 + audit_log_format(ab, ", acl");
1263 + if (flags & MS_UNBINDABLE)
1264 + audit_log_format(ab, flags & MS_REC ? ", runbindable" :
1266 + if (flags & MS_PRIVATE)
1267 + audit_log_format(ab, flags & MS_REC ? ", rprivate" :
1269 + if (flags & MS_SLAVE)
1270 + audit_log_format(ab, flags & MS_REC ? ", rslave" :
1272 + if (flags & MS_SHARED)
1273 + audit_log_format(ab, flags & MS_REC ? ", rshared" :
1275 + if (flags & MS_RELATIME)
1276 + audit_log_format(ab, ", relatime");
1277 + if (flags & MS_I_VERSION)
1278 + audit_log_format(ab, ", iversion");
1279 + if (flags & MS_STRICTATIME)
1280 + audit_log_format(ab, ", strictatime");
1281 + if (flags & MS_NOUSER)
1282 + audit_log_format(ab, ", nouser");
1286 + * audit_cb - call back for mount specific audit fields
1287 + * @ab: audit_buffer (NOT NULL)
1288 + * @va: audit struct to audit values of (NOT NULL)
1290 +static void audit_cb(struct audit_buffer *ab, void *va)
1292 + struct common_audit_data *sa = va;
1294 + if (sa->aad->mnt.type) {
1295 + audit_log_format(ab, " fstype=");
1296 + audit_log_untrustedstring(ab, sa->aad->mnt.type);
1298 + if (sa->aad->mnt.src_name) {
1299 + audit_log_format(ab, " srcname=");
1300 + audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
1302 + if (sa->aad->mnt.trans) {
1303 + audit_log_format(ab, " trans=");
1304 + audit_log_untrustedstring(ab, sa->aad->mnt.trans);
1306 + if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
1307 + audit_log_format(ab, " flags=\"");
1308 + audit_mnt_flags(ab, sa->aad->mnt.flags);
1309 + audit_log_format(ab, "\"");
1311 + if (sa->aad->mnt.data) {
1312 + audit_log_format(ab, " options=");
1313 + audit_log_untrustedstring(ab, sa->aad->mnt.data);
1318 + * audit_mount - handle the auditing of mount operations
1319 + * @profile: the profile being enforced (NOT NULL)
1320 + * @gfp: allocation flags
1321 + * @op: operation being mediated (NOT NULL)
1322 + * @name: name of object being mediated (MAYBE NULL)
1323 + * @src_name: src_name of object being mediated (MAYBE_NULL)
1324 + * @type: type of filesystem (MAYBE_NULL)
1325 + * @trans: name of trans (MAYBE NULL)
1326 + * @flags: filesystem idependent mount flags
1327 + * @data: filesystem mount flags
1328 + * @request: permissions requested
1329 + * @perms: the permissions computed for the request (NOT NULL)
1330 + * @info: extra information message (MAYBE NULL)
1331 + * @error: 0 if operation allowed else failure error code
1333 + * Returns: %0 or error on failure
1335 +static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
1336 + const char *name, const char *src_name,
1337 + const char *type, const char *trans,
1338 + unsigned long flags, const void *data, u32 request,
1339 + struct file_perms *perms, const char *info, int error)
1341 + int audit_type = AUDIT_APPARMOR_AUTO;
1342 + struct common_audit_data sa;
1343 + struct apparmor_audit_data aad = { };
1345 + if (likely(!error)) {
1346 + u32 mask = perms->audit;
1348 + if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
1351 + /* mask off perms that are not being force audited */
1354 + if (likely(!request))
1356 + audit_type = AUDIT_APPARMOR_AUDIT;
1358 + /* only report permissions that were denied */
1359 + request = request & ~perms->allow;
1361 + if (request & perms->kill)
1362 + audit_type = AUDIT_APPARMOR_KILL;
1364 + /* quiet known rejects, assumes quiet and kill do not overlap */
1365 + if ((request & perms->quiet) &&
1366 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1367 + AUDIT_MODE(profile) != AUDIT_ALL)
1368 + request &= ~perms->quiet;
1371 + return COMPLAIN_MODE(profile) ?
1372 + complain_error(error) : error;
1375 + COMMON_AUDIT_DATA_INIT(&sa, NONE);
1378 + sa.aad->name = name;
1379 + sa.aad->mnt.src_name = src_name;
1380 + sa.aad->mnt.type = type;
1381 + sa.aad->mnt.trans = trans;
1382 + sa.aad->mnt.flags = flags;
1383 + if (data && (perms->audit & AA_AUDIT_DATA))
1384 + sa.aad->mnt.data = data;
1385 + sa.aad->info = info;
1386 + sa.aad->error = error;
1388 + return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
1392 + * match_mnt_flags - Do an ordered match on mount flags
1393 + * @dfa: dfa to match against
1394 + * @state: state to start in
1395 + * @flags: mount flags to match against
1397 + * Mount flags are encoded as an ordered match. This is done instead of
1398 + * checking against a simple bitmask, to allow for logical operations
1401 + * Returns: next state after flags match
1403 +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
1404 + unsigned long flags)
1408 + for (i = 0; i <= 31 ; ++i) {
1409 + if ((1 << i) & flags)
1410 + state = aa_dfa_next(dfa, state, i + 1);
1417 + * compute_mnt_perms - compute mount permission associated with @state
1418 + * @dfa: dfa to match against (NOT NULL)
1419 + * @state: state match finished in
1421 + * Returns: mount permissions
1423 +static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
1424 + unsigned int state)
1426 + struct file_perms perms;
1429 + perms.allow = dfa_user_allow(dfa, state);
1430 + perms.audit = dfa_user_audit(dfa, state);
1431 + perms.quiet = dfa_user_quiet(dfa, state);
1432 + perms.xindex = dfa_user_xindex(dfa, state);
1437 +static const char const *mnt_info_table[] = {
1438 + "match succeeded",
1439 + "failed mntpnt match",
1440 + "failed srcname match",
1441 + "failed type match",
1442 + "failed flags match",
1443 + "failed data match"
1447 + * Returns 0 on success else element that match failed in, this is the
1448 + * index into the mnt_info_table above
1450 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
1451 + const char *mntpnt, const char *devname,
1452 + const char *type, unsigned long flags,
1453 + void *data, bool binary, struct file_perms *perms)
1455 + unsigned int state;
1457 + state = aa_dfa_match(dfa, start, mntpnt);
1458 + state = aa_dfa_null_transition(dfa, state);
1463 + state = aa_dfa_match(dfa, state, devname);
1464 + state = aa_dfa_null_transition(dfa, state);
1469 + state = aa_dfa_match(dfa, state, type);
1470 + state = aa_dfa_null_transition(dfa, state);
1474 + state = match_mnt_flags(dfa, state, flags);
1477 + *perms = compute_mnt_perms(dfa, state);
1478 + if (perms->allow & AA_MAY_MOUNT)
1481 + /* only match data if not binary and the DFA flags data is expected */
1482 + if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
1483 + state = aa_dfa_null_transition(dfa, state);
1487 + state = aa_dfa_match(dfa, state, data);
1490 + *perms = compute_mnt_perms(dfa, state);
1491 + if (perms->allow & AA_MAY_MOUNT)
1495 + /* failed at end of flags match */
1500 + * match_mnt - handle path matching for mount
1501 + * @profile: the confining profile
1502 + * @mntpnt: string for the mntpnt (NOT NULL)
1503 + * @devname: string for the devname/src_name (MAYBE NULL)
1504 + * @type: string for the dev type (MAYBE NULL)
1505 + * @flags: mount flags to match
1506 + * @data: fs mount data (MAYBE NULL)
1507 + * @binary: whether @data is binary
1508 + * @perms: Returns: permission found by the match
1509 + * @info: Returns: infomation string about the match for logging
1511 + * Returns: 0 on success else error
1513 +static int match_mnt(struct aa_profile *profile, const char *mntpnt,
1514 + const char *devname, const char *type,
1515 + unsigned long flags, void *data, bool binary,
1516 + struct file_perms *perms, const char **info)
1520 + if (!profile->policy.dfa)
1523 + pos = do_match_mnt(profile->policy.dfa,
1524 + profile->policy.start[AA_CLASS_MOUNT],
1525 + mntpnt, devname, type, flags, data, binary, perms);
1527 + *info = mnt_info_table[pos];
1534 +static int path_flags(struct aa_profile *profile, struct path *path)
1536 + return profile->path_flags |
1537 + S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
1540 +int aa_remount(struct aa_profile *profile, struct path *path,
1541 + unsigned long flags, void *data)
1543 + struct file_perms perms = { };
1544 + const char *name, *info = NULL;
1545 + char *buffer = NULL;
1546 + int binary, error;
1548 + binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
1550 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1555 + error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
1559 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1560 + NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1567 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
1568 + const char *dev_name, unsigned long flags)
1570 + struct file_perms perms = { };
1571 + char *buffer = NULL, *old_buffer = NULL;
1572 + const char *name, *old_name = NULL, *info = NULL;
1573 + struct path old_path;
1576 + if (!dev_name || !*dev_name)
1579 + flags &= MS_REC | MS_BIND;
1581 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1586 + error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1590 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1591 + &old_buffer, &old_name, &info);
1592 + path_put(&old_path);
1596 + error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
1600 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1601 + NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
1604 + kfree(old_buffer);
1609 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1610 + unsigned long flags)
1612 + struct file_perms perms = { };
1613 + char *buffer = NULL;
1614 + const char *name, *info = NULL;
1617 + /* These are the flags allowed by do_change_type() */
1618 + flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
1621 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1626 + error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
1630 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1631 + NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
1638 +int aa_move_mount(struct aa_profile *profile, struct path *path,
1639 + const char *orig_name)
1641 + struct file_perms perms = { };
1642 + char *buffer = NULL, *old_buffer = NULL;
1643 + const char *name, *old_name = NULL, *info = NULL;
1644 + struct path old_path;
1647 + if (!orig_name || !*orig_name)
1650 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1655 + error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
1659 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1660 + &old_buffer, &old_name, &info);
1661 + path_put(&old_path);
1665 + error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
1669 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1670 + NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
1673 + kfree(old_buffer);
1678 +int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
1679 + struct path *path, const char *type, unsigned long flags,
1682 + struct file_perms perms = { };
1683 + char *buffer = NULL, *dev_buffer = NULL;
1684 + const char *name = NULL, *dev_name = NULL, *info = NULL;
1688 + dev_name = orig_dev_name;
1691 + struct file_system_type *fstype = get_fs_type(type);
1695 + binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
1696 + requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
1697 + put_filesystem(fstype);
1699 + if (requires_dev) {
1700 + struct path dev_path;
1702 + if (!dev_name || !*dev_name) {
1707 + error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
1711 + error = aa_path_name(&dev_path,
1712 + path_flags(profile, &dev_path),
1713 + &dev_buffer, &dev_name, &info);
1714 + path_put(&dev_path);
1720 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1725 + error = match_mnt(profile, name, dev_name, type, flags, data, binary,
1729 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
1730 + type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1733 + kfree(dev_buffer);
1740 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
1742 + struct file_perms perms = { };
1743 + char *buffer = NULL;
1744 + const char *name, *info = NULL;
1747 + struct path path = { mnt, mnt->mnt_root };
1748 + error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
1753 + if (!error && profile->policy.dfa) {
1754 + unsigned int state;
1755 + state = aa_dfa_match(profile->policy.dfa,
1756 + profile->policy.start[AA_CLASS_MOUNT],
1758 + perms = compute_mnt_perms(profile->policy.dfa, state);
1761 + if (AA_MAY_UMOUNT & ~perms.allow)
1765 + error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
1766 + NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
1772 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1773 + struct path *new_path)
1775 + struct file_perms perms = { };
1776 + struct aa_profile *target = NULL;
1777 + char *old_buffer = NULL, *new_buffer = NULL;
1778 + const char *old_name, *new_name = NULL, *info = NULL;
1781 + error = aa_path_name(old_path, path_flags(profile, old_path),
1782 + &old_buffer, &old_name, &info);
1786 + error = aa_path_name(new_path, path_flags(profile, new_path),
1787 + &new_buffer, &new_name, &info);
1791 + if (profile->policy.dfa) {
1792 + unsigned int state;
1793 + state = aa_dfa_match(profile->policy.dfa,
1794 + profile->policy.start[AA_CLASS_MOUNT],
1796 + state = aa_dfa_null_transition(profile->policy.dfa, state);
1797 + state = aa_dfa_match(profile->policy.dfa, state, old_name);
1798 + perms = compute_mnt_perms(profile->policy.dfa, state);
1801 + if (AA_MAY_PIVOTROOT & perms.allow) {
1802 + if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
1803 + target = x_table_lookup(profile, perms.xindex);
1807 + error = aa_replace_current_profile(target);
1813 + error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
1814 + old_name, NULL, target ? target->base.name : NULL,
1815 + 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
1816 + aa_put_profile(target);
1817 + kfree(old_buffer);
1818 + kfree(new_buffer);