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