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/.gitignore b/security/apparmor/.gitignore
310 index 4d995ae..d5b291e 100644
311 --- a/security/apparmor/.gitignore
312 +++ b/security/apparmor/.gitignore
315 # Generated include files
321 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
322 index 806bd19..19daa85 100644
323 --- a/security/apparmor/Makefile
324 +++ b/security/apparmor/Makefile
325 @@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
327 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
328 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
329 - resource.o sid.o file.o
330 + resource.o sid.o file.o net.o
332 -clean-files := capability_names.h rlim_names.h
333 +clean-files := capability_names.h rlim_names.h net_names.h
336 # Build a lower case string table of capability names
337 @@ -20,6 +20,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
338 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
341 +# Build a lower case string table of address family names
342 +# Transform lines from
343 +# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
344 +# #define AF_INET 2 /* Internet IP Protocol */
349 +# and build the securityfs entries for the mapping.
350 +# Transforms lines from
351 +# #define AF_INET 2 /* Internet IP Protocol */
353 +# #define AA_FS_AF_MASK "local inet"
354 +quiet_cmd_make-af = GEN $@
355 +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
356 + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
357 + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
359 + echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
360 + sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
361 + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
363 +# Build a lower case string table of sock type names
364 +# Transform lines from
368 +quiet_cmd_make-sock = GEN $@
369 +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
370 + sed $^ >>$@ -r -n \
371 + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
374 # Build a lower case string table of rlimit names.
375 # Transforms lines from
376 @@ -56,6 +88,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
377 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
379 $(obj)/capability.o : $(obj)/capability_names.h
380 +$(obj)/net.o : $(obj)/net_names.h
381 $(obj)/resource.o : $(obj)/rlim_names.h
382 $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
384 @@ -63,3 +96,8 @@ $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
385 $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \
387 $(call cmd,make-rlim)
388 +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
389 + $(srctree)/include/linux/net.h \
391 + $(call cmd,make-af)
392 + $(call cmd,make-sock)
393 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
394 index 42b7c9f..114fb23 100644
395 --- a/security/apparmor/apparmorfs.c
396 +++ b/security/apparmor/apparmorfs.c
397 @@ -429,6 +429,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
398 static struct aa_fs_entry aa_fs_entry_features[] = {
399 AA_FS_DIR("domain", aa_fs_entry_domain),
400 AA_FS_DIR("file", aa_fs_entry_file),
401 + AA_FS_DIR("network", aa_fs_entry_network),
402 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
403 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
405 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
406 index 4b7e189..17734f9 100644
407 --- a/security/apparmor/include/audit.h
408 +++ b/security/apparmor/include/audit.h
409 @@ -127,6 +127,10 @@ struct apparmor_audit_data {
414 + int type, protocol;
420 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
422 index 0000000..cb8a121
424 +++ b/security/apparmor/include/net.h
427 + * AppArmor security module
429 + * This file contains AppArmor network mediation definitions.
431 + * Copyright (C) 1998-2008 Novell/SUSE
432 + * Copyright 2009-2012 Canonical Ltd.
434 + * This program is free software; you can redistribute it and/or
435 + * modify it under the terms of the GNU General Public License as
436 + * published by the Free Software Foundation, version 2 of the
443 +#include <net/sock.h>
445 +#include "apparmorfs.h"
447 +/* struct aa_net - network confinement data
448 + * @allowed: basic network families permissions
449 + * @audit_network: which network permissions to force audit
450 + * @quiet_network: which network permissions to quiet rejects
458 +extern struct aa_fs_entry aa_fs_entry_network[];
460 +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
461 + int type, int protocol, struct sock *sk);
462 +extern int aa_revalidate_sk(int op, struct sock *sk);
464 +static inline void aa_free_net_rules(struct aa_net *new)
469 +#endif /* __AA_NET_H */
470 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
471 index bda4569..eb13a73 100644
472 --- a/security/apparmor/include/policy.h
473 +++ b/security/apparmor/include/policy.h
475 #include "capability.h"
479 #include "resource.h"
481 extern const char *const profile_mode_names[];
482 @@ -157,6 +158,7 @@ struct aa_policydb {
483 * @policy: general match rules governing policy
484 * @file: The set of rules governing basic file access and domain transitions
485 * @caps: capabilities for the profile
486 + * @net: network controls for the profile
487 * @rlimits: rlimits for the profile
489 * The AppArmor profile contains the basic confinement data. Each profile
490 @@ -194,6 +196,7 @@ struct aa_profile {
491 struct aa_policydb policy;
492 struct aa_file_rules file;
495 struct aa_rlimit rlimits;
498 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
499 index 8ea39aa..f628734 100644
500 --- a/security/apparmor/lsm.c
501 +++ b/security/apparmor/lsm.c
503 #include "include/context.h"
504 #include "include/file.h"
505 #include "include/ipc.h"
506 +#include "include/net.h"
507 #include "include/path.h"
508 #include "include/policy.h"
509 #include "include/procattr.h"
510 @@ -614,6 +615,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
514 +static int apparmor_socket_create(int family, int type, int protocol, int kern)
516 + struct aa_profile *profile;
522 + profile = __aa_current_profile();
523 + if (!unconfined(profile))
524 + error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
529 +static int apparmor_socket_bind(struct socket *sock,
530 + struct sockaddr *address, int addrlen)
532 + struct sock *sk = sock->sk;
534 + return aa_revalidate_sk(OP_BIND, sk);
537 +static int apparmor_socket_connect(struct socket *sock,
538 + struct sockaddr *address, int addrlen)
540 + struct sock *sk = sock->sk;
542 + return aa_revalidate_sk(OP_CONNECT, sk);
545 +static int apparmor_socket_listen(struct socket *sock, int backlog)
547 + struct sock *sk = sock->sk;
549 + return aa_revalidate_sk(OP_LISTEN, sk);
552 +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
554 + struct sock *sk = sock->sk;
556 + return aa_revalidate_sk(OP_ACCEPT, sk);
559 +static int apparmor_socket_sendmsg(struct socket *sock,
560 + struct msghdr *msg, int size)
562 + struct sock *sk = sock->sk;
564 + return aa_revalidate_sk(OP_SENDMSG, sk);
567 +static int apparmor_socket_recvmsg(struct socket *sock,
568 + struct msghdr *msg, int size, int flags)
570 + struct sock *sk = sock->sk;
572 + return aa_revalidate_sk(OP_RECVMSG, sk);
575 +static int apparmor_socket_getsockname(struct socket *sock)
577 + struct sock *sk = sock->sk;
579 + return aa_revalidate_sk(OP_GETSOCKNAME, sk);
582 +static int apparmor_socket_getpeername(struct socket *sock)
584 + struct sock *sk = sock->sk;
586 + return aa_revalidate_sk(OP_GETPEERNAME, sk);
589 +static int apparmor_socket_getsockopt(struct socket *sock, int level,
592 + struct sock *sk = sock->sk;
594 + return aa_revalidate_sk(OP_GETSOCKOPT, sk);
597 +static int apparmor_socket_setsockopt(struct socket *sock, int level,
600 + struct sock *sk = sock->sk;
602 + return aa_revalidate_sk(OP_SETSOCKOPT, sk);
605 +static int apparmor_socket_shutdown(struct socket *sock, int how)
607 + struct sock *sk = sock->sk;
609 + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
612 static struct security_operations apparmor_ops = {
615 @@ -646,6 +745,19 @@ static struct security_operations apparmor_ops = {
616 .getprocattr = apparmor_getprocattr,
617 .setprocattr = apparmor_setprocattr,
619 + .socket_create = apparmor_socket_create,
620 + .socket_bind = apparmor_socket_bind,
621 + .socket_connect = apparmor_socket_connect,
622 + .socket_listen = apparmor_socket_listen,
623 + .socket_accept = apparmor_socket_accept,
624 + .socket_sendmsg = apparmor_socket_sendmsg,
625 + .socket_recvmsg = apparmor_socket_recvmsg,
626 + .socket_getsockname = apparmor_socket_getsockname,
627 + .socket_getpeername = apparmor_socket_getpeername,
628 + .socket_getsockopt = apparmor_socket_getsockopt,
629 + .socket_setsockopt = apparmor_socket_setsockopt,
630 + .socket_shutdown = apparmor_socket_shutdown,
632 .cred_alloc_blank = apparmor_cred_alloc_blank,
633 .cred_free = apparmor_cred_free,
634 .cred_prepare = apparmor_cred_prepare,
635 diff --git a/security/apparmor/net.c b/security/apparmor/net.c
637 index 0000000..003dd18
639 +++ b/security/apparmor/net.c
642 + * AppArmor security module
644 + * This file contains AppArmor network mediation
646 + * Copyright (C) 1998-2008 Novell/SUSE
647 + * Copyright 2009-2012 Canonical Ltd.
649 + * This program is free software; you can redistribute it and/or
650 + * modify it under the terms of the GNU General Public License as
651 + * published by the Free Software Foundation, version 2 of the
655 +#include "include/apparmor.h"
656 +#include "include/audit.h"
657 +#include "include/context.h"
658 +#include "include/net.h"
659 +#include "include/policy.h"
661 +#include "net_names.h"
663 +struct aa_fs_entry aa_fs_entry_network[] = {
664 + AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
668 +/* audit callback for net specific fields */
669 +static void audit_cb(struct audit_buffer *ab, void *va)
671 + struct common_audit_data *sa = va;
673 + audit_log_format(ab, " family=");
674 + if (address_family_names[sa->u.net->family]) {
675 + audit_log_string(ab, address_family_names[sa->u.net->family]);
677 + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
679 + audit_log_format(ab, " sock_type=");
680 + if (sock_type_names[sa->aad->net.type]) {
681 + audit_log_string(ab, sock_type_names[sa->aad->net.type]);
683 + audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
685 + audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
689 + * audit_net - audit network access
690 + * @profile: profile being enforced (NOT NULL)
691 + * @op: operation being checked
692 + * @family: network family
693 + * @type: network type
694 + * @protocol: network protocol
695 + * @sk: socket auditing is being applied to
696 + * @error: error code for failure else 0
698 + * Returns: %0 or sa->error else other errorcode on failure
700 +static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
701 + int protocol, struct sock *sk, int error)
703 + int audit_type = AUDIT_APPARMOR_AUTO;
704 + struct common_audit_data sa;
705 + struct apparmor_audit_data aad = { };
706 + struct lsm_network_audit net = { };
708 + sa.type = LSM_AUDIT_DATA_NET;
710 + sa.type = LSM_AUDIT_DATA_NONE;
712 + /* todo fill in socket addr info */
716 + sa.u.net->family = family;
718 + sa.aad->net.type = type;
719 + sa.aad->net.protocol = protocol;
720 + sa.aad->error = error;
722 + if (likely(!sa.aad->error)) {
723 + u16 audit_mask = profile->net.audit[sa.u.net->family];
724 + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
725 + !(1 << sa.aad->net.type & audit_mask)))
727 + audit_type = AUDIT_APPARMOR_AUDIT;
729 + u16 quiet_mask = profile->net.quiet[sa.u.net->family];
731 + u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
733 + if (denied & kill_mask)
734 + audit_type = AUDIT_APPARMOR_KILL;
736 + if ((denied & quiet_mask) &&
737 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
738 + AUDIT_MODE(profile) != AUDIT_ALL)
739 + return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
742 + return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
746 + * aa_net_perm - very course network access check
747 + * @op: operation being checked
748 + * @profile: profile being enforced (NOT NULL)
749 + * @family: network family
750 + * @type: network type
751 + * @protocol: network protocol
753 + * Returns: %0 else error if permission denied
755 +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
756 + int protocol, struct sock *sk)
761 + if ((family < 0) || (family >= AF_MAX))
764 + if ((type < 0) || (type >= SOCK_MAX))
767 + /* unix domain and netlink sockets are handled by ipc */
768 + if (family == AF_UNIX || family == AF_NETLINK)
771 + family_mask = profile->net.allow[family];
773 + error = (family_mask & (1 << type)) ? 0 : -EACCES;
775 + return audit_net(profile, op, family, type, protocol, sk, error);
779 + * aa_revalidate_sk - Revalidate access to a sock
780 + * @op: operation being checked
781 + * @sk: sock being revalidated (NOT NULL)
783 + * Returns: %0 else error if permission denied
785 +int aa_revalidate_sk(int op, struct sock *sk)
787 + struct aa_profile *profile;
790 + /* aa_revalidate_sk should not be called from interrupt context
791 + * don't mediate these calls as they are not task related
793 + if (in_interrupt())
796 + profile = __aa_current_profile();
797 + if (!unconfined(profile))
798 + error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
799 + sk->sk_protocol, sk);
803 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
804 index cf5fd22..27c8161 100644
805 --- a/security/apparmor/policy.c
806 +++ b/security/apparmor/policy.c
807 @@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile)
809 aa_free_file_rules(&profile->file);
810 aa_free_cap_rules(&profile->caps);
811 + aa_free_net_rules(&profile->net);
812 aa_free_rlimit_rules(&profile->rlimits);
814 aa_free_sid(profile->sid);
815 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
816 index 329b1fd..1b90dfa 100644
817 --- a/security/apparmor/policy_unpack.c
818 +++ b/security/apparmor/policy_unpack.c
819 @@ -193,6 +193,19 @@ fail:
823 +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
825 + if (unpack_nameX(e, AA_U16, name)) {
826 + if (!inbounds(e, sizeof(u16)))
829 + *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
830 + e->pos += sizeof(u16);
836 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
838 if (unpack_nameX(e, AA_U32, name)) {
839 @@ -471,6 +484,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
841 struct aa_profile *profile = NULL;
842 const char *name = NULL;
844 int i, error = -EPROTO;
847 @@ -564,6 +578,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
848 if (!unpack_rlimits(e, profile))
851 + size = unpack_array(e, "net_allowed_af");
854 + for (i = 0; i < size; i++) {
855 + /* discard extraneous rules that this kernel will
860 + if (!unpack_u16(e, &tmp, NULL) ||
861 + !unpack_u16(e, &tmp, NULL) ||
862 + !unpack_u16(e, &tmp, NULL))
866 + if (!unpack_u16(e, &profile->net.allow[i], NULL))
868 + if (!unpack_u16(e, &profile->net.audit[i], NULL))
870 + if (!unpack_u16(e, &profile->net.quiet[i], NULL))
873 + if (!unpack_nameX(e, AA_ARRAYEND, NULL))
877 + * allow unix domain and netlink sockets they are handled
880 + profile->net.allow[AF_UNIX] = 0xffff;
881 + profile->net.allow[AF_NETLINK] = 0xffff;
883 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
884 /* generic policy dfa - optional and may be NULL */
885 profile->policy.dfa = unpack_dfa(e);
889 From 888a3d71db1ffd3a19d9f621b07e60c4ab9e1c44 Mon Sep 17 00:00:00 2001
890 From: John Johansen <john.johansen@canonical.com>
891 Date: Wed, 16 May 2012 10:58:05 -0700
892 Subject: [PATCH] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
894 Add the ability for apparmor to do mediation of mount operations. Mount
895 rules require an updated apparmor_parser (2.8 series) for policy compilation.
897 The basic form of the rules are.
899 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
900 [audit] [deny] remount [conds]* [path],
901 [audit] [deny] umount [conds]* [path],
902 [audit] [deny] pivotroot [oldroot=<value>] <path>
904 remount is just a short cut for mount options=remount
910 Example mount commands
911 mount, # allow all mounts, but not umount or pivotroot
913 mount fstype=procfs, # allow mounting procfs anywhere
915 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
917 mount /dev/sda -> /mnt,
919 mount /dev/sd** -> /mnt/**,
921 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
927 See the apparmor userspace for full documentation
929 Signed-off-by: John Johansen <john.johansen@canonical.com>
930 Acked-by: Kees Cook <kees@ubuntu.com>
932 security/apparmor/Makefile | 2 +-
933 security/apparmor/apparmorfs.c | 13 +
934 security/apparmor/audit.c | 4 +
935 security/apparmor/domain.c | 2 +-
936 security/apparmor/include/apparmor.h | 3 +-
937 security/apparmor/include/audit.h | 11 +
938 security/apparmor/include/domain.h | 2 +
939 security/apparmor/include/mount.h | 54 +++
940 security/apparmor/lsm.c | 59 ++++
941 security/apparmor/mount.c | 620 ++++++++++++++++++++++++++++++++++
942 10 files changed, 767 insertions(+), 3 deletions(-)
943 create mode 100644 security/apparmor/include/mount.h
944 create mode 100644 security/apparmor/mount.c
946 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
947 index 19daa85..63e0a4c 100644
948 --- a/security/apparmor/Makefile
949 +++ b/security/apparmor/Makefile
950 @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
952 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
953 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
954 - resource.o sid.o file.o net.o
955 + resource.o sid.o file.o net.o mount.o
957 clean-files := capability_names.h rlim_names.h net_names.h
959 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
960 index 114fb23..ee77ec9 100644
961 --- a/security/apparmor/apparmorfs.c
962 +++ b/security/apparmor/apparmorfs.c
963 @@ -426,10 +426,23 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
967 +static struct aa_fs_entry aa_fs_entry_mount[] = {
968 + AA_FS_FILE_STRING("mask", "mount umount"),
972 +static struct aa_fs_entry aa_fs_entry_namespaces[] = {
973 + AA_FS_FILE_BOOLEAN("profile", 1),
974 + AA_FS_FILE_BOOLEAN("pivot_root", 1),
978 static struct aa_fs_entry aa_fs_entry_features[] = {
979 AA_FS_DIR("domain", aa_fs_entry_domain),
980 AA_FS_DIR("file", aa_fs_entry_file),
981 AA_FS_DIR("network", aa_fs_entry_network),
982 + AA_FS_DIR("mount", aa_fs_entry_mount),
983 + AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
984 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
985 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
987 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
988 index 3ae28db..e267963 100644
989 --- a/security/apparmor/audit.c
990 +++ b/security/apparmor/audit.c
991 @@ -44,6 +44,10 @@ const char *const op_table[] = {
1002 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
1003 index b81ea10..afa8671 100644
1004 --- a/security/apparmor/domain.c
1005 +++ b/security/apparmor/domain.c
1006 @@ -242,7 +242,7 @@ static const char *next_name(int xtype, const char *name)
1008 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
1010 -static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
1011 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
1013 struct aa_profile *new_profile = NULL;
1014 struct aa_namespace *ns = profile->ns;
1015 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
1016 index 40aedd9..e243d96 100644
1017 --- a/security/apparmor/include/apparmor.h
1018 +++ b/security/apparmor/include/apparmor.h
1020 #define AA_CLASS_NET 4
1021 #define AA_CLASS_RLIMITS 5
1022 #define AA_CLASS_DOMAIN 6
1023 +#define AA_CLASS_MOUNT 7
1025 -#define AA_CLASS_LAST AA_CLASS_DOMAIN
1026 +#define AA_CLASS_LAST AA_CLASS_MOUNT
1028 /* Control parameters settable through module/boot flags */
1029 extern enum audit_mode aa_g_audit;
1030 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
1031 index 17734f9..66a738c 100644
1032 --- a/security/apparmor/include/audit.h
1033 +++ b/security/apparmor/include/audit.h
1034 @@ -73,6 +73,10 @@ enum aa_ops {
1045 @@ -122,6 +126,13 @@ struct apparmor_audit_data {
1049 + const char *src_name;
1051 + const char *trans;
1053 + unsigned long flags;
1059 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
1060 index de04464..a3f70c5 100644
1061 --- a/security/apparmor/include/domain.h
1062 +++ b/security/apparmor/include/domain.h
1063 @@ -23,6 +23,8 @@ struct aa_domain {
1067 +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
1069 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
1070 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
1071 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
1072 diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
1073 new file mode 100644
1074 index 0000000..bc17a53
1076 +++ b/security/apparmor/include/mount.h
1079 + * AppArmor security module
1081 + * This file contains AppArmor file mediation function definitions.
1083 + * Copyright 2012 Canonical Ltd.
1085 + * This program is free software; you can redistribute it and/or
1086 + * modify it under the terms of the GNU General Public License as
1087 + * published by the Free Software Foundation, version 2 of the
1091 +#ifndef __AA_MOUNT_H
1092 +#define __AA_MOUNT_H
1094 +#include <linux/fs.h>
1095 +#include <linux/path.h>
1097 +#include "domain.h"
1098 +#include "policy.h"
1101 +#define AA_MAY_PIVOTROOT 0x01
1102 +#define AA_MAY_MOUNT 0x02
1103 +#define AA_MAY_UMOUNT 0x04
1104 +#define AA_AUDIT_DATA 0x40
1105 +#define AA_CONT_MATCH 0x40
1107 +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
1109 +int aa_remount(struct aa_profile *profile, struct path *path,
1110 + unsigned long flags, void *data);
1112 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
1113 + const char *old_name, unsigned long flags);
1116 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1117 + unsigned long flags);
1119 +int aa_move_mount(struct aa_profile *profile, struct path *path,
1120 + const char *old_name);
1122 +int aa_new_mount(struct aa_profile *profile, const char *dev_name,
1123 + struct path *path, const char *type, unsigned long flags,
1126 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
1128 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1129 + struct path *new_path);
1131 +#endif /* __AA_MOUNT_H */
1132 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1133 index f628734..65ff9e4 100644
1134 --- a/security/apparmor/lsm.c
1135 +++ b/security/apparmor/lsm.c
1137 #include "include/path.h"
1138 #include "include/policy.h"
1139 #include "include/procattr.h"
1140 +#include "include/mount.h"
1142 /* Flag indicating whether initialization completed */
1143 int apparmor_initialized __initdata;
1144 @@ -504,6 +505,60 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1145 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1148 +static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
1149 + unsigned long flags, void *data)
1151 + struct aa_profile *profile;
1154 + /* Discard magic */
1155 + if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1156 + flags &= ~MS_MGC_MSK;
1158 + flags &= ~AA_MS_IGNORE_MASK;
1160 + profile = __aa_current_profile();
1161 + if (!unconfined(profile)) {
1162 + if (flags & MS_REMOUNT)
1163 + error = aa_remount(profile, path, flags, data);
1164 + else if (flags & MS_BIND)
1165 + error = aa_bind_mount(profile, path, dev_name, flags);
1166 + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
1168 + error = aa_mount_change_type(profile, path, flags);
1169 + else if (flags & MS_MOVE)
1170 + error = aa_move_mount(profile, path, dev_name);
1172 + error = aa_new_mount(profile, dev_name, path, type,
1178 +static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
1180 + struct aa_profile *profile;
1183 + profile = __aa_current_profile();
1184 + if (!unconfined(profile))
1185 + error = aa_umount(profile, mnt, flags);
1190 +static int apparmor_sb_pivotroot(struct path *old_path, struct path *new_path)
1192 + struct aa_profile *profile;
1195 + profile = __aa_current_profile();
1196 + if (!unconfined(profile))
1197 + error = aa_pivotroot(profile, old_path, new_path);
1202 static int apparmor_getprocattr(struct task_struct *task, char *name,
1205 @@ -721,6 +776,10 @@ static struct security_operations apparmor_ops = {
1206 .capget = apparmor_capget,
1207 .capable = apparmor_capable,
1209 + .sb_mount = apparmor_sb_mount,
1210 + .sb_umount = apparmor_sb_umount,
1211 + .sb_pivotroot = apparmor_sb_pivotroot,
1213 .path_link = apparmor_path_link,
1214 .path_unlink = apparmor_path_unlink,
1215 .path_symlink = apparmor_path_symlink,
1216 diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
1217 new file mode 100644
1218 index 0000000..478aa4d
1220 +++ b/security/apparmor/mount.c
1223 + * AppArmor security module
1225 + * This file contains AppArmor mediation of files
1227 + * Copyright (C) 1998-2008 Novell/SUSE
1228 + * Copyright 2009-2012 Canonical Ltd.
1230 + * This program is free software; you can redistribute it and/or
1231 + * modify it under the terms of the GNU General Public License as
1232 + * published by the Free Software Foundation, version 2 of the
1236 +#include <linux/fs.h>
1237 +#include <linux/mount.h>
1238 +#include <linux/namei.h>
1240 +#include "include/apparmor.h"
1241 +#include "include/audit.h"
1242 +#include "include/context.h"
1243 +#include "include/domain.h"
1244 +#include "include/file.h"
1245 +#include "include/match.h"
1246 +#include "include/mount.h"
1247 +#include "include/path.h"
1248 +#include "include/policy.h"
1251 +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
1253 + if (flags & MS_RDONLY)
1254 + audit_log_format(ab, "ro");
1256 + audit_log_format(ab, "rw");
1257 + if (flags & MS_NOSUID)
1258 + audit_log_format(ab, ", nosuid");
1259 + if (flags & MS_NODEV)
1260 + audit_log_format(ab, ", nodev");
1261 + if (flags & MS_NOEXEC)
1262 + audit_log_format(ab, ", noexec");
1263 + if (flags & MS_SYNCHRONOUS)
1264 + audit_log_format(ab, ", sync");
1265 + if (flags & MS_REMOUNT)
1266 + audit_log_format(ab, ", remount");
1267 + if (flags & MS_MANDLOCK)
1268 + audit_log_format(ab, ", mand");
1269 + if (flags & MS_DIRSYNC)
1270 + audit_log_format(ab, ", dirsync");
1271 + if (flags & MS_NOATIME)
1272 + audit_log_format(ab, ", noatime");
1273 + if (flags & MS_NODIRATIME)
1274 + audit_log_format(ab, ", nodiratime");
1275 + if (flags & MS_BIND)
1276 + audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
1277 + if (flags & MS_MOVE)
1278 + audit_log_format(ab, ", move");
1279 + if (flags & MS_SILENT)
1280 + audit_log_format(ab, ", silent");
1281 + if (flags & MS_POSIXACL)
1282 + audit_log_format(ab, ", acl");
1283 + if (flags & MS_UNBINDABLE)
1284 + audit_log_format(ab, flags & MS_REC ? ", runbindable" :
1286 + if (flags & MS_PRIVATE)
1287 + audit_log_format(ab, flags & MS_REC ? ", rprivate" :
1289 + if (flags & MS_SLAVE)
1290 + audit_log_format(ab, flags & MS_REC ? ", rslave" :
1292 + if (flags & MS_SHARED)
1293 + audit_log_format(ab, flags & MS_REC ? ", rshared" :
1295 + if (flags & MS_RELATIME)
1296 + audit_log_format(ab, ", relatime");
1297 + if (flags & MS_I_VERSION)
1298 + audit_log_format(ab, ", iversion");
1299 + if (flags & MS_STRICTATIME)
1300 + audit_log_format(ab, ", strictatime");
1301 + if (flags & MS_NOUSER)
1302 + audit_log_format(ab, ", nouser");
1306 + * audit_cb - call back for mount specific audit fields
1307 + * @ab: audit_buffer (NOT NULL)
1308 + * @va: audit struct to audit values of (NOT NULL)
1310 +static void audit_cb(struct audit_buffer *ab, void *va)
1312 + struct common_audit_data *sa = va;
1314 + if (sa->aad->mnt.type) {
1315 + audit_log_format(ab, " fstype=");
1316 + audit_log_untrustedstring(ab, sa->aad->mnt.type);
1318 + if (sa->aad->mnt.src_name) {
1319 + audit_log_format(ab, " srcname=");
1320 + audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
1322 + if (sa->aad->mnt.trans) {
1323 + audit_log_format(ab, " trans=");
1324 + audit_log_untrustedstring(ab, sa->aad->mnt.trans);
1326 + if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
1327 + audit_log_format(ab, " flags=\"");
1328 + audit_mnt_flags(ab, sa->aad->mnt.flags);
1329 + audit_log_format(ab, "\"");
1331 + if (sa->aad->mnt.data) {
1332 + audit_log_format(ab, " options=");
1333 + audit_log_untrustedstring(ab, sa->aad->mnt.data);
1338 + * audit_mount - handle the auditing of mount operations
1339 + * @profile: the profile being enforced (NOT NULL)
1340 + * @gfp: allocation flags
1341 + * @op: operation being mediated (NOT NULL)
1342 + * @name: name of object being mediated (MAYBE NULL)
1343 + * @src_name: src_name of object being mediated (MAYBE_NULL)
1344 + * @type: type of filesystem (MAYBE_NULL)
1345 + * @trans: name of trans (MAYBE NULL)
1346 + * @flags: filesystem idependent mount flags
1347 + * @data: filesystem mount flags
1348 + * @request: permissions requested
1349 + * @perms: the permissions computed for the request (NOT NULL)
1350 + * @info: extra information message (MAYBE NULL)
1351 + * @error: 0 if operation allowed else failure error code
1353 + * Returns: %0 or error on failure
1355 +static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
1356 + const char *name, const char *src_name,
1357 + const char *type, const char *trans,
1358 + unsigned long flags, const void *data, u32 request,
1359 + struct file_perms *perms, const char *info, int error)
1361 + int audit_type = AUDIT_APPARMOR_AUTO;
1362 + struct common_audit_data sa = { };
1363 + struct apparmor_audit_data aad = { };
1365 + if (likely(!error)) {
1366 + u32 mask = perms->audit;
1368 + if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
1371 + /* mask off perms that are not being force audited */
1374 + if (likely(!request))
1376 + audit_type = AUDIT_APPARMOR_AUDIT;
1378 + /* only report permissions that were denied */
1379 + request = request & ~perms->allow;
1381 + if (request & perms->kill)
1382 + audit_type = AUDIT_APPARMOR_KILL;
1384 + /* quiet known rejects, assumes quiet and kill do not overlap */
1385 + if ((request & perms->quiet) &&
1386 + AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1387 + AUDIT_MODE(profile) != AUDIT_ALL)
1388 + request &= ~perms->quiet;
1391 + return COMPLAIN_MODE(profile) ?
1392 + complain_error(error) : error;
1395 + sa.type = LSM_AUDIT_DATA_NONE;
1398 + sa.aad->name = name;
1399 + sa.aad->mnt.src_name = src_name;
1400 + sa.aad->mnt.type = type;
1401 + sa.aad->mnt.trans = trans;
1402 + sa.aad->mnt.flags = flags;
1403 + if (data && (perms->audit & AA_AUDIT_DATA))
1404 + sa.aad->mnt.data = data;
1405 + sa.aad->info = info;
1406 + sa.aad->error = error;
1408 + return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
1412 + * match_mnt_flags - Do an ordered match on mount flags
1413 + * @dfa: dfa to match against
1414 + * @state: state to start in
1415 + * @flags: mount flags to match against
1417 + * Mount flags are encoded as an ordered match. This is done instead of
1418 + * checking against a simple bitmask, to allow for logical operations
1421 + * Returns: next state after flags match
1423 +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
1424 + unsigned long flags)
1428 + for (i = 0; i <= 31 ; ++i) {
1429 + if ((1 << i) & flags)
1430 + state = aa_dfa_next(dfa, state, i + 1);
1437 + * compute_mnt_perms - compute mount permission associated with @state
1438 + * @dfa: dfa to match against (NOT NULL)
1439 + * @state: state match finished in
1441 + * Returns: mount permissions
1443 +static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
1444 + unsigned int state)
1446 + struct file_perms perms;
1449 + perms.allow = dfa_user_allow(dfa, state);
1450 + perms.audit = dfa_user_audit(dfa, state);
1451 + perms.quiet = dfa_user_quiet(dfa, state);
1452 + perms.xindex = dfa_user_xindex(dfa, state);
1457 +static const char const *mnt_info_table[] = {
1458 + "match succeeded",
1459 + "failed mntpnt match",
1460 + "failed srcname match",
1461 + "failed type match",
1462 + "failed flags match",
1463 + "failed data match"
1467 + * Returns 0 on success else element that match failed in, this is the
1468 + * index into the mnt_info_table above
1470 +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
1471 + const char *mntpnt, const char *devname,
1472 + const char *type, unsigned long flags,
1473 + void *data, bool binary, struct file_perms *perms)
1475 + unsigned int state;
1477 + state = aa_dfa_match(dfa, start, mntpnt);
1478 + state = aa_dfa_null_transition(dfa, state);
1483 + state = aa_dfa_match(dfa, state, devname);
1484 + state = aa_dfa_null_transition(dfa, state);
1489 + state = aa_dfa_match(dfa, state, type);
1490 + state = aa_dfa_null_transition(dfa, state);
1494 + state = match_mnt_flags(dfa, state, flags);
1497 + *perms = compute_mnt_perms(dfa, state);
1498 + if (perms->allow & AA_MAY_MOUNT)
1501 + /* only match data if not binary and the DFA flags data is expected */
1502 + if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
1503 + state = aa_dfa_null_transition(dfa, state);
1507 + state = aa_dfa_match(dfa, state, data);
1510 + *perms = compute_mnt_perms(dfa, state);
1511 + if (perms->allow & AA_MAY_MOUNT)
1515 + /* failed at end of flags match */
1520 + * match_mnt - handle path matching for mount
1521 + * @profile: the confining profile
1522 + * @mntpnt: string for the mntpnt (NOT NULL)
1523 + * @devname: string for the devname/src_name (MAYBE NULL)
1524 + * @type: string for the dev type (MAYBE NULL)
1525 + * @flags: mount flags to match
1526 + * @data: fs mount data (MAYBE NULL)
1527 + * @binary: whether @data is binary
1528 + * @perms: Returns: permission found by the match
1529 + * @info: Returns: infomation string about the match for logging
1531 + * Returns: 0 on success else error
1533 +static int match_mnt(struct aa_profile *profile, const char *mntpnt,
1534 + const char *devname, const char *type,
1535 + unsigned long flags, void *data, bool binary,
1536 + struct file_perms *perms, const char **info)
1540 + if (!profile->policy.dfa)
1543 + pos = do_match_mnt(profile->policy.dfa,
1544 + profile->policy.start[AA_CLASS_MOUNT],
1545 + mntpnt, devname, type, flags, data, binary, perms);
1547 + *info = mnt_info_table[pos];
1554 +static int path_flags(struct aa_profile *profile, struct path *path)
1556 + return profile->path_flags |
1557 + S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
1560 +int aa_remount(struct aa_profile *profile, struct path *path,
1561 + unsigned long flags, void *data)
1563 + struct file_perms perms = { };
1564 + const char *name, *info = NULL;
1565 + char *buffer = NULL;
1566 + int binary, error;
1568 + binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
1570 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1575 + error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
1579 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1580 + NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1587 +int aa_bind_mount(struct aa_profile *profile, struct path *path,
1588 + const char *dev_name, unsigned long flags)
1590 + struct file_perms perms = { };
1591 + char *buffer = NULL, *old_buffer = NULL;
1592 + const char *name, *old_name = NULL, *info = NULL;
1593 + struct path old_path;
1596 + if (!dev_name || !*dev_name)
1599 + flags &= MS_REC | MS_BIND;
1601 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1606 + error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1610 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1611 + &old_buffer, &old_name, &info);
1612 + path_put(&old_path);
1616 + error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
1620 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1621 + NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
1624 + kfree(old_buffer);
1629 +int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1630 + unsigned long flags)
1632 + struct file_perms perms = { };
1633 + char *buffer = NULL;
1634 + const char *name, *info = NULL;
1637 + /* These are the flags allowed by do_change_type() */
1638 + flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
1641 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1646 + error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
1650 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1651 + NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
1658 +int aa_move_mount(struct aa_profile *profile, struct path *path,
1659 + const char *orig_name)
1661 + struct file_perms perms = { };
1662 + char *buffer = NULL, *old_buffer = NULL;
1663 + const char *name, *old_name = NULL, *info = NULL;
1664 + struct path old_path;
1667 + if (!orig_name || !*orig_name)
1670 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1675 + error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
1679 + error = aa_path_name(&old_path, path_flags(profile, &old_path),
1680 + &old_buffer, &old_name, &info);
1681 + path_put(&old_path);
1685 + error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
1689 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1690 + NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
1693 + kfree(old_buffer);
1698 +int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
1699 + struct path *path, const char *type, unsigned long flags,
1702 + struct file_perms perms = { };
1703 + char *buffer = NULL, *dev_buffer = NULL;
1704 + const char *name = NULL, *dev_name = NULL, *info = NULL;
1708 + dev_name = orig_dev_name;
1711 + struct file_system_type *fstype = get_fs_type(type);
1715 + binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
1716 + requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
1717 + put_filesystem(fstype);
1719 + if (requires_dev) {
1720 + struct path dev_path;
1722 + if (!dev_name || !*dev_name) {
1727 + error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
1731 + error = aa_path_name(&dev_path,
1732 + path_flags(profile, &dev_path),
1733 + &dev_buffer, &dev_name, &info);
1734 + path_put(&dev_path);
1740 + error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1745 + error = match_mnt(profile, name, dev_name, type, flags, data, binary,
1749 + error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
1750 + type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1753 + kfree(dev_buffer);
1760 +int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
1762 + struct file_perms perms = { };
1763 + char *buffer = NULL;
1764 + const char *name, *info = NULL;
1767 + struct path path = { mnt, mnt->mnt_root };
1768 + error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
1773 + if (!error && profile->policy.dfa) {
1774 + unsigned int state;
1775 + state = aa_dfa_match(profile->policy.dfa,
1776 + profile->policy.start[AA_CLASS_MOUNT],
1778 + perms = compute_mnt_perms(profile->policy.dfa, state);
1781 + if (AA_MAY_UMOUNT & ~perms.allow)
1785 + error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
1786 + NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
1792 +int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1793 + struct path *new_path)
1795 + struct file_perms perms = { };
1796 + struct aa_profile *target = NULL;
1797 + char *old_buffer = NULL, *new_buffer = NULL;
1798 + const char *old_name, *new_name = NULL, *info = NULL;
1801 + error = aa_path_name(old_path, path_flags(profile, old_path),
1802 + &old_buffer, &old_name, &info);
1806 + error = aa_path_name(new_path, path_flags(profile, new_path),
1807 + &new_buffer, &new_name, &info);
1811 + if (profile->policy.dfa) {
1812 + unsigned int state;
1813 + state = aa_dfa_match(profile->policy.dfa,
1814 + profile->policy.start[AA_CLASS_MOUNT],
1816 + state = aa_dfa_null_transition(profile->policy.dfa, state);
1817 + state = aa_dfa_match(profile->policy.dfa, state, old_name);
1818 + perms = compute_mnt_perms(profile->policy.dfa, state);
1821 + if (AA_MAY_PIVOTROOT & perms.allow) {
1822 + if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
1823 + target = x_table_lookup(profile, perms.xindex);
1827 + error = aa_replace_current_profile(target);
1833 + error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
1834 + old_name, NULL, target ? target->base.name : NULL,
1835 + 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
1836 + aa_put_profile(target);
1837 + kfree(old_buffer);
1838 + kfree(new_buffer);