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