]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-apparmor.patch
- 4.4.16
[packages/kernel.git] / kernel-apparmor.patch
CommitLineData
c2c0f25c 1From e37c855a09ba7a8fa69334e9e3c7f5b0f66de896 Mon Sep 17 00:00:00 2001
0fa3db16
AM
2From: John Johansen <john.johansen@canonical.com>
3Date: Mon, 4 Oct 2010 15:03:36 -0700
c2c0f25c 4Subject: UBUNTU: SAUCE: AppArmor: basic networking rules
1e8b8f9b
AM
5
6Base support for network mediation.
76514441
AM
7
8Signed-off-by: John Johansen <john.johansen@canonical.com>
5882c9d4 9
5882c9d4
AM
10diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
11index 9cdec70..d5b291e 100644
12--- a/security/apparmor/.gitignore
13+++ b/security/apparmor/.gitignore
14@@ -1,5 +1,6 @@
15 #
16 # Generated include files
17 #
18+net_names.h
19 capability_names.h
20 rlim_names.h
fc63ffa9 21diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
5882c9d4 22index d693df8..5dbb72f 100644
fc63ffa9
AM
23--- a/security/apparmor/Makefile
24+++ b/security/apparmor/Makefile
5882c9d4 25@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
ceaf2cfb 26
fc63ffa9
AM
27 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
28 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
29- resource.o sid.o file.o
30+ resource.o sid.o file.o net.o
5882c9d4 31 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
ceaf2cfb 32
948a1326 33-clean-files := capability_names.h rlim_names.h
1e8b8f9b 34+clean-files := capability_names.h rlim_names.h net_names.h
ceaf2cfb 35
ceaf2cfb 36
948a1326 37 # Build a lower case string table of capability names
5882c9d4
AM
38@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
39 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
40 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
948a1326 41
1e8b8f9b 42+# Build a lower case string table of address family names
948a1326 43+# Transform lines from
1e8b8f9b
AM
44+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
45+# #define AF_INET 2 /* Internet IP Protocol */
46+# to
47+# [1] = "local",
48+# [2] = "inet",
49+#
50+# and build the securityfs entries for the mapping.
51+# Transforms lines from
52+# #define AF_INET 2 /* Internet IP Protocol */
948a1326 53+# to
1e8b8f9b 54+# #define AA_FS_AF_MASK "local inet"
ceaf2cfb 55+quiet_cmd_make-af = GEN $@
948a1326 56+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
1e8b8f9b
AM
57+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
58+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
59+ echo "};" >> $@ ;\
60+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
61+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
62+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
63+
64+# Build a lower case string table of sock type names
65+# Transform lines from
66+# SOCK_STREAM = 1,
67+# to
68+# [1] = "stream",
69+quiet_cmd_make-sock = GEN $@
70+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
71+ sed $^ >>$@ -r -n \
72+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
948a1326 73+ echo "};" >> $@
1e8b8f9b
AM
74
75 # Build a lower case string table of rlimit names.
76 # Transforms lines from
5882c9d4 77@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
1e8b8f9b
AM
78 tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
79
fc63ffa9 80 $(obj)/capability.o : $(obj)/capability_names.h
1e8b8f9b 81+$(obj)/net.o : $(obj)/net_names.h
fc63ffa9 82 $(obj)/resource.o : $(obj)/rlim_names.h
5882c9d4 83 $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
1e8b8f9b 84 $(src)/Makefile
5882c9d4
AM
85@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
86 $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
1e8b8f9b 87 $(src)/Makefile
948a1326 88 $(call cmd,make-rlim)
1e8b8f9b
AM
89+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
90+ $(srctree)/include/linux/net.h \
91+ $(src)/Makefile
948a1326 92+ $(call cmd,make-af)
1e8b8f9b
AM
93+ $(call cmd,make-sock)
94diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
c2c0f25c 95index ad4fa49..6362c5a 100644
1e8b8f9b
AM
96--- a/security/apparmor/apparmorfs.c
97+++ b/security/apparmor/apparmorfs.c
5882c9d4
AM
98@@ -806,6 +806,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
99 AA_FS_DIR("policy", aa_fs_entry_policy),
1e8b8f9b
AM
100 AA_FS_DIR("domain", aa_fs_entry_domain),
101 AA_FS_DIR("file", aa_fs_entry_file),
102+ AA_FS_DIR("network", aa_fs_entry_network),
103 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
104 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
5882c9d4 105 AA_FS_DIR("caps", aa_fs_entry_caps),
1e8b8f9b 106diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
c2c0f25c 107index ba3dfd1..5d3c419 100644
1e8b8f9b
AM
108--- a/security/apparmor/include/audit.h
109+++ b/security/apparmor/include/audit.h
c2c0f25c 110@@ -125,6 +125,10 @@ struct apparmor_audit_data {
1e8b8f9b 111 u32 denied;
5882c9d4 112 kuid_t ouid;
1e8b8f9b
AM
113 } fs;
114+ struct {
115+ int type, protocol;
116+ struct sock *sk;
117+ } net;
118 };
119 };
120
fc63ffa9 121diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
ceaf2cfb 122new file mode 100644
1e8b8f9b 123index 0000000..cb8a121
ceaf2cfb 124--- /dev/null
fc63ffa9 125+++ b/security/apparmor/include/net.h
1e8b8f9b 126@@ -0,0 +1,44 @@
9474138d
AM
127+/*
128+ * AppArmor security module
129+ *
fc63ffa9 130+ * This file contains AppArmor network mediation definitions.
9474138d
AM
131+ *
132+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 133+ * Copyright 2009-2012 Canonical Ltd.
9474138d
AM
134+ *
135+ * This program is free software; you can redistribute it and/or
136+ * modify it under the terms of the GNU General Public License as
137+ * published by the Free Software Foundation, version 2 of the
138+ * License.
139+ */
140+
fc63ffa9
AM
141+#ifndef __AA_NET_H
142+#define __AA_NET_H
2380c486 143+
fc63ffa9 144+#include <net/sock.h>
9474138d 145+
1e8b8f9b
AM
146+#include "apparmorfs.h"
147+
fc63ffa9
AM
148+/* struct aa_net - network confinement data
149+ * @allowed: basic network families permissions
150+ * @audit_network: which network permissions to force audit
151+ * @quiet_network: which network permissions to quiet rejects
152+ */
153+struct aa_net {
154+ u16 allow[AF_MAX];
155+ u16 audit[AF_MAX];
156+ u16 quiet[AF_MAX];
157+};
ceaf2cfb 158+
1e8b8f9b
AM
159+extern struct aa_fs_entry aa_fs_entry_network[];
160+
fc63ffa9
AM
161+extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
162+ int type, int protocol, struct sock *sk);
163+extern int aa_revalidate_sk(int op, struct sock *sk);
ceaf2cfb 164+
fc63ffa9
AM
165+static inline void aa_free_net_rules(struct aa_net *new)
166+{
167+ /* NOP */
ceaf2cfb
AM
168+}
169+
fc63ffa9
AM
170+#endif /* __AA_NET_H */
171diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
5882c9d4 172index c28b0f2..b524d88 100644
fc63ffa9
AM
173--- a/security/apparmor/include/policy.h
174+++ b/security/apparmor/include/policy.h
175@@ -27,6 +27,7 @@
176 #include "capability.h"
177 #include "domain.h"
178 #include "file.h"
179+#include "net.h"
180 #include "resource.h"
181
5882c9d4
AM
182 extern const char *const aa_profile_mode_names[];
183@@ -176,6 +177,7 @@ struct aa_replacedby {
1e8b8f9b 184 * @policy: general match rules governing policy
fc63ffa9
AM
185 * @file: The set of rules governing basic file access and domain transitions
186 * @caps: capabilities for the profile
187+ * @net: network controls for the profile
188 * @rlimits: rlimits for the profile
189 *
5882c9d4
AM
190 * @dents: dentries for the profiles file entries in apparmorfs
191@@ -217,6 +219,7 @@ struct aa_profile {
1e8b8f9b 192 struct aa_policydb policy;
fc63ffa9
AM
193 struct aa_file_rules file;
194 struct aa_caps caps;
195+ struct aa_net net;
196 struct aa_rlimit rlimits;
fc63ffa9 197
5882c9d4 198 unsigned char *hash;
fc63ffa9 199diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
c2c0f25c 200index dec607c..47fd244 100644
fc63ffa9
AM
201--- a/security/apparmor/lsm.c
202+++ b/security/apparmor/lsm.c
948a1326 203@@ -32,6 +32,7 @@
fc63ffa9
AM
204 #include "include/context.h"
205 #include "include/file.h"
206 #include "include/ipc.h"
207+#include "include/net.h"
208 #include "include/path.h"
209 #include "include/policy.h"
210 #include "include/procattr.h"
c2c0f25c 211@@ -605,6 +606,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
fc63ffa9
AM
212 return error;
213 }
214
215+static int apparmor_socket_create(int family, int type, int protocol, int kern)
ceaf2cfb 216+{
fc63ffa9
AM
217+ struct aa_profile *profile;
218+ int error = 0;
ceaf2cfb 219+
fc63ffa9
AM
220+ if (kern)
221+ return 0;
ceaf2cfb 222+
fc63ffa9
AM
223+ profile = __aa_current_profile();
224+ if (!unconfined(profile))
225+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
226+ NULL);
227+ return error;
228+}
ceaf2cfb 229+
fc63ffa9
AM
230+static int apparmor_socket_bind(struct socket *sock,
231+ struct sockaddr *address, int addrlen)
9474138d 232+{
fc63ffa9 233+ struct sock *sk = sock->sk;
9474138d 234+
fc63ffa9
AM
235+ return aa_revalidate_sk(OP_BIND, sk);
236+}
ceaf2cfb 237+
fc63ffa9
AM
238+static int apparmor_socket_connect(struct socket *sock,
239+ struct sockaddr *address, int addrlen)
240+{
241+ struct sock *sk = sock->sk;
ceaf2cfb 242+
fc63ffa9 243+ return aa_revalidate_sk(OP_CONNECT, sk);
9474138d
AM
244+}
245+
fc63ffa9 246+static int apparmor_socket_listen(struct socket *sock, int backlog)
9474138d 247+{
fc63ffa9
AM
248+ struct sock *sk = sock->sk;
249+
250+ return aa_revalidate_sk(OP_LISTEN, sk);
9474138d
AM
251+}
252+
fc63ffa9 253+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
9474138d 254+{
fc63ffa9 255+ struct sock *sk = sock->sk;
9474138d 256+
fc63ffa9
AM
257+ return aa_revalidate_sk(OP_ACCEPT, sk);
258+}
9474138d 259+
fc63ffa9
AM
260+static int apparmor_socket_sendmsg(struct socket *sock,
261+ struct msghdr *msg, int size)
76514441 262+{
fc63ffa9 263+ struct sock *sk = sock->sk;
76514441 264+
fc63ffa9 265+ return aa_revalidate_sk(OP_SENDMSG, sk);
76514441
AM
266+}
267+
fc63ffa9
AM
268+static int apparmor_socket_recvmsg(struct socket *sock,
269+ struct msghdr *msg, int size, int flags)
270+{
271+ struct sock *sk = sock->sk;
ceaf2cfb 272+
fc63ffa9
AM
273+ return aa_revalidate_sk(OP_RECVMSG, sk);
274+}
ceaf2cfb 275+
fc63ffa9
AM
276+static int apparmor_socket_getsockname(struct socket *sock)
277+{
278+ struct sock *sk = sock->sk;
ceaf2cfb 279+
fc63ffa9 280+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
9474138d
AM
281+}
282+
fc63ffa9 283+static int apparmor_socket_getpeername(struct socket *sock)
9474138d 284+{
fc63ffa9 285+ struct sock *sk = sock->sk;
9474138d 286+
fc63ffa9
AM
287+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
288+}
ceaf2cfb 289+
fc63ffa9
AM
290+static int apparmor_socket_getsockopt(struct socket *sock, int level,
291+ int optname)
292+{
293+ struct sock *sk = sock->sk;
ceaf2cfb 294+
fc63ffa9
AM
295+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
296+}
ceaf2cfb 297+
fc63ffa9
AM
298+static int apparmor_socket_setsockopt(struct socket *sock, int level,
299+ int optname)
300+{
301+ struct sock *sk = sock->sk;
2380c486 302+
fc63ffa9
AM
303+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
304+}
ceaf2cfb 305+
fc63ffa9
AM
306+static int apparmor_socket_shutdown(struct socket *sock, int how)
307+{
308+ struct sock *sk = sock->sk;
ceaf2cfb 309+
fc63ffa9 310+ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
ceaf2cfb 311+}
948a1326 312+
c2c0f25c
AM
313 static struct security_hook_list apparmor_hooks[] = {
314 LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
315 LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
316@@ -634,6 +733,19 @@ static struct security_hook_list apparmor_hooks[] = {
317 LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
318 LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
5d26c04f 319
c2c0f25c
AM
320+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
321+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
322+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
323+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
324+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
325+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
326+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
327+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
328+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
329+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
330+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
331+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
332+
333 LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
334 LSM_HOOK_INIT(cred_free, apparmor_cred_free),
335 LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
fc63ffa9 336diff --git a/security/apparmor/net.c b/security/apparmor/net.c
ceaf2cfb 337new file mode 100644
2dfbb274 338index 0000000..003dd18
ceaf2cfb 339--- /dev/null
fc63ffa9 340+++ b/security/apparmor/net.c
1e8b8f9b 341@@ -0,0 +1,162 @@
2380c486 342+/*
9474138d
AM
343+ * AppArmor security module
344+ *
fc63ffa9 345+ * This file contains AppArmor network mediation
2380c486 346+ *
9474138d 347+ * Copyright (C) 1998-2008 Novell/SUSE
1e8b8f9b 348+ * Copyright 2009-2012 Canonical Ltd.
2380c486 349+ *
9474138d
AM
350+ * This program is free software; you can redistribute it and/or
351+ * modify it under the terms of the GNU General Public License as
352+ * published by the Free Software Foundation, version 2 of the
353+ * License.
2380c486
JR
354+ */
355+
9474138d
AM
356+#include "include/apparmor.h"
357+#include "include/audit.h"
358+#include "include/context.h"
fc63ffa9 359+#include "include/net.h"
9474138d 360+#include "include/policy.h"
2380c486 361+
1e8b8f9b
AM
362+#include "net_names.h"
363+
364+struct aa_fs_entry aa_fs_entry_network[] = {
365+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
366+ { }
9474138d
AM
367+};
368+
fc63ffa9 369+/* audit callback for net specific fields */
76514441 370+static void audit_cb(struct audit_buffer *ab, void *va)
9474138d 371+{
76514441 372+ struct common_audit_data *sa = va;
9474138d 373+
fc63ffa9 374+ audit_log_format(ab, " family=");
1e8b8f9b
AM
375+ if (address_family_names[sa->u.net->family]) {
376+ audit_log_string(ab, address_family_names[sa->u.net->family]);
fc63ffa9 377+ } else {
1e8b8f9b 378+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
fc63ffa9 379+ }
fc63ffa9 380+ audit_log_format(ab, " sock_type=");
1e8b8f9b
AM
381+ if (sock_type_names[sa->aad->net.type]) {
382+ audit_log_string(ab, sock_type_names[sa->aad->net.type]);
fc63ffa9 383+ } else {
1e8b8f9b 384+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
fc63ffa9 385+ }
1e8b8f9b 386+ audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
2380c486
JR
387+}
388+
389+/**
fc63ffa9
AM
390+ * audit_net - audit network access
391+ * @profile: profile being enforced (NOT NULL)
392+ * @op: operation being checked
393+ * @family: network family
394+ * @type: network type
395+ * @protocol: network protocol
396+ * @sk: socket auditing is being applied to
397+ * @error: error code for failure else 0
ceaf2cfb 398+ *
fc63ffa9 399+ * Returns: %0 or sa->error else other errorcode on failure
2380c486 400+ */
fc63ffa9
AM
401+static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
402+ int protocol, struct sock *sk, int error)
2380c486 403+{
fc63ffa9
AM
404+ int audit_type = AUDIT_APPARMOR_AUTO;
405+ struct common_audit_data sa;
1e8b8f9b
AM
406+ struct apparmor_audit_data aad = { };
407+ struct lsm_network_audit net = { };
fc63ffa9 408+ if (sk) {
0c3ec466 409+ sa.type = LSM_AUDIT_DATA_NET;
fc63ffa9 410+ } else {
0c3ec466 411+ sa.type = LSM_AUDIT_DATA_NONE;
2380c486 412+ }
fc63ffa9 413+ /* todo fill in socket addr info */
1e8b8f9b
AM
414+ sa.aad = &aad;
415+ sa.u.net = &net;
416+ sa.aad->op = op,
417+ sa.u.net->family = family;
418+ sa.u.net->sk = sk;
419+ sa.aad->net.type = type;
420+ sa.aad->net.protocol = protocol;
421+ sa.aad->error = error;
422+
423+ if (likely(!sa.aad->error)) {
424+ u16 audit_mask = profile->net.audit[sa.u.net->family];
fc63ffa9 425+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
1e8b8f9b 426+ !(1 << sa.aad->net.type & audit_mask)))
ceaf2cfb 427+ return 0;
fc63ffa9
AM
428+ audit_type = AUDIT_APPARMOR_AUDIT;
429+ } else {
1e8b8f9b 430+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
fc63ffa9 431+ u16 kill_mask = 0;
1e8b8f9b 432+ u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
9474138d 433+
fc63ffa9
AM
434+ if (denied & kill_mask)
435+ audit_type = AUDIT_APPARMOR_KILL;
9474138d 436+
fc63ffa9
AM
437+ if ((denied & quiet_mask) &&
438+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
439+ AUDIT_MODE(profile) != AUDIT_ALL)
1e8b8f9b 440+ return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
9474138d
AM
441+ }
442+
fc63ffa9 443+ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
ceaf2cfb
AM
444+}
445+
2380c486 446+/**
fc63ffa9
AM
447+ * aa_net_perm - very course network access check
448+ * @op: operation being checked
449+ * @profile: profile being enforced (NOT NULL)
450+ * @family: network family
451+ * @type: network type
452+ * @protocol: network protocol
2380c486 453+ *
fc63ffa9 454+ * Returns: %0 else error if permission denied
2380c486 455+ */
fc63ffa9
AM
456+int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
457+ int protocol, struct sock *sk)
2380c486 458+{
fc63ffa9
AM
459+ u16 family_mask;
460+ int error;
ceaf2cfb 461+
fc63ffa9
AM
462+ if ((family < 0) || (family >= AF_MAX))
463+ return -EINVAL;
ceaf2cfb 464+
fc63ffa9
AM
465+ if ((type < 0) || (type >= SOCK_MAX))
466+ return -EINVAL;
76514441 467+
fc63ffa9
AM
468+ /* unix domain and netlink sockets are handled by ipc */
469+ if (family == AF_UNIX || family == AF_NETLINK)
470+ return 0;
76514441 471+
fc63ffa9 472+ family_mask = profile->net.allow[family];
2380c486 473+
fc63ffa9 474+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
ceaf2cfb 475+
fc63ffa9 476+ return audit_net(profile, op, family, type, protocol, sk, error);
2380c486
JR
477+}
478+
76514441 479+/**
fc63ffa9
AM
480+ * aa_revalidate_sk - Revalidate access to a sock
481+ * @op: operation being checked
482+ * @sk: sock being revalidated (NOT NULL)
76514441 483+ *
fc63ffa9 484+ * Returns: %0 else error if permission denied
76514441 485+ */
fc63ffa9 486+int aa_revalidate_sk(int op, struct sock *sk)
2380c486 487+{
fc63ffa9
AM
488+ struct aa_profile *profile;
489+ int error = 0;
2380c486 490+
fc63ffa9
AM
491+ /* aa_revalidate_sk should not be called from interrupt context
492+ * don't mediate these calls as they are not task related
493+ */
494+ if (in_interrupt())
495+ return 0;
ceaf2cfb 496+
fc63ffa9
AM
497+ profile = __aa_current_profile();
498+ if (!unconfined(profile))
499+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
500+ sk->sk_protocol, sk);
2380c486 501+
fc63ffa9 502+ return error;
2380c486 503+}
fc63ffa9 504diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
5882c9d4 505index 705c287..e2afe29 100644
fc63ffa9
AM
506--- a/security/apparmor/policy.c
507+++ b/security/apparmor/policy.c
5882c9d4 508@@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile)
fc63ffa9
AM
509
510 aa_free_file_rules(&profile->file);
511 aa_free_cap_rules(&profile->caps);
512+ aa_free_net_rules(&profile->net);
513 aa_free_rlimit_rules(&profile->rlimits);
514
5882c9d4 515 kzfree(profile->dirname);
fc63ffa9 516diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
5882c9d4 517index a689f10..1a35e6b 100644
fc63ffa9
AM
518--- a/security/apparmor/policy_unpack.c
519+++ b/security/apparmor/policy_unpack.c
1e8b8f9b 520@@ -193,6 +193,19 @@ fail:
fc63ffa9
AM
521 return 0;
522 }
523
524+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
2380c486 525+{
fc63ffa9
AM
526+ if (unpack_nameX(e, AA_U16, name)) {
527+ if (!inbounds(e, sizeof(u16)))
528+ return 0;
529+ if (data)
530+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
531+ e->pos += sizeof(u16);
532+ return 1;
2380c486 533+ }
2380c486
JR
534+ return 0;
535+}
536+
fc63ffa9
AM
537 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
538 {
539 if (unpack_nameX(e, AA_U32, name)) {
5882c9d4 540@@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
541 {
542 struct aa_profile *profile = NULL;
543 const char *name = NULL;
2380c486 544+ size_t size = 0;
1e8b8f9b 545 int i, error = -EPROTO;
fc63ffa9
AM
546 kernel_cap_t tmpcap;
547 u32 tmp;
5882c9d4 548@@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
fc63ffa9
AM
549 if (!unpack_rlimits(e, profile))
550 goto fail;
551
ceaf2cfb 552+ size = unpack_array(e, "net_allowed_af");
2380c486 553+ if (size) {
2380c486
JR
554+
555+ for (i = 0; i < size; i++) {
fc63ffa9
AM
556+ /* discard extraneous rules that this kernel will
557+ * never request
558+ */
1efb82ae 559+ if (i >= AF_MAX) {
fc63ffa9
AM
560+ u16 tmp;
561+ if (!unpack_u16(e, &tmp, NULL) ||
562+ !unpack_u16(e, &tmp, NULL) ||
563+ !unpack_u16(e, &tmp, NULL))
564+ goto fail;
565+ continue;
566+ }
76514441 567+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
2380c486 568+ goto fail;
ceaf2cfb 569+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
2380c486 570+ goto fail;
ceaf2cfb 571+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
2380c486
JR
572+ goto fail;
573+ }
ceaf2cfb 574+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
2380c486 575+ goto fail;
2380c486 576+ }
1e8b8f9b
AM
577+ /*
578+ * allow unix domain and netlink sockets they are handled
579+ * by IPC
580+ */
76514441
AM
581+ profile->net.allow[AF_UNIX] = 0xffff;
582+ profile->net.allow[AF_NETLINK] = 0xffff;
2380c486 583+
1e8b8f9b
AM
584 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
585 /* generic policy dfa - optional and may be NULL */
586 profile->policy.dfa = unpack_dfa(e);
0fa3db16 587--
c2c0f25c 588cgit v0.10.2
1e8b8f9b 589
c2c0f25c 590From 6b77d90baf3807b70ca17309ad6c0bd39f3297e7 Mon Sep 17 00:00:00 2001
5882c9d4
AM
591From: John Johansen <john.johansen@canonical.com>
592Date: Fri, 29 Jun 2012 17:34:00 -0700
c2c0f25c 593Subject: apparmor: Fix quieting of audit messages for network mediation
5882c9d4
AM
594
595If a profile specified a quieting of network denials for a given rule by
596either the quiet or deny rule qualifiers, the resultant quiet mask for
597denied requests was applied incorrectly, resulting in two potential bugs.
5981. 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
6022. 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
606Signed-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;
621--
c2c0f25c 622cgit v0.10.2
5882c9d4 623
c2c0f25c 624From a71049ba973b214e88eae89f9cb0c4965d184ead Mon Sep 17 00:00:00 2001
0fa3db16
AM
625From: John Johansen <john.johansen@canonical.com>
626Date: Wed, 16 May 2012 10:58:05 -0700
c2c0f25c 627Subject: UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
1e8b8f9b
AM
628
629Add the ability for apparmor to do mediation of mount operations. Mount
630rules require an updated apparmor_parser (2.8 series) for policy compilation.
631
632The basic form of the rules are.
633
634 [audit] [deny] mount [conds]* [device] [ -> [conds] path],
635 [audit] [deny] remount [conds]* [path],
636 [audit] [deny] umount [conds]* [path],
637 [audit] [deny] pivotroot [oldroot=<value>] <path>
638
639 remount is just a short cut for mount options=remount
640
641 where [conds] can be
642 fstype=<expr>
643 options=<expr>
644
645Example mount commands
646 mount, # allow all mounts, but not umount or pivotroot
647
648 mount fstype=procfs, # allow mounting procfs anywhere
649
650 mount options=(bind, ro) /foo -> /bar, # readonly bind mount
651
652 mount /dev/sda -> /mnt,
653
654 mount /dev/sd** -> /mnt/**,
655
656 mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
657
658 umount,
659
660 umount /m*,
661
662See the apparmor userspace for full documentation
fc63ffa9
AM
663
664Signed-off-by: John Johansen <john.johansen@canonical.com>
1e8b8f9b 665Acked-by: Kees Cook <kees@ubuntu.com>
5882c9d4 666
fc63ffa9 667diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
5882c9d4 668index 5dbb72f..89b3445 100644
fc63ffa9
AM
669--- a/security/apparmor/Makefile
670+++ b/security/apparmor/Makefile
1e8b8f9b
AM
671@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
672
948a1326 673 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
fc63ffa9 674 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
1e8b8f9b
AM
675- resource.o sid.o file.o net.o
676+ resource.o sid.o file.o net.o mount.o
5882c9d4 677 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
fc63ffa9 678
1e8b8f9b 679 clean-files := capability_names.h rlim_names.h net_names.h
1e8b8f9b 680diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
c2c0f25c 681index 6362c5a..4917747 100644
1e8b8f9b
AM
682--- a/security/apparmor/apparmorfs.c
683+++ b/security/apparmor/apparmorfs.c
5882c9d4 684@@ -799,7 +799,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
1e8b8f9b 685
5882c9d4
AM
686 static struct aa_fs_entry aa_fs_entry_policy[] = {
687 AA_FS_FILE_BOOLEAN("set_load", 1),
688- {}
689+ { }
690+};
691+
1e8b8f9b
AM
692+static struct aa_fs_entry aa_fs_entry_mount[] = {
693+ AA_FS_FILE_STRING("mask", "mount umount"),
694+ { }
695+};
696+
697+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
698+ AA_FS_FILE_BOOLEAN("profile", 1),
699+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
700+ { }
5882c9d4
AM
701 };
702
1e8b8f9b 703 static struct aa_fs_entry aa_fs_entry_features[] = {
5882c9d4 704@@ -807,6 +818,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
1e8b8f9b
AM
705 AA_FS_DIR("domain", aa_fs_entry_domain),
706 AA_FS_DIR("file", aa_fs_entry_file),
707 AA_FS_DIR("network", aa_fs_entry_network),
708+ AA_FS_DIR("mount", aa_fs_entry_mount),
709+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
710 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
711 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
5882c9d4 712 AA_FS_DIR("caps", aa_fs_entry_caps),
1e8b8f9b 713diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
c2c0f25c 714index 89c7865..7fdb5d7 100644
1e8b8f9b
AM
715--- a/security/apparmor/audit.c
716+++ b/security/apparmor/audit.c
717@@ -44,6 +44,10 @@ const char *const op_table[] = {
718 "file_mmap",
719 "file_mprotect",
720
721+ "pivotroot",
722+ "mount",
723+ "umount",
724+
725 "create",
726 "post_create",
727 "bind",
728diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
c2c0f25c 729index dc0027b..a2e3813 100644
1e8b8f9b
AM
730--- a/security/apparmor/domain.c
731+++ b/security/apparmor/domain.c
c2c0f25c 732@@ -236,7 +236,7 @@ static const char *next_name(int xtype, const char *name)
1e8b8f9b
AM
733 *
734 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
735 */
736-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
737+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
738 {
739 struct aa_profile *new_profile = NULL;
740 struct aa_namespace *ns = profile->ns;
741diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
c2c0f25c 742index e4ea626..ce6ff6a 100644
1e8b8f9b
AM
743--- a/security/apparmor/include/apparmor.h
744+++ b/security/apparmor/include/apparmor.h
5882c9d4 745@@ -30,8 +30,9 @@
1e8b8f9b
AM
746 #define AA_CLASS_NET 4
747 #define AA_CLASS_RLIMITS 5
748 #define AA_CLASS_DOMAIN 6
749+#define AA_CLASS_MOUNT 7
750
751-#define AA_CLASS_LAST AA_CLASS_DOMAIN
752+#define AA_CLASS_LAST AA_CLASS_MOUNT
753
754 /* Control parameters settable through module/boot flags */
755 extern enum audit_mode aa_g_audit;
756diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
c2c0f25c 757index 5d3c419..b9f1d57 100644
1e8b8f9b
AM
758--- a/security/apparmor/include/audit.h
759+++ b/security/apparmor/include/audit.h
5882c9d4 760@@ -72,6 +72,10 @@ enum aa_ops {
1e8b8f9b
AM
761 OP_FMMAP,
762 OP_FMPROT,
763
764+ OP_PIVOTROOT,
765+ OP_MOUNT,
766+ OP_UMOUNT,
767+
768 OP_CREATE,
769 OP_POST_CREATE,
770 OP_BIND,
c2c0f25c 771@@ -120,6 +124,13 @@ struct apparmor_audit_data {
1e8b8f9b
AM
772 unsigned long max;
773 } rlim;
774 struct {
775+ const char *src_name;
776+ const char *type;
777+ const char *trans;
778+ const char *data;
779+ unsigned long flags;
780+ } mnt;
781+ struct {
782 const char *target;
783 u32 request;
784 u32 denied;
785diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
786index de04464..a3f70c5 100644
787--- a/security/apparmor/include/domain.h
788+++ b/security/apparmor/include/domain.h
789@@ -23,6 +23,8 @@ struct aa_domain {
790 char **table;
791 };
792
793+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
794+
795 int apparmor_bprm_set_creds(struct linux_binprm *bprm);
796 int apparmor_bprm_secureexec(struct linux_binprm *bprm);
797 void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
798diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
ceaf2cfb 799new file mode 100644
1e8b8f9b 800index 0000000..bc17a53
ceaf2cfb 801--- /dev/null
1e8b8f9b
AM
802+++ b/security/apparmor/include/mount.h
803@@ -0,0 +1,54 @@
2380c486 804+/*
9474138d
AM
805+ * AppArmor security module
806+ *
1e8b8f9b 807+ * This file contains AppArmor file mediation function definitions.
2380c486 808+ *
1e8b8f9b 809+ * Copyright 2012 Canonical Ltd.
2380c486 810+ *
9474138d
AM
811+ * This program is free software; you can redistribute it and/or
812+ * modify it under the terms of the GNU General Public License as
813+ * published by the Free Software Foundation, version 2 of the
814+ * License.
2380c486
JR
815+ */
816+
1e8b8f9b
AM
817+#ifndef __AA_MOUNT_H
818+#define __AA_MOUNT_H
fc63ffa9 819+
1e8b8f9b
AM
820+#include <linux/fs.h>
821+#include <linux/path.h>
2380c486 822+
1e8b8f9b
AM
823+#include "domain.h"
824+#include "policy.h"
76514441 825+
1e8b8f9b
AM
826+/* mount perms */
827+#define AA_MAY_PIVOTROOT 0x01
828+#define AA_MAY_MOUNT 0x02
829+#define AA_MAY_UMOUNT 0x04
830+#define AA_AUDIT_DATA 0x40
831+#define AA_CONT_MATCH 0x40
fc63ffa9 832+
1e8b8f9b 833+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
fc63ffa9 834+
1e8b8f9b
AM
835+int aa_remount(struct aa_profile *profile, struct path *path,
836+ unsigned long flags, void *data);
fc63ffa9 837+
1e8b8f9b
AM
838+int aa_bind_mount(struct aa_profile *profile, struct path *path,
839+ const char *old_name, unsigned long flags);
fc63ffa9 840+
fc63ffa9 841+
1e8b8f9b
AM
842+int aa_mount_change_type(struct aa_profile *profile, struct path *path,
843+ unsigned long flags);
fc63ffa9 844+
1e8b8f9b
AM
845+int aa_move_mount(struct aa_profile *profile, struct path *path,
846+ const char *old_name);
847+
848+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
849+ struct path *path, const char *type, unsigned long flags,
850+ void *data);
851+
852+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
853+
854+int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
855+ struct path *new_path);
856+
857+#endif /* __AA_MOUNT_H */
858diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
c2c0f25c 859index 47fd244..fb92441 100644
1e8b8f9b
AM
860--- a/security/apparmor/lsm.c
861+++ b/security/apparmor/lsm.c
862@@ -36,6 +36,7 @@
863 #include "include/path.h"
864 #include "include/policy.h"
865 #include "include/procattr.h"
866+#include "include/mount.h"
867
868 /* Flag indicating whether initialization completed */
869 int apparmor_initialized __initdata;
c2c0f25c 870@@ -492,6 +493,60 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
1e8b8f9b
AM
871 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
872 }
873
874+static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
875+ unsigned long flags, void *data)
2380c486 876+{
1e8b8f9b
AM
877+ struct aa_profile *profile;
878+ int error = 0;
76514441 879+
1e8b8f9b
AM
880+ /* Discard magic */
881+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
882+ flags &= ~MS_MGC_MSK;
2380c486 883+
1e8b8f9b
AM
884+ flags &= ~AA_MS_IGNORE_MASK;
885+
886+ profile = __aa_current_profile();
887+ if (!unconfined(profile)) {
888+ if (flags & MS_REMOUNT)
889+ error = aa_remount(profile, path, flags, data);
890+ else if (flags & MS_BIND)
891+ error = aa_bind_mount(profile, path, dev_name, flags);
892+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
893+ MS_UNBINDABLE))
894+ error = aa_mount_change_type(profile, path, flags);
895+ else if (flags & MS_MOVE)
896+ error = aa_move_mount(profile, path, dev_name);
897+ else
898+ error = aa_new_mount(profile, dev_name, path, type,
899+ flags, data);
2380c486 900+ }
1e8b8f9b
AM
901+ return error;
902+}
2380c486 903+
1e8b8f9b
AM
904+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
905+{
906+ struct aa_profile *profile;
907+ int error = 0;
908+
909+ profile = __aa_current_profile();
910+ if (!unconfined(profile))
911+ error = aa_umount(profile, mnt, flags);
912+
913+ return error;
2380c486
JR
914+}
915+
1e8b8f9b 916+static int apparmor_sb_pivotroot(struct path *old_path, 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 {
c2c0f25c
AM
931@@ -710,6 +765,10 @@ static struct security_hook_list apparmor_hooks[] = {
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
2dfbb274 944index 0000000..478aa4d
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+
1e8b8f9b
AM
1280+static int path_flags(struct aa_profile *profile, struct path *path)
1281+{
1282+ return profile->path_flags |
1283+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
1284+}
9474138d 1285+
1e8b8f9b
AM
1286+int aa_remount(struct aa_profile *profile, struct path *path,
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+
1e8b8f9b
AM
1313+int aa_bind_mount(struct aa_profile *profile, struct path *path,
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+
1e8b8f9b
AM
1355+int aa_mount_change_type(struct aa_profile *profile, struct path *path,
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+
1384+int aa_move_mount(struct aa_profile *profile, struct path *path,
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,
1425+ struct path *path, const char *type, unsigned long flags,
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+
1518+int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
1519+ struct path *new_path)
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+}
0fa3db16 1568--
c2c0f25c 1569cgit v0.10.2
0fa3db16 1570
This page took 0.428973 seconds and 4 git commands to generate.