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