1 From 05bf1eb7276886a3eda0588a8e012b558b693e96 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] UBUNTU: SAUCE: AppArmor: Add profile introspection file to
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>
13 security/apparmor/Kconfig | 9 ++
14 security/apparmor/apparmorfs.c | 231 ++++++++++++++++++++++++++++++++++++++++
15 2 files changed, 240 insertions(+), 0 deletions(-)
17 diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
18 index 9b9013b..51ebf96 100644
19 --- a/security/apparmor/Kconfig
20 +++ b/security/apparmor/Kconfig
21 @@ -29,3 +29,12 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
24 If you are unsure how to answer this question, answer 1.
26 +config SECURITY_APPARMOR_COMPAT_24
27 + bool "Enable AppArmor 2.4 compatability"
28 + depends on SECURITY_APPARMOR
31 + This option enables compatability with AppArmor 2.4. It is
32 + recommended if compatability with older versions of AppArmor
34 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
35 index 16c15ec..42b7c9f 100644
36 --- a/security/apparmor/apparmorfs.c
37 +++ b/security/apparmor/apparmorfs.c
38 @@ -182,6 +182,234 @@ const struct file_operations aa_fs_seq_file_ops = {
39 .release = single_release,
42 +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
44 + * __next_namespace - find the next namespace to list
45 + * @root: root namespace to stop search at (NOT NULL)
46 + * @ns: current ns position (NOT NULL)
48 + * Find the next namespace from @ns under @root and handle all locking needed
49 + * while switching current namespace.
51 + * Returns: next namespace or NULL if at last namespace under @root
52 + * NOTE: will not unlock root->lock
54 +static struct aa_namespace *__next_namespace(struct aa_namespace *root,
55 + struct aa_namespace *ns)
57 + struct aa_namespace *parent;
59 + /* is next namespace a child */
60 + if (!list_empty(&ns->sub_ns)) {
61 + struct aa_namespace *next;
62 + next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
63 + read_lock(&next->lock);
67 + /* check if the next ns is a sibling, parent, gp, .. */
68 + parent = ns->parent;
70 + read_unlock(&ns->lock);
71 + list_for_each_entry_continue(ns, &parent->sub_ns, base.list) {
72 + read_lock(&ns->lock);
78 + parent = parent->parent;
85 + * __first_profile - find the first profile in a namespace
86 + * @root: namespace that is root of profiles being displayed (NOT NULL)
87 + * @ns: namespace to start in (NOT NULL)
89 + * Returns: unrefcounted profile or NULL if no profile
91 +static struct aa_profile *__first_profile(struct aa_namespace *root,
92 + struct aa_namespace *ns)
94 + for ( ; ns; ns = __next_namespace(root, ns)) {
95 + if (!list_empty(&ns->base.profiles))
96 + return list_first_entry(&ns->base.profiles,
97 + struct aa_profile, base.list);
103 + * __next_profile - step to the next profile in a profile tree
104 + * @profile: current profile in tree (NOT NULL)
106 + * Perform a depth first taversal on the profile tree in a namespace
108 + * Returns: next profile or NULL if done
109 + * Requires: profile->ns.lock to be held
111 +static struct aa_profile *__next_profile(struct aa_profile *p)
113 + struct aa_profile *parent;
114 + struct aa_namespace *ns = p->ns;
116 + /* is next profile a child */
117 + if (!list_empty(&p->base.profiles))
118 + return list_first_entry(&p->base.profiles, typeof(*p),
121 + /* is next profile a sibling, parent sibling, gp, subling, .. */
122 + parent = p->parent;
124 + list_for_each_entry_continue(p, &parent->base.profiles,
128 + parent = parent->parent;
131 + /* is next another profile in the namespace */
132 + list_for_each_entry_continue(p, &ns->base.profiles, base.list)
139 + * next_profile - step to the next profile in where ever it may be
140 + * @root: root namespace (NOT NULL)
141 + * @profile: current profile (NOT NULL)
143 + * Returns: next profile or NULL if there isn't one
145 +static struct aa_profile *next_profile(struct aa_namespace *root,
146 + struct aa_profile *profile)
148 + struct aa_profile *next = __next_profile(profile);
152 + /* finished all profiles in namespace move to next namespace */
153 + return __first_profile(root, __next_namespace(root, profile->ns));
157 + * p_start - start a depth first traversal of profile tree
158 + * @f: seq_file to fill
159 + * @pos: current position
161 + * Returns: first profile under current namespace or NULL if none found
163 + * acquires first ns->lock
165 +static void *p_start(struct seq_file *f, loff_t *pos)
166 + __acquires(root->lock)
168 + struct aa_profile *profile = NULL;
169 + struct aa_namespace *root = aa_current_profile()->ns;
171 + f->private = aa_get_namespace(root);
174 + /* find the first profile */
175 + read_lock(&root->lock);
176 + profile = __first_profile(root, root);
178 + /* skip to position */
179 + for (; profile && l > 0; l--)
180 + profile = next_profile(root, profile);
186 + * p_next - read the next profile entry
187 + * @f: seq_file to fill
188 + * @p: profile previously returned
189 + * @pos: current position
191 + * Returns: next profile after @p or NULL if none
193 + * may acquire/release locks in namespace tree as necessary
195 +static void *p_next(struct seq_file *f, void *p, loff_t *pos)
197 + struct aa_profile *profile = p;
198 + struct aa_namespace *root = f->private;
201 + return next_profile(root, profile);
205 + * p_stop - stop depth first traversal
206 + * @f: seq_file we are filling
207 + * @p: the last profile writen
209 + * Release all locking done by p_start/p_next on namespace tree
211 +static void p_stop(struct seq_file *f, void *p)
212 + __releases(root->lock)
214 + struct aa_profile *profile = p;
215 + struct aa_namespace *root = f->private, *ns;
218 + for (ns = profile->ns; ns && ns != root; ns = ns->parent)
219 + read_unlock(&ns->lock);
221 + read_unlock(&root->lock);
222 + aa_put_namespace(root);
226 + * seq_show_profile - show a profile entry
227 + * @f: seq_file to file
228 + * @p: current position (profile) (NOT NULL)
230 + * Returns: error on failure
232 +static int seq_show_profile(struct seq_file *f, void *p)
234 + struct aa_profile *profile = (struct aa_profile *)p;
235 + struct aa_namespace *root = f->private;
237 + if (profile->ns != root)
238 + seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
239 + seq_printf(f, "%s (%s)\n", profile->base.hname,
240 + COMPLAIN_MODE(profile) ? "complain" : "enforce");
245 +static const struct seq_operations aa_fs_profiles_op = {
249 + .show = seq_show_profile,
252 +static int profiles_open(struct inode *inode, struct file *file)
254 + return seq_open(file, &aa_fs_profiles_op);
257 +static int profiles_release(struct inode *inode, struct file *file)
259 + return seq_release(inode, file);
262 +const struct file_operations aa_fs_profiles_fops = {
263 + .open = profiles_open,
265 + .llseek = seq_lseek,
266 + .release = profiles_release,
268 +#endif /* CONFIG_SECURITY_APPARMOR_COMPAT_24 */
270 /** Base file system setup **/
272 static struct aa_fs_entry aa_fs_entry_file[] = {
273 @@ -210,6 +438,9 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = {
274 AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
275 AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
276 AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
277 +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
278 + AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
280 AA_FS_DIR("features", aa_fs_entry_features),
286 From 4facdf9db37c12ff655c91270d9030e2ed805ca2 Mon Sep 17 00:00:00 2001
287 From: John Johansen <john.johansen@canonical.com>
288 Date: Mon, 4 Oct 2010 15:03:36 -0700
289 Subject: [PATCH] UBUNTU: SAUCE: AppArmor: basic networking rules
291 Base support for network mediation.
293 Signed-off-by: John Johansen <john.johansen@canonical.com>
295 security/apparmor/.gitignore | 2 +-
296 security/apparmor/Makefile | 42 +++++++++-
297 security/apparmor/apparmorfs.c | 1 +
298 security/apparmor/include/audit.h | 4 +
299 security/apparmor/include/net.h | 44 ++++++++++
300 security/apparmor/include/policy.h | 3 +
301 security/apparmor/lsm.c | 112 +++++++++++++++++++++++++
302 security/apparmor/net.c | 162 ++++++++++++++++++++++++++++++++++++
303 security/apparmor/policy.c | 1 +
304 security/apparmor/policy_unpack.c | 46 ++++++++++
305 10 files changed, 414 insertions(+), 3 deletions(-)
306 create mode 100644 security/apparmor/include/net.h
307 create mode 100644 security/apparmor/net.c
309 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
310 index 806bd19..19daa85 100644
311 --- a/security/apparmor/Makefile
312 +++ b/security/apparmor/Makefile
313 @@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
315 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
316 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
317 - resource.o sid.o file.o
318 + resource.o sid.o file.o net.o
320 -clean-files := capability_names.h rlim_names.h
321 +clean-files := capability_names.h rlim_names.h net_names.h
324 # Build a lower case string table of capability names
325 @@ -20,6 +20,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
326 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
329 +# Build a lower case string table of address family names
330 +# Transform lines from
331 +# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
332 +# #define AF_INET 2 /* Internet IP Protocol */
337 +# and build the securityfs entries for the mapping.
338 +# Transforms lines from
339 +# #define AF_INET 2 /* Internet IP Protocol */
341 +# #define AA_FS_AF_MASK "local inet"
342 +quiet_cmd_make-af = GEN $@
343 +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
344 + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
345 + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
347 + echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
348 + sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
349 + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
351 +# Build a lower case string table of sock type names
352 +# Transform lines from
356 +quiet_cmd_make-sock = GEN $@
357 +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
358 + sed $^ >>$@ -r -n \
359 + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
362 # Build a lower case string table of rlimit names.
363 # Transforms lines from
364 @@ -56,6 +88,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
365 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
367 $(obj)/capability.o : $(obj)/capability_names.h
368 +$(obj)/net.o : $(obj)/net_names.h
369 $(obj)/resource.o : $(obj)/rlim_names.h
370 $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
372 @@ -63,3 +96,8 @@ $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
373 $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \
375 $(call cmd,make-rlim)
376 +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
377 + $(srctree)/include/linux/net.h \
379 + $(call cmd,make-af)
380 + $(call cmd,make-sock)
381 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
382 index 42b7c9f..114fb23 100644
383 --- a/security/apparmor/apparmorfs.c
384 +++ b/security/apparmor/apparmorfs.c
385 @@ -429,6 +429,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
386 static struct aa_fs_entry aa_fs_entry_features[] = {
387 AA_FS_DIR("domain", aa_fs_entry_domain),
388 AA_FS_DIR("file", aa_fs_entry_file),
389 + AA_FS_DIR("network", aa_fs_entry_network),
390 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
391 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
393 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
394 index 4b7e189..17734f9 100644
395 --- a/security/apparmor/include/audit.h
396 +++ b/security/apparmor/include/audit.h
397 @@ -127,6 +127,10 @@ struct apparmor_audit_data {
402 + int type, protocol;
408 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
410 index 0000000..cb8a121
412 +++ b/security/apparmor/include/net.h
415 + * AppArmor security module
417 + * This file contains AppArmor network mediation definitions.
419 + * Copyright (C) 1998-2008 Novell/SUSE
420 + * Copyright 2009-2012 Canonical Ltd.
422 + * This program is free software; you can redistribute it and/or
423 + * modify it under the terms of the GNU General Public License as
424 + * published by the Free Software Foundation, version 2 of the
431 +#include <net/sock.h>
433 +#include "apparmorfs.h"
435 +/* struct aa_net - network confinement data
436 + * @allowed: basic network families permissions
437 + * @audit_network: which network permissions to force audit
438 + * @quiet_network: which network permissions to quiet rejects
446 +extern struct aa_fs_entry aa_fs_entry_network[];
448 +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
449 + int type, int protocol, struct sock *sk);
450 +extern int aa_revalidate_sk(int op, struct sock *sk);
452 +static inline void aa_free_net_rules(struct aa_net *new)
457 +#endif /* __AA_NET_H */
458 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
459 index bda4569..eb13a73 100644
460 --- a/security/apparmor/include/policy.h
461 +++ b/security/apparmor/include/policy.h
463 #include "capability.h"
467 #include "resource.h"
469 extern const char *const profile_mode_names[];
470 @@ -157,6 +158,7 @@ struct aa_policydb {
471 * @policy: general match rules governing policy
472 * @file: The set of rules governing basic file access and domain transitions
473 * @caps: capabilities for the profile
474 + * @net: network controls for the profile
475 * @rlimits: rlimits for the profile
477 * The AppArmor profile contains the basic confinement data. Each profile
478 @@ -194,6 +196,7 @@ struct aa_profile {
479 struct aa_policydb policy;
480 struct aa_file_rules file;
483 struct aa_rlimit rlimits;
486 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
487 index 8ea39aa..f628734 100644
488 --- a/security/apparmor/lsm.c
489 +++ b/security/apparmor/lsm.c
491 #include "include/context.h"
492 #include "include/file.h"
493 #include "include/ipc.h"
494 +#include "include/net.h"
495 #include "include/path.h"
496 #include "include/policy.h"
497 #include "include/procattr.h"
498 @@ -614,6 +615,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
502 +static int apparmor_socket_create(int family, int type, int protocol, int kern)
504 + struct aa_profile *profile;
510 + profile = __aa_current_profile();
511 + if (!unconfined(profile))
512 + error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
517 +static int apparmor_socket_bind(struct socket *sock,
518 + struct sockaddr *address, int addrlen)
520 + struct sock *sk = sock->sk;
522 + return aa_revalidate_sk(OP_BIND, sk);
525 +static int apparmor_socket_connect(struct socket *sock,
526 + struct sockaddr *address, int addrlen)
528 + struct sock *sk = sock->sk;
530 + return aa_revalidate_sk(OP_CONNECT, sk);
533 +static int apparmor_socket_listen(struct socket *sock, int backlog)
535 + struct sock *sk = sock->sk;
537 + return aa_revalidate_sk(OP_LISTEN, sk);
540 +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
542 + struct sock *sk = sock->sk;
544 + return aa_revalidate_sk(OP_ACCEPT, sk);
547 +static int apparmor_socket_sendmsg(struct socket *sock,
548 + struct msghdr *msg, int size)
550 + struct sock *sk = sock->sk;
552 + return aa_revalidate_sk(OP_SENDMSG, sk);
555 +static int apparmor_socket_recvmsg(struct socket *sock,
556 + struct msghdr *msg, int size, int flags)
558 + struct sock *sk = sock->sk;
560 + return aa_revalidate_sk(OP_RECVMSG, sk);
563 +static int apparmor_socket_getsockname(struct socket *sock)
565 + struct sock *sk = sock->sk;
567 + return aa_revalidate_sk(OP_GETSOCKNAME, sk);
570 +static int apparmor_socket_getpeername(struct socket *sock)
572 + struct sock *sk = sock->sk;
574 + return aa_revalidate_sk(OP_GETPEERNAME, sk);
577 +static int apparmor_socket_getsockopt(struct socket *sock, int level,
580 + struct sock *sk = sock->sk;
582 + return aa_revalidate_sk(OP_GETSOCKOPT, sk);
585 +static int apparmor_socket_setsockopt(struct socket *sock, int level,
588 + struct sock *sk = sock->sk;
590 + return aa_revalidate_sk(OP_SETSOCKOPT, sk);
593 +static int apparmor_socket_shutdown(struct socket *sock, int how)
595 + struct sock *sk = sock->sk;
597 + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
600 static struct security_operations apparmor_ops = {
603 @@ -646,6 +745,19 @@ static struct security_operations apparmor_ops = {
604 .getprocattr = apparmor_getprocattr,
605 .setprocattr = apparmor_setprocattr,
607 + .socket_create = apparmor_socket_create,
608 + .socket_bind = apparmor_socket_bind,
609 + .socket_connect = apparmor_socket_connect,
610 + .socket_listen = apparmor_socket_listen,
611 + .socket_accept = apparmor_socket_accept,
612 + .socket_sendmsg = apparmor_socket_sendmsg,
613 + .socket_recvmsg = apparmor_socket_recvmsg,
614 + .socket_getsockname = apparmor_socket_getsockname,
615 + .socket_getpeername = apparmor_socket_getpeername,
616 + .socket_getsockopt = apparmor_socket_getsockopt,
617 + .socket_setsockopt = apparmor_socket_setsockopt,
618 + .socket_shutdown = apparmor_socket_shutdown,
620 .cred_alloc_blank = apparmor_cred_alloc_blank,
621 .cred_free = apparmor_cred_free,
622 .cred_prepare = apparmor_cred_prepare,
623 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
625 index 0000000..003dd18
627 +++ b/security/apparmor/net.c
630 + * AppArmor security module
632 + * This file contains AppArmor network mediation
634 + * Copyright (C) 1998-2008 Novell/SUSE
635 + * Copyright 2009-2012 Canonical Ltd.
637 + * This program is free software; you can redistribute it and/or
638 + * modify it under the terms of the GNU General Public License as
639 + * published by the Free Software Foundation, version 2 of the
643 +#include "include/apparmor.h"
644 +#include "include/audit.h"
645 +#include "include/context.h"
646 +#include "include/net.h"
647 +#include "include/policy.h"
649 +#include "net_names.h"
651 +struct aa_fs_entry aa_fs_entry_network[] = {
652 + AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
656 +/* audit callback for net specific fields */
657 +static void audit_cb(struct audit_buffer *ab, void *va)
659 + struct common_audit_data *sa = va;
661 + audit_log_format(ab, " family=");
662 + if (address_family_names[sa->u.net->family]) {
663 + audit_log_string(ab, address_family_names[sa->u.net->family]);
665 + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
667 + audit_log_format(ab, " sock_type=");
668 + if (sock_type_names[sa->aad->net.type]) {
669 + audit_log_string(ab, sock_type_names[sa->aad->net.type]);
671 + audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
673 + audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
677 + * audit_net - audit network access
678 + * @profile: profile being enforced (NOT NULL)
679 + * @op: operation being checked
680 + * @family: network family
681 + * @type: network type
682 + * @protocol: network protocol
683 + * @sk: socket auditing is being applied to
684 + * @error: error code for failure else 0
686 + * Returns: %0 or sa->error else other errorcode on failure
688 +static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
689 + int protocol, struct sock *sk, int error)
691 + int audit_type = AUDIT_APPARMOR_AUTO;
692 + struct common_audit_data sa;
693 + struct apparmor_audit_data aad = { };
694 + struct lsm_network_audit net = { };
696 + sa.type = LSM_AUDIT_DATA_NET;
698 + sa.type = LSM_AUDIT_DATA_NONE;
700 + /* todo fill in socket addr info */
704 + sa.u.net->family = family;
706 + sa.aad->net.type = type;
707 + sa.aad->net.protocol = protocol;
708 + sa.aad->error = error;
710 + if (likely(!sa.aad->error)) {
711 + u16 audit_mask = profile->net.audit[sa.u.net->family];
712 + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
713 + !(1 << sa.aad->net.type & audit_mask)))
715 + audit_type = AUDIT_APPARMOR_AUDIT;
717 + u16 quiet_mask = profile->net.quiet[sa.u.net->family];
719 + u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
721 + if (denied & kill_mask)
722 + audit_type = AUDIT_APPARMOR_KILL;
724 + if ((denied & quiet_mask) &&
725 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
726 + AUDIT_MODE(profile) != AUDIT_ALL)
727 + return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
730 + return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
734 + * aa_net_perm - very course network access check
735 + * @op: operation being checked
736 + * @profile: profile being enforced (NOT NULL)
737 + * @family: network family
738 + * @type: network type
739 + * @protocol: network protocol
741 + * Returns: %0 else error if permission denied
743 +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
744 + int protocol, struct sock *sk)
749 + if ((family < 0) || (family >= AF_MAX))
752 + if ((type < 0) || (type >= SOCK_MAX))
755 + /* unix domain and netlink sockets are handled by ipc */
756 + if (family == AF_UNIX || family == AF_NETLINK)
759 + family_mask = profile->net.allow[family];
761 + error = (family_mask & (1 << type)) ? 0 : -EACCES;
763 + return audit_net(profile, op, family, type, protocol, sk, error);
767 + * aa_revalidate_sk - Revalidate access to a sock
768 + * @op: operation being checked
769 + * @sk: sock being revalidated (NOT NULL)
771 + * Returns: %0 else error if permission denied
773 +int aa_revalidate_sk(int op, struct sock *sk)
775 + struct aa_profile *profile;
778 + /* aa_revalidate_sk should not be called from interrupt context
779 + * don't mediate these calls as they are not task related
781 + if (in_interrupt())
784 + profile = __aa_current_profile();
785 + if (!unconfined(profile))
786 + error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
787 + sk->sk_protocol, sk);
791 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
792 index cf5fd22..27c8161 100644
793 --- a/security/apparmor/policy.c
794 +++ b/security/apparmor/policy.c
795 @@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile)
797 aa_free_file_rules(&profile->file);
798 aa_free_cap_rules(&profile->caps);
799 + aa_free_net_rules(&profile->net);
800 aa_free_rlimit_rules(&profile->rlimits);
802 aa_free_sid(profile->sid);
803 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
804 index 329b1fd..1b90dfa 100644
805 --- a/security/apparmor/policy_unpack.c
806 +++ b/security/apparmor/policy_unpack.c
807 @@ -193,6 +193,19 @@ fail:
811 +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
813 + if (unpack_nameX(e, AA_U16, name)) {
814 + if (!inbounds(e, sizeof(u16)))
817 + *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
818 + e->pos += sizeof(u16);
824 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
826 if (unpack_nameX(e, AA_U32, name)) {
827 @@ -471,6 +484,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
829 struct aa_profile *profile = NULL;
830 const char *name = NULL;
832 int i, error = -EPROTO;
835 @@ -564,6 +578,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
836 if (!unpack_rlimits(e, profile))
839 + size = unpack_array(e, "net_allowed_af");
842 + for (i = 0; i < size; i++) {
843 + /* discard extraneous rules that this kernel will
848 + if (!unpack_u16(e, &tmp, NULL) ||
849 + !unpack_u16(e, &tmp, NULL) ||
850 + !unpack_u16(e, &tmp, NULL))
854 + if (!unpack_u16(e, &profile->net.allow[i], NULL))
856 + if (!unpack_u16(e, &profile->net.audit[i], NULL))
858 + if (!unpack_u16(e, &profile->net.quiet[i], NULL))
861 + if (!unpack_nameX(e, AA_ARRAYEND, NULL))
865 + * allow unix domain and netlink sockets they are handled
868 + profile->net.allow[AF_UNIX] = 0xffff;
869 + profile->net.allow[AF_NETLINK] = 0xffff;
871 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
872 /* generic policy dfa - optional and may be NULL */
873 profile->policy.dfa = unpack_dfa(e);
877 From 888a3d71db1ffd3a19d9f621b07e60c4ab9e1c44 Mon Sep 17 00:00:00 2001
878 From: John Johansen <john.johansen@canonical.com>
879 Date: Wed, 16 May 2012 10:58:05 -0700
880 Subject: [PATCH] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
882 Add the ability for apparmor to do mediation of mount operations. Mount
883 rules require an updated apparmor_parser (2.8 series) for policy compilation.
885 The basic form of the rules are.
887 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
888 [audit] [deny] remount [conds]* [path],
889 [audit] [deny] umount [conds]* [path],
890 [audit] [deny] pivotroot [oldroot=<value>] <path>
892 remount is just a short cut for mount options=remount
898 Example mount commands
899 mount, # allow all mounts, but not umount or pivotroot
901 mount fstype=procfs, # allow mounting procfs anywhere
903 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
905 mount /dev/sda -> /mnt,
907 mount /dev/sd** -> /mnt/**,
909 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
915 See the apparmor userspace for full documentation
917 Signed-off-by: John Johansen <john.johansen@canonical.com>
918 Acked-by: Kees Cook <kees@ubuntu.com>
920 security/apparmor/Makefile | 2 +-
921 security/apparmor/apparmorfs.c | 13 +
922 security/apparmor/audit.c | 4 +
923 security/apparmor/domain.c | 2 +-
924 security/apparmor/include/apparmor.h | 3 +-
925 security/apparmor/include/audit.h | 11 +
926 security/apparmor/include/domain.h | 2 +
927 security/apparmor/include/mount.h | 54 +++
928 security/apparmor/lsm.c | 59 ++++
929 security/apparmor/mount.c | 620 ++++++++++++++++++++++++++++++++++
930 10 files changed, 767 insertions(+), 3 deletions(-)
931 create mode 100644 security/apparmor/include/mount.h
932 create mode 100644 security/apparmor/mount.c
934 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
935 index 19daa85..63e0a4c 100644
936 --- a/security/apparmor/Makefile
937 +++ b/security/apparmor/Makefile
938 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
940 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
941 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
942 - resource.o sid.o file.o net.o
943 + resource.o sid.o file.o net.o mount.o
945 clean-files := capability_names.h rlim_names.h net_names.h
947 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
948 index 114fb23..ee77ec9 100644
949 --- a/security/apparmor/apparmorfs.c
950 +++ b/security/apparmor/apparmorfs.c
951 @@ -426,10 +426,23 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
955 +static struct aa_fs_entry aa_fs_entry_mount[] = {
956 + AA_FS_FILE_STRING("mask", "mount umount"),
960 +static struct aa_fs_entry aa_fs_entry_namespaces[] = {
961 + AA_FS_FILE_BOOLEAN("profile", 1),
962 + AA_FS_FILE_BOOLEAN("pivot_root", 1),
966 static struct aa_fs_entry aa_fs_entry_features[] = {
967 AA_FS_DIR("domain", aa_fs_entry_domain),
968 AA_FS_DIR("file", aa_fs_entry_file),
969 AA_FS_DIR("network", aa_fs_entry_network),
970 + AA_FS_DIR("mount", aa_fs_entry_mount),
971 + AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
972 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
973 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
975 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
976 index 3ae28db..e267963 100644
977 --- a/security/apparmor/audit.c
978 +++ b/security/apparmor/audit.c
979 @@ -44,6 +44,10 @@ const char *const op_table[] = {
990 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
991 index b81ea10..afa8671 100644
992 --- a/security/apparmor/domain.c
993 +++ b/security/apparmor/domain.c
994 @@ -242,7 +242,7 @@ static const char *next_name(int xtype, const char *name)
996 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
998 -static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
999 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
1001 struct aa_profile *new_profile = NULL;
1002 struct aa_namespace *ns = profile->ns;
1003 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
1004 index 40aedd9..e243d96 100644
1005 --- a/security/apparmor/include/apparmor.h
1006 +++ b/security/apparmor/include/apparmor.h
1008 #define AA_CLASS_NET 4
1009 #define AA_CLASS_RLIMITS 5
1010 #define AA_CLASS_DOMAIN 6
1011 +#define AA_CLASS_MOUNT 7
1013 -#define AA_CLASS_LAST AA_CLASS_DOMAIN
1014 +#define AA_CLASS_LAST AA_CLASS_MOUNT
1016 /* Control parameters settable through module/boot flags */
1017 extern enum audit_mode aa_g_audit;
1018 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
1019 index 17734f9..66a738c 100644
1020 --- a/security/apparmor/include/audit.h
1021 +++ b/security/apparmor/include/audit.h
1022 @@ -73,6 +73,10 @@ enum aa_ops {
1033 @@ -122,6 +126,13 @@ struct apparmor_audit_data {
1037 + const char *src_name;
1039 + const char *trans;
1041 + unsigned long flags;
1047 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
1048 index de04464..a3f70c5 100644
1049 --- a/security/apparmor/include/domain.h
1050 +++ b/security/apparmor/include/domain.h
1051 @@ -23,6 +23,8 @@ struct aa_domain {
1055 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
1057 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
1058 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
1059 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
1060 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
1061 new file mode 100644
1062 index 0000000..bc17a53
1064 +++ b/security/apparmor/include/mount.h
1067 + * AppArmor security module
1069 + * This file contains AppArmor file mediation function definitions.
1071 + * Copyright 2012 Canonical Ltd.
1073 + * This program is free software; you can redistribute it and/or
1074 + * modify it under the terms of the GNU General Public License as
1075 + * published by the Free Software Foundation, version 2 of the
1079 +#ifndef __AA_MOUNT_H
1080 +#define __AA_MOUNT_H
1082 +#include <linux/fs.h>
1083 +#include <linux/path.h>
1085 +#include "domain.h"
1086 +#include "policy.h"
1089 +#define AA_MAY_PIVOTROOT 0x01
1090 +#define AA_MAY_MOUNT 0x02
1091 +#define AA_MAY_UMOUNT 0x04
1092 +#define AA_AUDIT_DATA 0x40
1093 +#define AA_CONT_MATCH 0x40
1095 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
1097 +int aa_remount(struct aa_profile *profile, struct path *path,
1098 + unsigned long flags, void *data);
1100 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
1101 + const char *old_name, unsigned long flags);
1104 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1105 + unsigned long flags);
1107 +int aa_move_mount(struct aa_profile *profile, struct path *path,
1108 + const char *old_name);
1110 +int aa_new_mount(struct aa_profile *profile, const char *dev_name,
1111 + struct path *path, const char *type, unsigned long flags,
1114 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
1116 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1117 + struct path *new_path);
1119 +#endif /* __AA_MOUNT_H */
1120 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1121 index f628734..65ff9e4 100644
1122 --- a/security/apparmor/lsm.c
1123 +++ b/security/apparmor/lsm.c
1125 #include "include/path.h"
1126 #include "include/policy.h"
1127 #include "include/procattr.h"
1128 +#include "include/mount.h"
1130 /* Flag indicating whether initialization completed */
1131 int apparmor_initialized __initdata;
1132 @@ -504,6 +505,60 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1133 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1136 +static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
1137 + unsigned long flags, void *data)
1139 + struct aa_profile *profile;
1142 + /* Discard magic */
1143 + if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1144 + flags &= ~MS_MGC_MSK;
1146 + flags &= ~AA_MS_IGNORE_MASK;
1148 + profile = __aa_current_profile();
1149 + if (!unconfined(profile)) {
1150 + if (flags & MS_REMOUNT)
1151 + error = aa_remount(profile, path, flags, data);
1152 + else if (flags & MS_BIND)
1153 + error = aa_bind_mount(profile, path, dev_name, flags);
1154 + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
1156 + error = aa_mount_change_type(profile, path, flags);
1157 + else if (flags & MS_MOVE)
1158 + error = aa_move_mount(profile, path, dev_name);
1160 + error = aa_new_mount(profile, dev_name, path, type,
1166 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
1168 + struct aa_profile *profile;
1171 + profile = __aa_current_profile();
1172 + if (!unconfined(profile))
1173 + error = aa_umount(profile, mnt, flags);
1178 +static int apparmor_sb_pivotroot(struct path *old_path, struct path *new_path)
1180 + struct aa_profile *profile;
1183 + profile = __aa_current_profile();
1184 + if (!unconfined(profile))
1185 + error = aa_pivotroot(profile, old_path, new_path);
1190 static int apparmor_getprocattr(struct task_struct *task, char *name,
1193 @@ -721,6 +776,10 @@ static struct security_operations apparmor_ops = {
1194 .capget = apparmor_capget,
1195 .capable = apparmor_capable,
1197 + .sb_mount = apparmor_sb_mount,
1198 + .sb_umount = apparmor_sb_umount,
1199 + .sb_pivotroot = apparmor_sb_pivotroot,
1201 .path_link = apparmor_path_link,
1202 .path_unlink = apparmor_path_unlink,
1203 .path_symlink = apparmor_path_symlink,
1204 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
1205 new file mode 100644
1206 index 0000000..478aa4d
1208 +++ b/security/apparmor/mount.c
1211 + * AppArmor security module
1213 + * This file contains AppArmor mediation of files
1215 + * Copyright (C) 1998-2008 Novell/SUSE
1216 + * Copyright 2009-2012 Canonical Ltd.
1218 + * This program is free software; you can redistribute it and/or
1219 + * modify it under the terms of the GNU General Public License as
1220 + * published by the Free Software Foundation, version 2 of the
1224 +#include <linux/fs.h>
1225 +#include <linux/mount.h>
1226 +#include <linux/namei.h>
1228 +#include "include/apparmor.h"
1229 +#include "include/audit.h"
1230 +#include "include/context.h"
1231 +#include "include/domain.h"
1232 +#include "include/file.h"
1233 +#include "include/match.h"
1234 +#include "include/mount.h"
1235 +#include "include/path.h"
1236 +#include "include/policy.h"
1239 +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
1241 + if (flags & MS_RDONLY)
1242 + audit_log_format(ab, "ro");
1244 + audit_log_format(ab, "rw");
1245 + if (flags & MS_NOSUID)
1246 + audit_log_format(ab, ", nosuid");
1247 + if (flags & MS_NODEV)
1248 + audit_log_format(ab, ", nodev");
1249 + if (flags & MS_NOEXEC)
1250 + audit_log_format(ab, ", noexec");
1251 + if (flags & MS_SYNCHRONOUS)
1252 + audit_log_format(ab, ", sync");
1253 + if (flags & MS_REMOUNT)
1254 + audit_log_format(ab, ", remount");
1255 + if (flags & MS_MANDLOCK)
1256 + audit_log_format(ab, ", mand");
1257 + if (flags & MS_DIRSYNC)
1258 + audit_log_format(ab, ", dirsync");
1259 + if (flags & MS_NOATIME)
1260 + audit_log_format(ab, ", noatime");
1261 + if (flags & MS_NODIRATIME)
1262 + audit_log_format(ab, ", nodiratime");
1263 + if (flags & MS_BIND)
1264 + audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
1265 + if (flags & MS_MOVE)
1266 + audit_log_format(ab, ", move");
1267 + if (flags & MS_SILENT)
1268 + audit_log_format(ab, ", silent");
1269 + if (flags & MS_POSIXACL)
1270 + audit_log_format(ab, ", acl");
1271 + if (flags & MS_UNBINDABLE)
1272 + audit_log_format(ab, flags & MS_REC ? ", runbindable" :
1274 + if (flags & MS_PRIVATE)
1275 + audit_log_format(ab, flags & MS_REC ? ", rprivate" :
1277 + if (flags & MS_SLAVE)
1278 + audit_log_format(ab, flags & MS_REC ? ", rslave" :
1280 + if (flags & MS_SHARED)
1281 + audit_log_format(ab, flags & MS_REC ? ", rshared" :
1283 + if (flags & MS_RELATIME)
1284 + audit_log_format(ab, ", relatime");
1285 + if (flags & MS_I_VERSION)
1286 + audit_log_format(ab, ", iversion");
1287 + if (flags & MS_STRICTATIME)
1288 + audit_log_format(ab, ", strictatime");
1289 + if (flags & MS_NOUSER)
1290 + audit_log_format(ab, ", nouser");
1294 + * audit_cb - call back for mount specific audit fields
1295 + * @ab: audit_buffer (NOT NULL)
1296 + * @va: audit struct to audit values of (NOT NULL)
1298 +static void audit_cb(struct audit_buffer *ab, void *va)
1300 + struct common_audit_data *sa = va;
1302 + if (sa->aad->mnt.type) {
1303 + audit_log_format(ab, " fstype=");
1304 + audit_log_untrustedstring(ab, sa->aad->mnt.type);
1306 + if (sa->aad->mnt.src_name) {
1307 + audit_log_format(ab, " srcname=");
1308 + audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
1310 + if (sa->aad->mnt.trans) {
1311 + audit_log_format(ab, " trans=");
1312 + audit_log_untrustedstring(ab, sa->aad->mnt.trans);
1314 + if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
1315 + audit_log_format(ab, " flags=\"");
1316 + audit_mnt_flags(ab, sa->aad->mnt.flags);
1317 + audit_log_format(ab, "\"");
1319 + if (sa->aad->mnt.data) {
1320 + audit_log_format(ab, " options=");
1321 + audit_log_untrustedstring(ab, sa->aad->mnt.data);
1326 + * audit_mount - handle the auditing of mount operations
1327 + * @profile: the profile being enforced (NOT NULL)
1328 + * @gfp: allocation flags
1329 + * @op: operation being mediated (NOT NULL)
1330 + * @name: name of object being mediated (MAYBE NULL)
1331 + * @src_name: src_name of object being mediated (MAYBE_NULL)
1332 + * @type: type of filesystem (MAYBE_NULL)
1333 + * @trans: name of trans (MAYBE NULL)
1334 + * @flags: filesystem idependent mount flags
1335 + * @data: filesystem mount flags
1336 + * @request: permissions requested
1337 + * @perms: the permissions computed for the request (NOT NULL)
1338 + * @info: extra information message (MAYBE NULL)
1339 + * @error: 0 if operation allowed else failure error code
1341 + * Returns: %0 or error on failure
1343 +static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
1344 + const char *name, const char *src_name,
1345 + const char *type, const char *trans,
1346 + unsigned long flags, const void *data, u32 request,
1347 + struct file_perms *perms, const char *info, int error)
1349 + int audit_type = AUDIT_APPARMOR_AUTO;
1350 + struct common_audit_data sa = { };
1351 + struct apparmor_audit_data aad = { };
1353 + if (likely(!error)) {
1354 + u32 mask = perms->audit;
1356 + if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
1359 + /* mask off perms that are not being force audited */
1362 + if (likely(!request))
1364 + audit_type = AUDIT_APPARMOR_AUDIT;
1366 + /* only report permissions that were denied */
1367 + request = request & ~perms->allow;
1369 + if (request & perms->kill)
1370 + audit_type = AUDIT_APPARMOR_KILL;
1372 + /* quiet known rejects, assumes quiet and kill do not overlap */
1373 + if ((request & perms->quiet) &&
1374 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1375 + AUDIT_MODE(profile) != AUDIT_ALL)
1376 + request &= ~perms->quiet;
1379 + return COMPLAIN_MODE(profile) ?
1380 + complain_error(error) : error;
1383 + sa.type = LSM_AUDIT_DATA_NONE;
1386 + sa.aad->name = name;
1387 + sa.aad->mnt.src_name = src_name;
1388 + sa.aad->mnt.type = type;
1389 + sa.aad->mnt.trans = trans;
1390 + sa.aad->mnt.flags = flags;
1391 + if (data && (perms->audit & AA_AUDIT_DATA))
1392 + sa.aad->mnt.data = data;
1393 + sa.aad->info = info;
1394 + sa.aad->error = error;
1396 + return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
1400 + * match_mnt_flags - Do an ordered match on mount flags
1401 + * @dfa: dfa to match against
1402 + * @state: state to start in
1403 + * @flags: mount flags to match against
1405 + * Mount flags are encoded as an ordered match. This is done instead of
1406 + * checking against a simple bitmask, to allow for logical operations
1409 + * Returns: next state after flags match
1411 +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
1412 + unsigned long flags)
1416 + for (i = 0; i <= 31 ; ++i) {
1417 + if ((1 << i) & flags)
1418 + state = aa_dfa_next(dfa, state, i + 1);
1425 + * compute_mnt_perms - compute mount permission associated with @state
1426 + * @dfa: dfa to match against (NOT NULL)
1427 + * @state: state match finished in
1429 + * Returns: mount permissions
1431 +static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
1432 + unsigned int state)
1434 + struct file_perms perms;
1437 + perms.allow = dfa_user_allow(dfa, state);
1438 + perms.audit = dfa_user_audit(dfa, state);
1439 + perms.quiet = dfa_user_quiet(dfa, state);
1440 + perms.xindex = dfa_user_xindex(dfa, state);
1445 +static const char const *mnt_info_table[] = {
1446 + "match succeeded",
1447 + "failed mntpnt match",
1448 + "failed srcname match",
1449 + "failed type match",
1450 + "failed flags match",
1451 + "failed data match"
1455 + * Returns 0 on success else element that match failed in, this is the
1456 + * index into the mnt_info_table above
1458 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
1459 + const char *mntpnt, const char *devname,
1460 + const char *type, unsigned long flags,
1461 + void *data, bool binary, struct file_perms *perms)
1463 + unsigned int state;
1465 + state = aa_dfa_match(dfa, start, mntpnt);
1466 + state = aa_dfa_null_transition(dfa, state);
1471 + state = aa_dfa_match(dfa, state, devname);
1472 + state = aa_dfa_null_transition(dfa, state);
1477 + state = aa_dfa_match(dfa, state, type);
1478 + state = aa_dfa_null_transition(dfa, state);
1482 + state = match_mnt_flags(dfa, state, flags);
1485 + *perms = compute_mnt_perms(dfa, state);
1486 + if (perms->allow & AA_MAY_MOUNT)
1489 + /* only match data if not binary and the DFA flags data is expected */
1490 + if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
1491 + state = aa_dfa_null_transition(dfa, state);
1495 + state = aa_dfa_match(dfa, state, data);
1498 + *perms = compute_mnt_perms(dfa, state);
1499 + if (perms->allow & AA_MAY_MOUNT)
1503 + /* failed at end of flags match */
1508 + * match_mnt - handle path matching for mount
1509 + * @profile: the confining profile
1510 + * @mntpnt: string for the mntpnt (NOT NULL)
1511 + * @devname: string for the devname/src_name (MAYBE NULL)
1512 + * @type: string for the dev type (MAYBE NULL)
1513 + * @flags: mount flags to match
1514 + * @data: fs mount data (MAYBE NULL)
1515 + * @binary: whether @data is binary
1516 + * @perms: Returns: permission found by the match
1517 + * @info: Returns: infomation string about the match for logging
1519 + * Returns: 0 on success else error
1521 +static int match_mnt(struct aa_profile *profile, const char *mntpnt,
1522 + const char *devname, const char *type,
1523 + unsigned long flags, void *data, bool binary,
1524 + struct file_perms *perms, const char **info)
1528 + if (!profile->policy.dfa)
1531 + pos = do_match_mnt(profile->policy.dfa,
1532 + profile->policy.start[AA_CLASS_MOUNT],
1533 + mntpnt, devname, type, flags, data, binary, perms);
1535 + *info = mnt_info_table[pos];
1542 +static int path_flags(struct aa_profile *profile, struct path *path)
1544 + return profile->path_flags |
1545 + S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
1548 +int aa_remount(struct aa_profile *profile, struct path *path,
1549 + unsigned long flags, void *data)
1551 + struct file_perms perms = { };
1552 + const char *name, *info = NULL;
1553 + char *buffer = NULL;
1554 + int binary, error;
1556 + binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
1558 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1563 + error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
1567 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1568 + NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1575 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
1576 + const char *dev_name, unsigned long flags)
1578 + struct file_perms perms = { };
1579 + char *buffer = NULL, *old_buffer = NULL;
1580 + const char *name, *old_name = NULL, *info = NULL;
1581 + struct path old_path;
1584 + if (!dev_name || !*dev_name)
1587 + flags &= MS_REC | MS_BIND;
1589 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1594 + error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1598 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1599 + &old_buffer, &old_name, &info);
1600 + path_put(&old_path);
1604 + error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
1608 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1609 + NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
1612 + kfree(old_buffer);
1617 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1618 + unsigned long flags)
1620 + struct file_perms perms = { };
1621 + char *buffer = NULL;
1622 + const char *name, *info = NULL;
1625 + /* These are the flags allowed by do_change_type() */
1626 + flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
1629 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1634 + error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
1638 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1639 + NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
1646 +int aa_move_mount(struct aa_profile *profile, struct path *path,
1647 + const char *orig_name)
1649 + struct file_perms perms = { };
1650 + char *buffer = NULL, *old_buffer = NULL;
1651 + const char *name, *old_name = NULL, *info = NULL;
1652 + struct path old_path;
1655 + if (!orig_name || !*orig_name)
1658 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1663 + error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
1667 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1668 + &old_buffer, &old_name, &info);
1669 + path_put(&old_path);
1673 + error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
1677 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1678 + NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
1681 + kfree(old_buffer);
1686 +int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
1687 + struct path *path, const char *type, unsigned long flags,
1690 + struct file_perms perms = { };
1691 + char *buffer = NULL, *dev_buffer = NULL;
1692 + const char *name = NULL, *dev_name = NULL, *info = NULL;
1696 + dev_name = orig_dev_name;
1699 + struct file_system_type *fstype = get_fs_type(type);
1703 + binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
1704 + requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
1705 + put_filesystem(fstype);
1707 + if (requires_dev) {
1708 + struct path dev_path;
1710 + if (!dev_name || !*dev_name) {
1715 + error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
1719 + error = aa_path_name(&dev_path,
1720 + path_flags(profile, &dev_path),
1721 + &dev_buffer, &dev_name, &info);
1722 + path_put(&dev_path);
1728 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1733 + error = match_mnt(profile, name, dev_name, type, flags, data, binary,
1737 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
1738 + type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1741 + kfree(dev_buffer);
1748 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
1750 + struct file_perms perms = { };
1751 + char *buffer = NULL;
1752 + const char *name, *info = NULL;
1755 + struct path path = { mnt, mnt->mnt_root };
1756 + error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
1761 + if (!error && profile->policy.dfa) {
1762 + unsigned int state;
1763 + state = aa_dfa_match(profile->policy.dfa,
1764 + profile->policy.start[AA_CLASS_MOUNT],
1766 + perms = compute_mnt_perms(profile->policy.dfa, state);
1769 + if (AA_MAY_UMOUNT & ~perms.allow)
1773 + error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
1774 + NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
1780 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1781 + struct path *new_path)
1783 + struct file_perms perms = { };
1784 + struct aa_profile *target = NULL;
1785 + char *old_buffer = NULL, *new_buffer = NULL;
1786 + const char *old_name, *new_name = NULL, *info = NULL;
1789 + error = aa_path_name(old_path, path_flags(profile, old_path),
1790 + &old_buffer, &old_name, &info);
1794 + error = aa_path_name(new_path, path_flags(profile, new_path),
1795 + &new_buffer, &new_name, &info);
1799 + if (profile->policy.dfa) {
1800 + unsigned int state;
1801 + state = aa_dfa_match(profile->policy.dfa,
1802 + profile->policy.start[AA_CLASS_MOUNT],
1804 + state = aa_dfa_null_transition(profile->policy.dfa, state);
1805 + state = aa_dfa_match(profile->policy.dfa, state, old_name);
1806 + perms = compute_mnt_perms(profile->policy.dfa, state);
1809 + if (AA_MAY_PIVOTROOT & perms.allow) {
1810 + if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
1811 + target = x_table_lookup(profile, perms.xindex);
1815 + error = aa_replace_current_profile(target);
1821 + error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
1822 + old_name, NULL, target ? target->base.name : NULL,
1823 + 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
1824 + aa_put_profile(target);
1825 + kfree(old_buffer);
1826 + kfree(new_buffer);