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