]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-apparmor.patch
- apparmor (2.8) and vserver (2.3.3.4) update
[packages/kernel.git] / kernel-apparmor.patch
CommitLineData
76514441 1From: John Johansen <john.johansen@canonical.com>
1e8b8f9b
AM
2Date: Thu, 22 Jul 2010 09:32:02 +0000 (-0700)
3Subject: UBUNTU: SAUCE: AppArmor: Add profile introspection file to interface
4X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fjj%2Flinux-apparmor.git;a=commitdiff_plain;h=8de755e4dfdbc40bfcaca848ae6b5aeaf0ede0e8
76514441 5
1e8b8f9b
AM
6UBUNTU: SAUCE: AppArmor: Add profile introspection file to interface
7
8Add the dynamic profiles file to the interace, to allow load policy
9introspection.
10
11Signed-off-by: John Johansen <john.johansen@canonical.com>
12Acked-by: Kees Cook <kees@ubuntu.com>
13Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
14---
15
16diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
17index 16c15ec..89bdc62 100644
18--- a/security/apparmor/apparmorfs.c
19+++ b/security/apparmor/apparmorfs.c
20@@ -182,6 +182,232 @@ const struct file_operations aa_fs_seq_file_ops = {
21 .release = single_release,
22 };
23
24+/**
25+ * __next_namespace - find the next namespace to list
26+ * @root: root namespace to stop search at (NOT NULL)
27+ * @ns: current ns position (NOT NULL)
28+ *
29+ * Find the next namespace from @ns under @root and handle all locking needed
30+ * while switching current namespace.
31+ *
32+ * Returns: next namespace or NULL if at last namespace under @root
33+ * NOTE: will not unlock root->lock
34+ */
35+static struct aa_namespace *__next_namespace(struct aa_namespace *root,
36+ struct aa_namespace *ns)
37+{
38+ struct aa_namespace *parent;
39+
40+ /* is next namespace a child */
41+ if (!list_empty(&ns->sub_ns)) {
42+ struct aa_namespace *next;
43+ next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
44+ read_lock(&next->lock);
45+ return next;
46+ }
47+
48+ /* check if the next ns is a sibling, parent, gp, .. */
49+ parent = ns->parent;
50+ while (parent) {
51+ read_unlock(&ns->lock);
52+ list_for_each_entry_continue(ns, &parent->sub_ns, base.list) {
53+ read_lock(&ns->lock);
54+ return ns;
55+ }
56+ if (parent == root)
57+ return NULL;
58+ ns = parent;
59+ parent = parent->parent;
60+ }
61+
62+ return NULL;
63+}
64+
65+/**
66+ * __first_profile - find the first profile in a namespace
67+ * @root: namespace that is root of profiles being displayed (NOT NULL)
68+ * @ns: namespace to start in (NOT NULL)
69+ *
70+ * Returns: unrefcounted profile or NULL if no profile
71+ */
72+static struct aa_profile *__first_profile(struct aa_namespace *root,
73+ struct aa_namespace *ns)
74+{
75+ for ( ; ns; ns = __next_namespace(root, ns)) {
76+ if (!list_empty(&ns->base.profiles))
77+ return list_first_entry(&ns->base.profiles,
78+ struct aa_profile, base.list);
79+ }
80+ return NULL;
81+}
82+
83+/**
84+ * __next_profile - step to the next profile in a profile tree
85+ * @profile: current profile in tree (NOT NULL)
86+ *
87+ * Perform a depth first taversal on the profile tree in a namespace
88+ *
89+ * Returns: next profile or NULL if done
90+ * Requires: profile->ns.lock to be held
91+ */
92+static struct aa_profile *__next_profile(struct aa_profile *p)
93+{
94+ struct aa_profile *parent;
95+ struct aa_namespace *ns = p->ns;
96+
97+ /* is next profile a child */
98+ if (!list_empty(&p->base.profiles))
99+ return list_first_entry(&p->base.profiles, typeof(*p),
100+ base.list);
101+
102+ /* is next profile a sibling, parent sibling, gp, subling, .. */
103+ parent = p->parent;
104+ while (parent) {
105+ list_for_each_entry_continue(p, &parent->base.profiles,
106+ base.list)
107+ return p;
108+ p = parent;
109+ parent = parent->parent;
110+ }
111+
112+ /* is next another profile in the namespace */
113+ list_for_each_entry_continue(p, &ns->base.profiles, base.list)
114+ return p;
115+
116+ return NULL;
117+}
118+
119+/**
120+ * next_profile - step to the next profile in where ever it may be
121+ * @root: root namespace (NOT NULL)
122+ * @profile: current profile (NOT NULL)
123+ *
124+ * Returns: next profile or NULL if there isn't one
125+ */
126+static struct aa_profile *next_profile(struct aa_namespace *root,
127+ struct aa_profile *profile)
128+{
129+ struct aa_profile *next = __next_profile(profile);
130+ if (next)
131+ return next;
132+
133+ /* finished all profiles in namespace move to next namespace */
134+ return __first_profile(root, __next_namespace(root, profile->ns));
135+}
136+
137+/**
138+ * p_start - start a depth first traversal of profile tree
139+ * @f: seq_file to fill
140+ * @pos: current position
141+ *
142+ * Returns: first profile under current namespace or NULL if none found
143+ *
144+ * acquires first ns->lock
145+ */
146+static void *p_start(struct seq_file *f, loff_t *pos)
147+ __acquires(root->lock)
148+{
149+ struct aa_profile *profile = NULL;
150+ struct aa_namespace *root = aa_current_profile()->ns;
151+ loff_t l = *pos;
152+ f->private = aa_get_namespace(root);
153+
154+
155+ /* find the first profile */
156+ read_lock(&root->lock);
157+ profile = __first_profile(root, root);
158+
159+ /* skip to position */
160+ for (; profile && l > 0; l--)
161+ profile = next_profile(root, profile);
162+
163+ return profile;
164+}
165+
166+/**
167+ * p_next - read the next profile entry
168+ * @f: seq_file to fill
169+ * @p: profile previously returned
170+ * @pos: current position
171+ *
172+ * Returns: next profile after @p or NULL if none
173+ *
174+ * may acquire/release locks in namespace tree as necessary
175+ */
176+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
177+{
178+ struct aa_profile *profile = p;
179+ struct aa_namespace *root = f->private;
180+ (*pos)++;
181+
182+ return next_profile(root, profile);
183+}
184+
185+/**
186+ * p_stop - stop depth first traversal
187+ * @f: seq_file we are filling
188+ * @p: the last profile writen
189+ *
190+ * Release all locking done by p_start/p_next on namespace tree
191+ */
192+static void p_stop(struct seq_file *f, void *p)
193+ __releases(root->lock)
194+{
195+ struct aa_profile *profile = p;
196+ struct aa_namespace *root = f->private, *ns;
197+
198+ if (profile) {
199+ for (ns = profile->ns; ns && ns != root; ns = ns->parent)
200+ read_unlock(&ns->lock);
201+ }
202+ read_unlock(&root->lock);
203+ aa_put_namespace(root);
204+}
205+
206+/**
207+ * seq_show_profile - show a profile entry
208+ * @f: seq_file to file
209+ * @p: current position (profile) (NOT NULL)
210+ *
211+ * Returns: error on failure
212+ */
213+static int seq_show_profile(struct seq_file *f, void *p)
214+{
215+ struct aa_profile *profile = (struct aa_profile *)p;
216+ struct aa_namespace *root = f->private;
217+
218+ if (profile->ns != root)
219+ seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
220+ seq_printf(f, "%s (%s)\n", profile->base.hname,
221+ COMPLAIN_MODE(profile) ? "complain" : "enforce");
222+
223+ return 0;
224+}
225+
226+static const struct seq_operations aa_fs_profiles_op = {
227+ .start = p_start,
228+ .next = p_next,
229+ .stop = p_stop,
230+ .show = seq_show_profile,
231+};
232+
233+static int profiles_open(struct inode *inode, struct file *file)
234+{
235+ return seq_open(file, &aa_fs_profiles_op);
236+}
237+
238+static int profiles_release(struct inode *inode, struct file *file)
239+{
240+ return seq_release(inode, file);
241+}
242+
243+const struct file_operations aa_fs_profiles_fops = {
244+ .open = profiles_open,
245+ .read = seq_read,
246+ .llseek = seq_lseek,
247+ .release = profiles_release,
248+};
249+
250 /** Base file system setup **/
251
252 static struct aa_fs_entry aa_fs_entry_file[] = {
253@@ -210,6 +436,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = {
254 AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
255 AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
256 AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
257+ AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
258 AA_FS_DIR("features", aa_fs_entry_features),
259 { }
260 };
261From: John Johansen <john.johansen@canonical.com>
262Date: Mon, 4 Oct 2010 22:03:36 +0000 (-0700)
263Subject: UBUNTU: SAUCE: AppArmor: basic networking rules
264X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fjj%2Flinux-apparmor.git;a=commitdiff_plain;h=423e2cb454d75d6185eecd0c1b5cf6ccc2d8482d
265
266UBUNTU: SAUCE: AppArmor: basic networking rules
267
268Base support for network mediation.
76514441
AM
269
270Signed-off-by: John Johansen <john.johansen@canonical.com>
271---
76514441 272
1e8b8f9b
AM
273diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
274index 4d995ae..d5b291e 100644
275--- a/security/apparmor/.gitignore
276+++ b/security/apparmor/.gitignore
277@@ -1,6 +1,6 @@
278 #
279 # Generated include files
280 #
281-af_names.h
282+net_names.h
283 capability_names.h
284 rlim_names.h
fc63ffa9 285diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
1e8b8f9b 286index 806bd19..19daa85 100644
fc63ffa9
AM
287--- a/security/apparmor/Makefile
288+++ b/security/apparmor/Makefile
948a1326 289@@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
ceaf2cfb 290
fc63ffa9
AM
291 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
292 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
293- resource.o sid.o file.o
294+ resource.o sid.o file.o net.o
ceaf2cfb 295
948a1326 296-clean-files := capability_names.h rlim_names.h
1e8b8f9b 297+clean-files := capability_names.h rlim_names.h net_names.h
ceaf2cfb 298
ceaf2cfb 299
948a1326 300 # Build a lower case string table of capability names
1e8b8f9b
AM
301@@ -20,6 +20,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
302 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
948a1326
JR
303 echo "};" >> $@
304
1e8b8f9b 305+# Build a lower case string table of address family names
948a1326 306+# Transform lines from
1e8b8f9b
AM
307+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
308+# #define AF_INET 2 /* Internet IP Protocol */
309+# to
310+# [1] = "local",
311+# [2] = "inet",
312+#
313+# and build the securityfs entries for the mapping.
314+# Transforms lines from
315+# #define AF_INET 2 /* Internet IP Protocol */
948a1326 316+# to
1e8b8f9b 317+# #define AA_FS_AF_MASK "local inet"
ceaf2cfb 318+quiet_cmd_make-af = GEN $@
948a1326 319+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
1e8b8f9b
AM
320+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
321+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
322+ echo "};" >> $@ ;\
323+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
324+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
325+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
326+
327+# Build a lower case string table of sock type names
328+# Transform lines from
329+# SOCK_STREAM = 1,
330+# to
331+# [1] = "stream",
332+quiet_cmd_make-sock = GEN $@
333+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
334+ sed $^ >>$@ -r -n \
335+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
948a1326 336+ echo "};" >> $@
1e8b8f9b
AM
337
338 # Build a lower case string table of rlimit names.
339 # Transforms lines from
340@@ -56,6 +88,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
341 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
342
fc63ffa9 343 $(obj)/capability.o : $(obj)/capability_names.h
1e8b8f9b 344+$(obj)/net.o : $(obj)/net_names.h
fc63ffa9 345 $(obj)/resource.o : $(obj)/rlim_names.h
1e8b8f9b
AM
346 $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
347 $(src)/Makefile
348@@ -63,3 +96,8 @@ $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
349 $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \
350 $(src)/Makefile
948a1326 351 $(call cmd,make-rlim)
1e8b8f9b
AM
352+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
353+ $(srctree)/include/linux/net.h \
354+ $(src)/Makefile
948a1326 355+ $(call cmd,make-af)
1e8b8f9b
AM
356+ $(call cmd,make-sock)
357diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
358index 89bdc62..c66315d 100644
359--- a/security/apparmor/apparmorfs.c
360+++ b/security/apparmor/apparmorfs.c
361@@ -427,6 +427,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
362 static struct aa_fs_entry aa_fs_entry_features[] = {
363 AA_FS_DIR("domain", aa_fs_entry_domain),
364 AA_FS_DIR("file", aa_fs_entry_file),
365+ AA_FS_DIR("network", aa_fs_entry_network),
366 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
367 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
368 { }
369diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
370index 3868b1e..c1ff09c 100644
371--- a/security/apparmor/include/audit.h
372+++ b/security/apparmor/include/audit.h
373@@ -126,6 +126,10 @@ struct apparmor_audit_data {
374 u32 denied;
375 uid_t ouid;
376 } fs;
377+ struct {
378+ int type, protocol;
379+ struct sock *sk;
380+ } net;
381 };
382 };
383
fc63ffa9 384diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
ceaf2cfb 385new file mode 100644
1e8b8f9b 386index 0000000..cb8a121
ceaf2cfb 387--- /dev/null
fc63ffa9 388+++ b/security/apparmor/include/net.h
1e8b8f9b 389@@ -0,0 +1,44 @@
9474138d
AM
390+/*
391+ * AppArmor security module
392+ *
fc63ffa9 393+ * This file contains AppArmor network mediation definitions.
9474138d
AM
394+ *
395+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 396+ * Copyright 2009-2012 Canonical Ltd.
9474138d
AM
397+ *
398+ * This program is free software; you can redistribute it and/or
399+ * modify it under the terms of the GNU General Public License as
400+ * published by the Free Software Foundation, version 2 of the
401+ * License.
402+ */
403+
fc63ffa9
AM
404+#ifndef __AA_NET_H
405+#define __AA_NET_H
2380c486 406+
fc63ffa9 407+#include <net/sock.h>
9474138d 408+
1e8b8f9b
AM
409+#include "apparmorfs.h"
410+
fc63ffa9
AM
411+/* struct aa_net - network confinement data
412+ * @allowed: basic network families permissions
413+ * @audit_network: which network permissions to force audit
414+ * @quiet_network: which network permissions to quiet rejects
415+ */
416+struct aa_net {
417+ u16 allow[AF_MAX];
418+ u16 audit[AF_MAX];
419+ u16 quiet[AF_MAX];
420+};
ceaf2cfb 421+
1e8b8f9b
AM
422+extern struct aa_fs_entry aa_fs_entry_network[];
423+
fc63ffa9
AM
424+extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
425+ int type, int protocol, struct sock *sk);
426+extern int aa_revalidate_sk(int op, struct sock *sk);
ceaf2cfb 427+
fc63ffa9
AM
428+static inline void aa_free_net_rules(struct aa_net *new)
429+{
430+ /* NOP */
ceaf2cfb
AM
431+}
432+
fc63ffa9
AM
433+#endif /* __AA_NET_H */
434diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
1e8b8f9b 435index bda4569..eb13a73 100644
fc63ffa9
AM
436--- a/security/apparmor/include/policy.h
437+++ b/security/apparmor/include/policy.h
438@@ -27,6 +27,7 @@
439 #include "capability.h"
440 #include "domain.h"
441 #include "file.h"
442+#include "net.h"
443 #include "resource.h"
444
1e8b8f9b
AM
445 extern const char *const profile_mode_names[];
446@@ -157,6 +158,7 @@ struct aa_policydb {
447 * @policy: general match rules governing policy
fc63ffa9
AM
448 * @file: The set of rules governing basic file access and domain transitions
449 * @caps: capabilities for the profile
450+ * @net: network controls for the profile
451 * @rlimits: rlimits for the profile
452 *
453 * The AppArmor profile contains the basic confinement data. Each profile
1e8b8f9b
AM
454@@ -194,6 +196,7 @@ struct aa_profile {
455 struct aa_policydb policy;
fc63ffa9
AM
456 struct aa_file_rules file;
457 struct aa_caps caps;
458+ struct aa_net net;
459 struct aa_rlimit rlimits;
460 };
461
462diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1e8b8f9b 463index ad05d39..3cde194 100644
fc63ffa9
AM
464--- a/security/apparmor/lsm.c
465+++ b/security/apparmor/lsm.c
948a1326 466@@ -32,6 +32,7 @@
fc63ffa9
AM
467 #include "include/context.h"
468 #include "include/file.h"
469 #include "include/ipc.h"
470+#include "include/net.h"
471 #include "include/path.h"
472 #include "include/policy.h"
473 #include "include/procattr.h"
1e8b8f9b 474@@ -622,6 +623,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
fc63ffa9
AM
475 return error;
476 }
477
478+static int apparmor_socket_create(int family, int type, int protocol, int kern)
ceaf2cfb 479+{
fc63ffa9
AM
480+ struct aa_profile *profile;
481+ int error = 0;
ceaf2cfb 482+
fc63ffa9
AM
483+ if (kern)
484+ return 0;
ceaf2cfb 485+
fc63ffa9
AM
486+ profile = __aa_current_profile();
487+ if (!unconfined(profile))
488+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
489+ NULL);
490+ return error;
491+}
ceaf2cfb 492+
fc63ffa9
AM
493+static int apparmor_socket_bind(struct socket *sock,
494+ struct sockaddr *address, int addrlen)
9474138d 495+{
fc63ffa9 496+ struct sock *sk = sock->sk;
9474138d 497+
fc63ffa9
AM
498+ return aa_revalidate_sk(OP_BIND, sk);
499+}
ceaf2cfb 500+
fc63ffa9
AM
501+static int apparmor_socket_connect(struct socket *sock,
502+ struct sockaddr *address, int addrlen)
503+{
504+ struct sock *sk = sock->sk;
ceaf2cfb 505+
fc63ffa9 506+ return aa_revalidate_sk(OP_CONNECT, sk);
9474138d
AM
507+}
508+
fc63ffa9 509+static int apparmor_socket_listen(struct socket *sock, int backlog)
9474138d 510+{
fc63ffa9
AM
511+ struct sock *sk = sock->sk;
512+
513+ return aa_revalidate_sk(OP_LISTEN, sk);
9474138d
AM
514+}
515+
fc63ffa9 516+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
9474138d 517+{
fc63ffa9 518+ struct sock *sk = sock->sk;
9474138d 519+
fc63ffa9
AM
520+ return aa_revalidate_sk(OP_ACCEPT, sk);
521+}
9474138d 522+
fc63ffa9
AM
523+static int apparmor_socket_sendmsg(struct socket *sock,
524+ struct msghdr *msg, int size)
76514441 525+{
fc63ffa9 526+ struct sock *sk = sock->sk;
76514441 527+
fc63ffa9 528+ return aa_revalidate_sk(OP_SENDMSG, sk);
76514441
AM
529+}
530+
fc63ffa9
AM
531+static int apparmor_socket_recvmsg(struct socket *sock,
532+ struct msghdr *msg, int size, int flags)
533+{
534+ struct sock *sk = sock->sk;
ceaf2cfb 535+
fc63ffa9
AM
536+ return aa_revalidate_sk(OP_RECVMSG, sk);
537+}
ceaf2cfb 538+
fc63ffa9
AM
539+static int apparmor_socket_getsockname(struct socket *sock)
540+{
541+ struct sock *sk = sock->sk;
ceaf2cfb 542+
fc63ffa9 543+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
9474138d
AM
544+}
545+
fc63ffa9 546+static int apparmor_socket_getpeername(struct socket *sock)
9474138d 547+{
fc63ffa9 548+ struct sock *sk = sock->sk;
9474138d 549+
fc63ffa9
AM
550+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
551+}
ceaf2cfb 552+
fc63ffa9
AM
553+static int apparmor_socket_getsockopt(struct socket *sock, int level,
554+ int optname)
555+{
556+ struct sock *sk = sock->sk;
ceaf2cfb 557+
fc63ffa9
AM
558+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
559+}
ceaf2cfb 560+
fc63ffa9
AM
561+static int apparmor_socket_setsockopt(struct socket *sock, int level,
562+ int optname)
563+{
564+ struct sock *sk = sock->sk;
2380c486 565+
fc63ffa9
AM
566+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
567+}
ceaf2cfb 568+
fc63ffa9
AM
569+static int apparmor_socket_shutdown(struct socket *sock, int how)
570+{
571+ struct sock *sk = sock->sk;
ceaf2cfb 572+
fc63ffa9 573+ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
ceaf2cfb 574+}
948a1326 575+
1e8b8f9b
AM
576 static struct security_operations apparmor_ops = {
577 .name = "apparmor",
578
579@@ -653,6 +752,19 @@ static struct security_operations apparmor_ops = {
5d26c04f
AM
580 .getprocattr = apparmor_getprocattr,
581 .setprocattr = apparmor_setprocattr,
582
583+ .socket_create = apparmor_socket_create,
584+ .socket_bind = apparmor_socket_bind,
585+ .socket_connect = apparmor_socket_connect,
586+ .socket_listen = apparmor_socket_listen,
587+ .socket_accept = apparmor_socket_accept,
588+ .socket_sendmsg = apparmor_socket_sendmsg,
589+ .socket_recvmsg = apparmor_socket_recvmsg,
590+ .socket_getsockname = apparmor_socket_getsockname,
591+ .socket_getpeername = apparmor_socket_getpeername,
592+ .socket_getsockopt = apparmor_socket_getsockopt,
593+ .socket_setsockopt = apparmor_socket_setsockopt,
594+ .socket_shutdown = apparmor_socket_shutdown,
595+
596 .cred_alloc_blank = apparmor_cred_alloc_blank,
597 .cred_free = apparmor_cred_free,
598 .cred_prepare = apparmor_cred_prepare,
fc63ffa9 599diff --git a/security/apparmor/net.c b/security/apparmor/net.c
ceaf2cfb 600new file mode 100644
1e8b8f9b 601index 0000000..084232b
ceaf2cfb 602--- /dev/null
fc63ffa9 603+++ b/security/apparmor/net.c
1e8b8f9b 604@@ -0,0 +1,162 @@
2380c486 605+/*
9474138d
AM
606+ * AppArmor security module
607+ *
fc63ffa9 608+ * This file contains AppArmor network mediation
2380c486 609+ *
9474138d 610+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 611+ * Copyright 2009-2012 Canonical Ltd.
2380c486 612+ *
9474138d
AM
613+ * This program is free software; you can redistribute it and/or
614+ * modify it under the terms of the GNU General Public License as
615+ * published by the Free Software Foundation, version 2 of the
616+ * License.
2380c486
JR
617+ */
618+
9474138d
AM
619+#include "include/apparmor.h"
620+#include "include/audit.h"
621+#include "include/context.h"
fc63ffa9 622+#include "include/net.h"
9474138d 623+#include "include/policy.h"
2380c486 624+
1e8b8f9b
AM
625+#include "net_names.h"
626+
627+struct aa_fs_entry aa_fs_entry_network[] = {
628+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
629+ { }
9474138d
AM
630+};
631+
fc63ffa9 632+/* audit callback for net specific fields */
76514441 633+static void audit_cb(struct audit_buffer *ab, void *va)
9474138d 634+{
76514441 635+ struct common_audit_data *sa = va;
9474138d 636+
fc63ffa9 637+ audit_log_format(ab, " family=");
1e8b8f9b
AM
638+ if (address_family_names[sa->u.net->family]) {
639+ audit_log_string(ab, address_family_names[sa->u.net->family]);
fc63ffa9 640+ } else {
1e8b8f9b 641+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
fc63ffa9 642+ }
fc63ffa9 643+ audit_log_format(ab, " sock_type=");
1e8b8f9b
AM
644+ if (sock_type_names[sa->aad->net.type]) {
645+ audit_log_string(ab, sock_type_names[sa->aad->net.type]);
fc63ffa9 646+ } else {
1e8b8f9b 647+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
fc63ffa9 648+ }
1e8b8f9b 649+ audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
2380c486
JR
650+}
651+
652+/**
fc63ffa9
AM
653+ * audit_net - audit network access
654+ * @profile: profile being enforced (NOT NULL)
655+ * @op: operation being checked
656+ * @family: network family
657+ * @type: network type
658+ * @protocol: network protocol
659+ * @sk: socket auditing is being applied to
660+ * @error: error code for failure else 0
ceaf2cfb 661+ *
fc63ffa9 662+ * Returns: %0 or sa->error else other errorcode on failure
2380c486 663+ */
fc63ffa9
AM
664+static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
665+ int protocol, struct sock *sk, int error)
2380c486 666+{
fc63ffa9
AM
667+ int audit_type = AUDIT_APPARMOR_AUTO;
668+ struct common_audit_data sa;
1e8b8f9b
AM
669+ struct apparmor_audit_data aad = { };
670+ struct lsm_network_audit net = { };
fc63ffa9
AM
671+ if (sk) {
672+ COMMON_AUDIT_DATA_INIT(&sa, NET);
673+ } else {
674+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
2380c486 675+ }
fc63ffa9 676+ /* todo fill in socket addr info */
1e8b8f9b
AM
677+ sa.aad = &aad;
678+ sa.u.net = &net;
679+ sa.aad->op = op,
680+ sa.u.net->family = family;
681+ sa.u.net->sk = sk;
682+ sa.aad->net.type = type;
683+ sa.aad->net.protocol = protocol;
684+ sa.aad->error = error;
685+
686+ if (likely(!sa.aad->error)) {
687+ u16 audit_mask = profile->net.audit[sa.u.net->family];
fc63ffa9 688+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
1e8b8f9b 689+ !(1 << sa.aad->net.type & audit_mask)))
ceaf2cfb 690+ return 0;
fc63ffa9
AM
691+ audit_type = AUDIT_APPARMOR_AUDIT;
692+ } else {
1e8b8f9b 693+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
fc63ffa9 694+ u16 kill_mask = 0;
1e8b8f9b 695+ u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
9474138d 696+
fc63ffa9
AM
697+ if (denied & kill_mask)
698+ audit_type = AUDIT_APPARMOR_KILL;
9474138d 699+
fc63ffa9
AM
700+ if ((denied & quiet_mask) &&
701+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
702+ AUDIT_MODE(profile) != AUDIT_ALL)
1e8b8f9b 703+ return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
9474138d
AM
704+ }
705+
fc63ffa9 706+ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
ceaf2cfb
AM
707+}
708+
2380c486 709+/**
fc63ffa9
AM
710+ * aa_net_perm - very course network access check
711+ * @op: operation being checked
712+ * @profile: profile being enforced (NOT NULL)
713+ * @family: network family
714+ * @type: network type
715+ * @protocol: network protocol
2380c486 716+ *
fc63ffa9 717+ * Returns: %0 else error if permission denied
2380c486 718+ */
fc63ffa9
AM
719+int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
720+ int protocol, struct sock *sk)
2380c486 721+{
fc63ffa9
AM
722+ u16 family_mask;
723+ int error;
ceaf2cfb 724+
fc63ffa9
AM
725+ if ((family < 0) || (family >= AF_MAX))
726+ return -EINVAL;
ceaf2cfb 727+
fc63ffa9
AM
728+ if ((type < 0) || (type >= SOCK_MAX))
729+ return -EINVAL;
76514441 730+
fc63ffa9
AM
731+ /* unix domain and netlink sockets are handled by ipc */
732+ if (family == AF_UNIX || family == AF_NETLINK)
733+ return 0;
76514441 734+
fc63ffa9 735+ family_mask = profile->net.allow[family];
2380c486 736+
fc63ffa9 737+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
ceaf2cfb 738+
fc63ffa9 739+ return audit_net(profile, op, family, type, protocol, sk, error);
2380c486
JR
740+}
741+
76514441 742+/**
fc63ffa9
AM
743+ * aa_revalidate_sk - Revalidate access to a sock
744+ * @op: operation being checked
745+ * @sk: sock being revalidated (NOT NULL)
76514441 746+ *
fc63ffa9 747+ * Returns: %0 else error if permission denied
76514441 748+ */
fc63ffa9 749+int aa_revalidate_sk(int op, struct sock *sk)
2380c486 750+{
fc63ffa9
AM
751+ struct aa_profile *profile;
752+ int error = 0;
2380c486 753+
fc63ffa9
AM
754+ /* aa_revalidate_sk should not be called from interrupt context
755+ * don't mediate these calls as they are not task related
756+ */
757+ if (in_interrupt())
758+ return 0;
ceaf2cfb 759+
fc63ffa9
AM
760+ profile = __aa_current_profile();
761+ if (!unconfined(profile))
762+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
763+ sk->sk_protocol, sk);
2380c486 764+
fc63ffa9 765+ return error;
2380c486 766+}
fc63ffa9 767diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
1e8b8f9b 768index f1f7506..b8100a7 100644
fc63ffa9
AM
769--- a/security/apparmor/policy.c
770+++ b/security/apparmor/policy.c
771@@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile)
772
773 aa_free_file_rules(&profile->file);
774 aa_free_cap_rules(&profile->caps);
775+ aa_free_net_rules(&profile->net);
776 aa_free_rlimit_rules(&profile->rlimits);
777
778 aa_free_sid(profile->sid);
779diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
1e8b8f9b 780index deab7c7..8f8e9c1 100644
fc63ffa9
AM
781--- a/security/apparmor/policy_unpack.c
782+++ b/security/apparmor/policy_unpack.c
1e8b8f9b 783@@ -193,6 +193,19 @@ fail:
fc63ffa9
AM
784 return 0;
785 }
786
787+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
2380c486 788+{
fc63ffa9
AM
789+ if (unpack_nameX(e, AA_U16, name)) {
790+ if (!inbounds(e, sizeof(u16)))
791+ return 0;
792+ if (data)
793+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
794+ e->pos += sizeof(u16);
795+ return 1;
2380c486 796+ }
2380c486
JR
797+ return 0;
798+}
799+
fc63ffa9
AM
800 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
801 {
802 if (unpack_nameX(e, AA_U32, name)) {
1e8b8f9b 803@@ -471,6 +484,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
804 {
805 struct aa_profile *profile = NULL;
806 const char *name = NULL;
2380c486 807+ size_t size = 0;
1e8b8f9b 808 int i, error = -EPROTO;
fc63ffa9
AM
809 kernel_cap_t tmpcap;
810 u32 tmp;
1e8b8f9b 811@@ -564,6 +578,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
812 if (!unpack_rlimits(e, profile))
813 goto fail;
814
ceaf2cfb 815+ size = unpack_array(e, "net_allowed_af");
2380c486 816+ if (size) {
2380c486
JR
817+
818+ for (i = 0; i < size; i++) {
fc63ffa9
AM
819+ /* discard extraneous rules that this kernel will
820+ * never request
821+ */
1efb82ae 822+ if (i >= AF_MAX) {
fc63ffa9
AM
823+ u16 tmp;
824+ if (!unpack_u16(e, &tmp, NULL) ||
825+ !unpack_u16(e, &tmp, NULL) ||
826+ !unpack_u16(e, &tmp, NULL))
827+ goto fail;
828+ continue;
829+ }
76514441 830+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
2380c486 831+ goto fail;
ceaf2cfb 832+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
2380c486 833+ goto fail;
ceaf2cfb 834+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
2380c486
JR
835+ goto fail;
836+ }
ceaf2cfb 837+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
2380c486 838+ goto fail;
2380c486 839+ }
1e8b8f9b
AM
840+ /*
841+ * allow unix domain and netlink sockets they are handled
842+ * by IPC
843+ */
76514441
AM
844+ profile->net.allow[AF_UNIX] = 0xffff;
845+ profile->net.allow[AF_NETLINK] = 0xffff;
2380c486 846+
1e8b8f9b
AM
847 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
848 /* generic policy dfa - optional and may be NULL */
849 profile->policy.dfa = unpack_dfa(e);
fc63ffa9 850From: John Johansen <john.johansen@canonical.com>
1e8b8f9b
AM
851Date: Wed, 16 May 2012 17:58:05 +0000 (-0700)
852Subject: UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
853X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fjj%2Flinux-apparmor.git;a=commitdiff_plain;h=a94d5e11c0484af59e5feebf144cc48c186892ad
854
855UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
856
857Add the ability for apparmor to do mediation of mount operations. Mount
858rules require an updated apparmor_parser (2.8 series) for policy compilation.
859
860The basic form of the rules are.
861
862 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
863 [audit] [deny] remount [conds]* [path],
864 [audit] [deny] umount [conds]* [path],
865 [audit] [deny] pivotroot [oldroot=<value>] <path>
866
867 remount is just a short cut for mount options=remount
868
869 where [conds] can be
870 fstype=<expr>
871 options=<expr>
872
873Example mount commands
874 mount, # allow all mounts, but not umount or pivotroot
875
876 mount fstype=procfs, # allow mounting procfs anywhere
877
878 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
879
880 mount /dev/sda -> /mnt,
881
882 mount /dev/sd** -> /mnt/**,
883
884 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
885
886 umount,
887
888 umount /m*,
889
890See the apparmor userspace for full documentation
fc63ffa9
AM
891
892Signed-off-by: John Johansen <john.johansen@canonical.com>
1e8b8f9b 893Acked-by: Kees Cook <kees@ubuntu.com>
fc63ffa9 894---
fc63ffa9 895
fc63ffa9 896diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
1e8b8f9b 897index 19daa85..63e0a4c 100644
fc63ffa9
AM
898--- a/security/apparmor/Makefile
899+++ b/security/apparmor/Makefile
1e8b8f9b
AM
900@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
901
948a1326 902 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
fc63ffa9 903 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
1e8b8f9b
AM
904- resource.o sid.o file.o net.o
905+ resource.o sid.o file.o net.o mount.o
fc63ffa9 906
1e8b8f9b 907 clean-files := capability_names.h rlim_names.h net_names.h
948a1326 908
1e8b8f9b
AM
909diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
910index c66315d..ff19009 100644
911--- a/security/apparmor/apparmorfs.c
912+++ b/security/apparmor/apparmorfs.c
913@@ -424,10 +424,23 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
914 { }
915 };
916
917+static struct aa_fs_entry aa_fs_entry_mount[] = {
918+ AA_FS_FILE_STRING("mask", "mount umount"),
919+ { }
920+};
921+
922+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
923+ AA_FS_FILE_BOOLEAN("profile", 1),
924+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
925+ { }
926+};
927+
928 static struct aa_fs_entry aa_fs_entry_features[] = {
929 AA_FS_DIR("domain", aa_fs_entry_domain),
930 AA_FS_DIR("file", aa_fs_entry_file),
931 AA_FS_DIR("network", aa_fs_entry_network),
932+ AA_FS_DIR("mount", aa_fs_entry_mount),
933+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
934 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
935 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
936 { }
937diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
938index cc3520d..b9f5ee9 100644
939--- a/security/apparmor/audit.c
940+++ b/security/apparmor/audit.c
941@@ -44,6 +44,10 @@ const char *const op_table[] = {
942 "file_mmap",
943 "file_mprotect",
944
945+ "pivotroot",
946+ "mount",
947+ "umount",
948+
949 "create",
950 "post_create",
951 "bind",
952diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
953index 6327685..dfdc47b 100644
954--- a/security/apparmor/domain.c
955+++ b/security/apparmor/domain.c
956@@ -242,7 +242,7 @@ static const char *next_name(int xtype, const char *name)
957 *
958 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
959 */
960-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
961+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
962 {
963 struct aa_profile *new_profile = NULL;
964 struct aa_namespace *ns = profile->ns;
965diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
966index 40aedd9..e243d96 100644
967--- a/security/apparmor/include/apparmor.h
968+++ b/security/apparmor/include/apparmor.h
969@@ -29,8 +29,9 @@
970 #define AA_CLASS_NET 4
971 #define AA_CLASS_RLIMITS 5
972 #define AA_CLASS_DOMAIN 6
973+#define AA_CLASS_MOUNT 7
974
975-#define AA_CLASS_LAST AA_CLASS_DOMAIN
976+#define AA_CLASS_LAST AA_CLASS_MOUNT
977
978 /* Control parameters settable through module/boot flags */
979 extern enum audit_mode aa_g_audit;
980diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
981index c1ff09c..7b90900c 100644
982--- a/security/apparmor/include/audit.h
983+++ b/security/apparmor/include/audit.h
984@@ -73,6 +73,10 @@ enum aa_ops {
985 OP_FMMAP,
986 OP_FMPROT,
987
988+ OP_PIVOTROOT,
989+ OP_MOUNT,
990+ OP_UMOUNT,
991+
992 OP_CREATE,
993 OP_POST_CREATE,
994 OP_BIND,
995@@ -121,6 +125,13 @@ struct apparmor_audit_data {
996 unsigned long max;
997 } rlim;
998 struct {
999+ const char *src_name;
1000+ const char *type;
1001+ const char *trans;
1002+ const char *data;
1003+ unsigned long flags;
1004+ } mnt;
1005+ struct {
1006 const char *target;
1007 u32 request;
1008 u32 denied;
1009diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
1010index de04464..a3f70c5 100644
1011--- a/security/apparmor/include/domain.h
1012+++ b/security/apparmor/include/domain.h
1013@@ -23,6 +23,8 @@ struct aa_domain {
1014 char **table;
1015 };
1016
1017+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
1018+
1019 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
1020 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
1021 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
1022diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
ceaf2cfb 1023new file mode 100644
1e8b8f9b 1024index 0000000..bc17a53
ceaf2cfb 1025--- /dev/null
1e8b8f9b
AM
1026+++ b/security/apparmor/include/mount.h
1027@@ -0,0 +1,54 @@
2380c486 1028+/*
9474138d
AM
1029+ * AppArmor security module
1030+ *
1e8b8f9b 1031+ * This file contains AppArmor file mediation function definitions.
2380c486 1032+ *
1e8b8f9b 1033+ * Copyright 2012 Canonical Ltd.
2380c486 1034+ *
9474138d
AM
1035+ * This program is free software; you can redistribute it and/or
1036+ * modify it under the terms of the GNU General Public License as
1037+ * published by the Free Software Foundation, version 2 of the
1038+ * License.
2380c486
JR
1039+ */
1040+
1e8b8f9b
AM
1041+#ifndef __AA_MOUNT_H
1042+#define __AA_MOUNT_H
fc63ffa9 1043+
1e8b8f9b
AM
1044+#include <linux/fs.h>
1045+#include <linux/path.h>
2380c486 1046+
1e8b8f9b
AM
1047+#include "domain.h"
1048+#include "policy.h"
76514441 1049+
1e8b8f9b
AM
1050+/* mount perms */
1051+#define AA_MAY_PIVOTROOT 0x01
1052+#define AA_MAY_MOUNT 0x02
1053+#define AA_MAY_UMOUNT 0x04
1054+#define AA_AUDIT_DATA 0x40
1055+#define AA_CONT_MATCH 0x40
fc63ffa9 1056+
1e8b8f9b 1057+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
fc63ffa9 1058+
1e8b8f9b
AM
1059+int aa_remount(struct aa_profile *profile, struct path *path,
1060+ unsigned long flags, void *data);
fc63ffa9 1061+
1e8b8f9b
AM
1062+int aa_bind_mount(struct aa_profile *profile, struct path *path,
1063+ const char *old_name, unsigned long flags);
fc63ffa9 1064+
fc63ffa9 1065+
1e8b8f9b
AM
1066+int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1067+ unsigned long flags);
fc63ffa9 1068+
1e8b8f9b
AM
1069+int aa_move_mount(struct aa_profile *profile, struct path *path,
1070+ const char *old_name);
1071+
1072+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
1073+ struct path *path, const char *type, unsigned long flags,
1074+ void *data);
1075+
1076+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
1077+
1078+int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1079+ struct path *new_path);
1080+
1081+#endif /* __AA_MOUNT_H */
1082diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
1083index 3cde194..4512cc6 100644
1084--- a/security/apparmor/lsm.c
1085+++ b/security/apparmor/lsm.c
1086@@ -36,6 +36,7 @@
1087 #include "include/path.h"
1088 #include "include/policy.h"
1089 #include "include/procattr.h"
1090+#include "include/mount.h"
1091
1092 /* Flag indicating whether initialization completed */
1093 int apparmor_initialized __initdata;
1094@@ -512,6 +513,60 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1095 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1096 }
1097
1098+static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
1099+ unsigned long flags, void *data)
2380c486 1100+{
1e8b8f9b
AM
1101+ struct aa_profile *profile;
1102+ int error = 0;
76514441 1103+
1e8b8f9b
AM
1104+ /* Discard magic */
1105+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1106+ flags &= ~MS_MGC_MSK;
2380c486 1107+
1e8b8f9b
AM
1108+ flags &= ~AA_MS_IGNORE_MASK;
1109+
1110+ profile = __aa_current_profile();
1111+ if (!unconfined(profile)) {
1112+ if (flags & MS_REMOUNT)
1113+ error = aa_remount(profile, path, flags, data);
1114+ else if (flags & MS_BIND)
1115+ error = aa_bind_mount(profile, path, dev_name, flags);
1116+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
1117+ MS_UNBINDABLE))
1118+ error = aa_mount_change_type(profile, path, flags);
1119+ else if (flags & MS_MOVE)
1120+ error = aa_move_mount(profile, path, dev_name);
1121+ else
1122+ error = aa_new_mount(profile, dev_name, path, type,
1123+ flags, data);
2380c486 1124+ }
1e8b8f9b
AM
1125+ return error;
1126+}
2380c486 1127+
1e8b8f9b
AM
1128+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
1129+{
1130+ struct aa_profile *profile;
1131+ int error = 0;
1132+
1133+ profile = __aa_current_profile();
1134+ if (!unconfined(profile))
1135+ error = aa_umount(profile, mnt, flags);
1136+
1137+ return error;
2380c486
JR
1138+}
1139+
1e8b8f9b 1140+static int apparmor_sb_pivotroot(struct path *old_path, struct path *new_path)
2380c486 1141+{
1e8b8f9b
AM
1142+ struct aa_profile *profile;
1143+ int error = 0;
1144+
1145+ profile = __aa_current_profile();
1146+ if (!unconfined(profile))
1147+ error = aa_pivotroot(profile, old_path, new_path);
1148+
1149+ return error;
2380c486
JR
1150+}
1151+
1e8b8f9b
AM
1152 static int apparmor_getprocattr(struct task_struct *task, char *name,
1153 char **value)
1154 {
1155@@ -729,6 +784,10 @@ static struct security_operations apparmor_ops = {
1156 .capget = apparmor_capget,
1157 .capable = apparmor_capable,
1158
1159+ .sb_mount = apparmor_sb_mount,
1160+ .sb_umount = apparmor_sb_umount,
1161+ .sb_pivotroot = apparmor_sb_pivotroot,
1162+
1163 .path_link = apparmor_path_link,
1164 .path_unlink = apparmor_path_unlink,
1165 .path_symlink = apparmor_path_symlink,
1166diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
1167new file mode 100644
1168index 0000000..63d8493
1169--- /dev/null
1170+++ b/security/apparmor/mount.c
1171@@ -0,0 +1,620 @@
1172+/*
1173+ * AppArmor security module
fc63ffa9 1174+ *
1e8b8f9b 1175+ * This file contains AppArmor mediation of files
ceaf2cfb 1176+ *
1e8b8f9b
AM
1177+ * Copyright (C) 1998-2008 Novell/SUSE
1178+ * Copyright 2009-2012 Canonical Ltd.
1179+ *
1180+ * This program is free software; you can redistribute it and/or
1181+ * modify it under the terms of the GNU General Public License as
1182+ * published by the Free Software Foundation, version 2 of the
1183+ * License.
ceaf2cfb 1184+ */
2380c486 1185+
1e8b8f9b
AM
1186+#include <linux/fs.h>
1187+#include <linux/mount.h>
1188+#include <linux/namei.h>
2380c486 1189+
1e8b8f9b
AM
1190+#include "include/apparmor.h"
1191+#include "include/audit.h"
1192+#include "include/context.h"
1193+#include "include/domain.h"
1194+#include "include/file.h"
1195+#include "include/match.h"
1196+#include "include/mount.h"
1197+#include "include/path.h"
1198+#include "include/policy.h"
ceaf2cfb 1199+
2380c486 1200+
1e8b8f9b
AM
1201+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
1202+{
1203+ if (flags & MS_RDONLY)
1204+ audit_log_format(ab, "ro");
1205+ else
1206+ audit_log_format(ab, "rw");
1207+ if (flags & MS_NOSUID)
1208+ audit_log_format(ab, ", nosuid");
1209+ if (flags & MS_NODEV)
1210+ audit_log_format(ab, ", nodev");
1211+ if (flags & MS_NOEXEC)
1212+ audit_log_format(ab, ", noexec");
1213+ if (flags & MS_SYNCHRONOUS)
1214+ audit_log_format(ab, ", sync");
1215+ if (flags & MS_REMOUNT)
1216+ audit_log_format(ab, ", remount");
1217+ if (flags & MS_MANDLOCK)
1218+ audit_log_format(ab, ", mand");
1219+ if (flags & MS_DIRSYNC)
1220+ audit_log_format(ab, ", dirsync");
1221+ if (flags & MS_NOATIME)
1222+ audit_log_format(ab, ", noatime");
1223+ if (flags & MS_NODIRATIME)
1224+ audit_log_format(ab, ", nodiratime");
1225+ if (flags & MS_BIND)
1226+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
1227+ if (flags & MS_MOVE)
1228+ audit_log_format(ab, ", move");
1229+ if (flags & MS_SILENT)
1230+ audit_log_format(ab, ", silent");
1231+ if (flags & MS_POSIXACL)
1232+ audit_log_format(ab, ", acl");
1233+ if (flags & MS_UNBINDABLE)
1234+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
1235+ ", unbindable");
1236+ if (flags & MS_PRIVATE)
1237+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
1238+ ", private");
1239+ if (flags & MS_SLAVE)
1240+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
1241+ ", slave");
1242+ if (flags & MS_SHARED)
1243+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
1244+ ", shared");
1245+ if (flags & MS_RELATIME)
1246+ audit_log_format(ab, ", relatime");
1247+ if (flags & MS_I_VERSION)
1248+ audit_log_format(ab, ", iversion");
1249+ if (flags & MS_STRICTATIME)
1250+ audit_log_format(ab, ", strictatime");
1251+ if (flags & MS_NOUSER)
1252+ audit_log_format(ab, ", nouser");
2380c486
JR
1253+}
1254+
ceaf2cfb 1255+/**
1e8b8f9b
AM
1256+ * audit_cb - call back for mount specific audit fields
1257+ * @ab: audit_buffer (NOT NULL)
1258+ * @va: audit struct to audit values of (NOT NULL)
ceaf2cfb 1259+ */
1e8b8f9b 1260+static void audit_cb(struct audit_buffer *ab, void *va)
2380c486 1261+{
1e8b8f9b 1262+ struct common_audit_data *sa = va;
9474138d 1263+
1e8b8f9b
AM
1264+ if (sa->aad->mnt.type) {
1265+ audit_log_format(ab, " fstype=");
1266+ audit_log_untrustedstring(ab, sa->aad->mnt.type);
1267+ }
1268+ if (sa->aad->mnt.src_name) {
1269+ audit_log_format(ab, " srcname=");
1270+ audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
1271+ }
1272+ if (sa->aad->mnt.trans) {
1273+ audit_log_format(ab, " trans=");
1274+ audit_log_untrustedstring(ab, sa->aad->mnt.trans);
1275+ }
1276+ if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
1277+ audit_log_format(ab, " flags=\"");
1278+ audit_mnt_flags(ab, sa->aad->mnt.flags);
1279+ audit_log_format(ab, "\"");
1280+ }
1281+ if (sa->aad->mnt.data) {
1282+ audit_log_format(ab, " options=");
1283+ audit_log_untrustedstring(ab, sa->aad->mnt.data);
1284+ }
9474138d 1285+}
2380c486 1286+
fc63ffa9 1287+/**
1e8b8f9b
AM
1288+ * audit_mount - handle the auditing of mount operations
1289+ * @profile: the profile being enforced (NOT NULL)
1290+ * @gfp: allocation flags
1291+ * @op: operation being mediated (NOT NULL)
1292+ * @name: name of object being mediated (MAYBE NULL)
1293+ * @src_name: src_name of object being mediated (MAYBE_NULL)
1294+ * @type: type of filesystem (MAYBE_NULL)
1295+ * @trans: name of trans (MAYBE NULL)
1296+ * @flags: filesystem idependent mount flags
1297+ * @data: filesystem mount flags
1298+ * @request: permissions requested
1299+ * @perms: the permissions computed for the request (NOT NULL)
1300+ * @info: extra information message (MAYBE NULL)
1301+ * @error: 0 if operation allowed else failure error code
9474138d 1302+ *
1e8b8f9b 1303+ * Returns: %0 or error on failure
76514441 1304+ */
1e8b8f9b
AM
1305+static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
1306+ const char *name, const char *src_name,
1307+ const char *type, const char *trans,
1308+ unsigned long flags, const void *data, u32 request,
1309+ struct file_perms *perms, const char *info, int error)
2380c486 1310+{
1e8b8f9b
AM
1311+ int audit_type = AUDIT_APPARMOR_AUTO;
1312+ struct common_audit_data sa;
1313+ struct apparmor_audit_data aad = { };
9474138d 1314+
1e8b8f9b
AM
1315+ if (likely(!error)) {
1316+ u32 mask = perms->audit;
9474138d 1317+
1e8b8f9b
AM
1318+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
1319+ mask = 0xffff;
76514441 1320+
1e8b8f9b
AM
1321+ /* mask off perms that are not being force audited */
1322+ request &= mask;
fc63ffa9 1323+
1e8b8f9b
AM
1324+ if (likely(!request))
1325+ return 0;
1326+ audit_type = AUDIT_APPARMOR_AUDIT;
1327+ } else {
1328+ /* only report permissions that were denied */
1329+ request = request & ~perms->allow;
1330+
1331+ if (request & perms->kill)
1332+ audit_type = AUDIT_APPARMOR_KILL;
1333+
1334+ /* quiet known rejects, assumes quiet and kill do not overlap */
1335+ if ((request & perms->quiet) &&
1336+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
1337+ AUDIT_MODE(profile) != AUDIT_ALL)
1338+ request &= ~perms->quiet;
1339+
1340+ if (!request)
1341+ return COMPLAIN_MODE(profile) ?
1342+ complain_error(error) : error;
1343+ }
1344+
1345+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
1346+ sa.aad = &aad;
1347+ sa.aad->op = op;
1348+ sa.aad->name = name;
1349+ sa.aad->mnt.src_name = src_name;
1350+ sa.aad->mnt.type = type;
1351+ sa.aad->mnt.trans = trans;
1352+ sa.aad->mnt.flags = flags;
1353+ if (data && (perms->audit & AA_AUDIT_DATA))
1354+ sa.aad->mnt.data = data;
1355+ sa.aad->info = info;
1356+ sa.aad->error = error;
1357+
1358+ return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
76514441
AM
1359+}
1360+
1361+/**
1e8b8f9b
AM
1362+ * match_mnt_flags - Do an ordered match on mount flags
1363+ * @dfa: dfa to match against
1364+ * @state: state to start in
1365+ * @flags: mount flags to match against
76514441 1366+ *
1e8b8f9b
AM
1367+ * Mount flags are encoded as an ordered match. This is done instead of
1368+ * checking against a simple bitmask, to allow for logical operations
1369+ * on the flags.
76514441 1370+ *
1e8b8f9b 1371+ * Returns: next state after flags match
76514441 1372+ */
1e8b8f9b
AM
1373+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
1374+ unsigned long flags)
9474138d 1375+{
1e8b8f9b 1376+ unsigned int i;
fc63ffa9 1377+
1e8b8f9b
AM
1378+ for (i = 0; i <= 31 ; ++i) {
1379+ if ((1 << i) & flags)
1380+ state = aa_dfa_next(dfa, state, i + 1);
1381+ }
1382+
1383+ return state;
9474138d
AM
1384+}
1385+
1386+/**
1e8b8f9b
AM
1387+ * compute_mnt_perms - compute mount permission associated with @state
1388+ * @dfa: dfa to match against (NOT NULL)
1389+ * @state: state match finished in
ceaf2cfb 1390+ *
1e8b8f9b 1391+ * Returns: mount permissions
9474138d 1392+ */
1e8b8f9b
AM
1393+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
1394+ unsigned int state)
9474138d 1395+{
1e8b8f9b 1396+ struct file_perms perms;
2380c486 1397+
1e8b8f9b
AM
1398+ perms.kill = 0;
1399+ perms.allow = dfa_user_allow(dfa, state);
1400+ perms.audit = dfa_user_audit(dfa, state);
1401+ perms.quiet = dfa_user_quiet(dfa, state);
1402+ perms.xindex = dfa_user_xindex(dfa, state);
1403+
1404+ return perms;
1405+}
1406+
1407+static const char const *mnt_info_table[] = {
1408+ "match succeeded",
1409+ "failed mntpnt match",
1410+ "failed srcname match",
1411+ "failed type match",
1412+ "failed flags match",
1413+ "failed data match"
1414+};
1415+
1416+/*
1417+ * Returns 0 on success else element that match failed in, this is the
1418+ * index into the mnt_info_table above
1419+ */
1420+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
1421+ const char *mntpnt, const char *devname,
1422+ const char *type, unsigned long flags,
1423+ void *data, bool binary, struct file_perms *perms)
1424+{
1425+ unsigned int state;
1426+
1427+ state = aa_dfa_match(dfa, start, mntpnt);
1428+ state = aa_dfa_null_transition(dfa, state);
1429+ if (!state)
1430+ return 1;
1431+
1432+ if (devname)
1433+ state = aa_dfa_match(dfa, state, devname);
1434+ state = aa_dfa_null_transition(dfa, state);
1435+ if (!state)
1436+ return 2;
1437+
1438+ if (type)
1439+ state = aa_dfa_match(dfa, state, type);
1440+ state = aa_dfa_null_transition(dfa, state);
1441+ if (!state)
1442+ return 3;
1443+
1444+ state = match_mnt_flags(dfa, state, flags);
1445+ if (!state)
1446+ return 4;
1447+ *perms = compute_mnt_perms(dfa, state);
1448+ if (perms->allow & AA_MAY_MOUNT)
1449+ return 0;
1450+
1451+ /* only match data if not binary and the DFA flags data is expected */
1452+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
1453+ state = aa_dfa_null_transition(dfa, state);
1454+ if (!state)
1455+ return 4;
1456+
1457+ state = aa_dfa_match(dfa, state, data);
1458+ if (!state)
1459+ return 5;
1460+ *perms = compute_mnt_perms(dfa, state);
1461+ if (perms->allow & AA_MAY_MOUNT)
1462+ return 0;
fc63ffa9 1463+ }
1e8b8f9b
AM
1464+
1465+ /* failed at end of flags match */
1466+ return 4;
9474138d
AM
1467+}
1468+
ceaf2cfb 1469+/**
1e8b8f9b
AM
1470+ * match_mnt - handle path matching for mount
1471+ * @profile: the confining profile
1472+ * @mntpnt: string for the mntpnt (NOT NULL)
1473+ * @devname: string for the devname/src_name (MAYBE NULL)
1474+ * @type: string for the dev type (MAYBE NULL)
1475+ * @flags: mount flags to match
1476+ * @data: fs mount data (MAYBE NULL)
1477+ * @binary: whether @data is binary
1478+ * @perms: Returns: permission found by the match
1479+ * @info: Returns: infomation string about the match for logging
fc63ffa9 1480+ *
1e8b8f9b 1481+ * Returns: 0 on success else error
ceaf2cfb 1482+ */
1e8b8f9b
AM
1483+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
1484+ const char *devname, const char *type,
1485+ unsigned long flags, void *data, bool binary,
1486+ struct file_perms *perms, const char **info)
9474138d 1487+{
1e8b8f9b 1488+ int pos;
2380c486 1489+
1e8b8f9b
AM
1490+ if (!profile->policy.dfa)
1491+ return -EACCES;
1492+
1493+ pos = do_match_mnt(profile->policy.dfa,
1494+ profile->policy.start[AA_CLASS_MOUNT],
1495+ mntpnt, devname, type, flags, data, binary, perms);
1496+ if (pos) {
1497+ *info = mnt_info_table[pos];
1498+ return -EACCES;
1499+ }
2380c486 1500+
fc63ffa9 1501+ return 0;
9474138d 1502+}
9474138d 1503+
1e8b8f9b
AM
1504+static int path_flags(struct aa_profile *profile, struct path *path)
1505+{
1506+ return profile->path_flags |
1507+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
1508+}
9474138d 1509+
1e8b8f9b
AM
1510+int aa_remount(struct aa_profile *profile, struct path *path,
1511+ unsigned long flags, void *data)
9474138d 1512+{
1e8b8f9b
AM
1513+ struct file_perms perms = { };
1514+ const char *name, *info = NULL;
1515+ char *buffer = NULL;
1516+ int binary, error;
1517+
1518+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
1519+
1520+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1521+ &info);
1522+ if (error)
1523+ goto audit;
1524+
1525+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
1526+ &perms, &info);
1527+
1528+audit:
1529+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1530+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1531+ error);
1532+ kfree(buffer);
1533+
1534+ return error;
9474138d
AM
1535+}
1536+
1e8b8f9b
AM
1537+int aa_bind_mount(struct aa_profile *profile, struct path *path,
1538+ const char *dev_name, unsigned long flags)
9474138d 1539+{
1e8b8f9b
AM
1540+ struct file_perms perms = { };
1541+ char *buffer = NULL, *old_buffer = NULL;
1542+ const char *name, *old_name = NULL, *info = NULL;
1543+ struct path old_path;
1544+ int error;
1545+
1546+ if (!dev_name || !*dev_name)
1547+ return -EINVAL;
1548+
1549+ flags &= MS_REC | MS_BIND;
1550+
1551+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1552+ &info);
1553+ if (error)
1554+ goto audit;
1555+
1556+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1557+ if (error)
1558+ goto audit;
1559+
1560+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
1561+ &old_buffer, &old_name, &info);
1562+ path_put(&old_path);
1563+ if (error)
1564+ goto audit;
1565+
1566+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
1567+ &perms, &info);
1568+
1569+audit:
1570+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1571+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
1572+ info, error);
1573+ kfree(buffer);
1574+ kfree(old_buffer);
1575+
1576+ return error;
9474138d 1577+}
fc63ffa9 1578+
1e8b8f9b
AM
1579+int aa_mount_change_type(struct aa_profile *profile, struct path *path,
1580+ unsigned long flags)
1581+{
1582+ struct file_perms perms = { };
1583+ char *buffer = NULL;
1584+ const char *name, *info = NULL;
1585+ int error;
1586+
1587+ /* These are the flags allowed by do_change_type() */
1588+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
1589+ MS_UNBINDABLE);
1590+
1591+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1592+ &info);
fc63ffa9 1593+ if (error)
1e8b8f9b
AM
1594+ goto audit;
1595+
1596+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
1597+ &info);
1598+
1599+audit:
1600+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
1601+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
1602+ error);
1603+ kfree(buffer);
1604+
1605+ return error;
1606+}
1607+
1608+int aa_move_mount(struct aa_profile *profile, struct path *path,
1609+ const char *orig_name)
1610+{
1611+ struct file_perms perms = { };
1612+ char *buffer = NULL, *old_buffer = NULL;
1613+ const char *name, *old_name = NULL, *info = NULL;
1614+ struct path old_path;
1615+ int error;
1616+
1617+ if (!orig_name || !*orig_name)
1618+ return -EINVAL;
1619+
1620+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1621+ &info);
fc63ffa9 1622+ if (error)
1e8b8f9b
AM
1623+ goto audit;
1624+
1625+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
fc63ffa9 1626+ if (error)
1e8b8f9b
AM
1627+ goto audit;
1628+
1629+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
1630+ &old_buffer, &old_name, &info);
1631+ path_put(&old_path);
1632+ if (error)
1633+ goto audit;
1634+
1635+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
1636+ &perms, &info);
1637+
1638+audit:
1639+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
1640+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
1641+ info, error);
1642+ kfree(buffer);
1643+ kfree(old_buffer);
1644+
1645+ return error;
1646+}
1647+
1648+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
1649+ struct path *path, const char *type, unsigned long flags,
1650+ void *data)
1651+{
1652+ struct file_perms perms = { };
1653+ char *buffer = NULL, *dev_buffer = NULL;
1654+ const char *name = NULL, *dev_name = NULL, *info = NULL;
1655+ int binary = 1;
1656+ int error;
1657+
1658+ dev_name = orig_dev_name;
1659+ if (type) {
1660+ int requires_dev;
1661+ struct file_system_type *fstype = get_fs_type(type);
1662+ if (!fstype)
1663+ return -ENODEV;
1664+
1665+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
1666+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
1667+ put_filesystem(fstype);
1668+
1669+ if (requires_dev) {
1670+ struct path dev_path;
1671+
1672+ if (!dev_name || !*dev_name) {
1673+ error = -ENOENT;
1674+ goto out;
1675+ }
1676+
1677+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
1678+ if (error)
1679+ goto audit;
1680+
1681+ error = aa_path_name(&dev_path,
1682+ path_flags(profile, &dev_path),
1683+ &dev_buffer, &dev_name, &info);
1684+ path_put(&dev_path);
1685+ if (error)
1686+ goto audit;
1687+ }
1688+ }
1689+
1690+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
1691+ &info);
1692+ if (error)
1693+ goto audit;
1694+
1695+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
1696+ &perms, &info);
1697+
1698+audit:
1699+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
1700+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
1701+ error);
1702+ kfree(buffer);
1703+ kfree(dev_buffer);
1704+
1705+out:
1706+ return error;
1707+
1708+}
1709+
1710+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
1711+{
1712+ struct file_perms perms = { };
1713+ char *buffer = NULL;
1714+ const char *name, *info = NULL;
1715+ int error;
1716+
1717+ struct path path = { mnt, mnt->mnt_root };
1718+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
1719+ &info);
1720+ if (error)
1721+ goto audit;
1722+
1723+ if (!error && profile->policy.dfa) {
1724+ unsigned int state;
1725+ state = aa_dfa_match(profile->policy.dfa,
1726+ profile->policy.start[AA_CLASS_MOUNT],
1727+ name);
1728+ perms = compute_mnt_perms(profile->policy.dfa, state);
1729+ }
1730+
1731+ if (AA_MAY_UMOUNT & ~perms.allow)
1732+ error = -EACCES;
1733+
1734+audit:
1735+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
1736+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
1737+ kfree(buffer);
1738+
1739+ return error;
1740+}
1741+
1742+int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1743+ struct path *new_path)
1744+{
1745+ struct file_perms perms = { };
1746+ struct aa_profile *target = NULL;
1747+ char *old_buffer = NULL, *new_buffer = NULL;
1748+ const char *old_name, *new_name = NULL, *info = NULL;
1749+ int error;
1750+
1751+ error = aa_path_name(old_path, path_flags(profile, old_path),
1752+ &old_buffer, &old_name, &info);
1753+ if (error)
1754+ goto audit;
1755+
1756+ error = aa_path_name(new_path, path_flags(profile, new_path),
1757+ &new_buffer, &new_name, &info);
1758+ if (error)
1759+ goto audit;
1760+
1761+ if (profile->policy.dfa) {
1762+ unsigned int state;
1763+ state = aa_dfa_match(profile->policy.dfa,
1764+ profile->policy.start[AA_CLASS_MOUNT],
1765+ new_name);
1766+ state = aa_dfa_null_transition(profile->policy.dfa, state);
1767+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
1768+ perms = compute_mnt_perms(profile->policy.dfa, state);
1769+ }
1770+
1771+ if (AA_MAY_PIVOTROOT & perms.allow) {
1772+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
1773+ target = x_table_lookup(profile, perms.xindex);
1774+ if (!target)
1775+ error = -ENOENT;
1776+ else
1777+ error = aa_replace_current_profile(target);
1778+ }
1779+ } else
1780+ error = -EACCES;
1781+
1782+audit:
1783+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
1784+ old_name, NULL, target ? target->base.name : NULL,
1785+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
1786+ aa_put_profile(target);
1787+ kfree(old_buffer);
1788+ kfree(new_buffer);
1789+
1790+ return error;
1791+}
This page took 0.336641 seconds and 4 git commands to generate.