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