The AppArmor source code distributes out-of-tree kernel patches that
are needed in order to support the full functionality of AppArmor.
So, import those kernel patches from the latest available version of
AppArmor, i.e., v2.13.
Change-Id: I7bee0aece63b980a2cb36b053a9d8f28d934a993
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/5378
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Sharath George
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,607 @@ |
0 |
+From 20f953a08580786932c6b2c214c7dc2e2f99cf75 Mon Sep 17 00:00:00 2001 |
|
1 |
+From: John Johansen <john.johansen@canonical.com> |
|
2 |
+Date: Mon, 4 Oct 2010 15:03:36 -0700 |
|
3 |
+Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules |
|
4 |
+ |
|
5 |
+[ This is an out-of-tree patch distributed with the AppArmor source |
|
6 |
+ code (v2.13) ] |
|
7 |
+ |
|
8 |
+Base support for network mediation. |
|
9 |
+ |
|
10 |
+Signed-off-by: John Johansen <john.johansen@canonical.com> |
|
11 |
+Signed-off-by: Srivatsa S. Bhat <srivatsa@csail.mit.edu> |
|
12 |
+--- |
|
13 |
+ security/apparmor/.gitignore | 1 + |
|
14 |
+ security/apparmor/Makefile | 42 +++++++++- |
|
15 |
+ security/apparmor/apparmorfs.c | 1 + |
|
16 |
+ security/apparmor/include/audit.h | 4 + |
|
17 |
+ security/apparmor/include/net.h | 44 ++++++++++ |
|
18 |
+ security/apparmor/include/policy.h | 3 + |
|
19 |
+ security/apparmor/lsm.c | 112 +++++++++++++++++++++++++ |
|
20 |
+ security/apparmor/net.c | 162 +++++++++++++++++++++++++++++++++++++ |
|
21 |
+ security/apparmor/policy.c | 1 + |
|
22 |
+ security/apparmor/policy_unpack.c | 46 +++++++++++ |
|
23 |
+ 10 files changed, 414 insertions(+), 2 deletions(-) |
|
24 |
+ create mode 100644 security/apparmor/include/net.h |
|
25 |
+ create mode 100644 security/apparmor/net.c |
|
26 |
+ |
|
27 |
+diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore |
|
28 |
+index 9cdec70..d5b291e 100644 |
|
29 |
+--- a/security/apparmor/.gitignore |
|
30 |
+@@ -1,5 +1,6 @@ |
|
31 |
+ # |
|
32 |
+ # Generated include files |
|
33 |
+ # |
|
34 |
++net_names.h |
|
35 |
+ capability_names.h |
|
36 |
+ rlim_names.h |
|
37 |
+diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile |
|
38 |
+index d693df8..5dbb72f 100644 |
|
39 |
+--- a/security/apparmor/Makefile |
|
40 |
+@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o |
|
41 |
+ |
|
42 |
+ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ |
|
43 |
+ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ |
|
44 |
+- resource.o sid.o file.o |
|
45 |
++ resource.o sid.o file.o net.o |
|
46 |
+ apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o |
|
47 |
+ |
|
48 |
+-clean-files := capability_names.h rlim_names.h |
|
49 |
++clean-files := capability_names.h rlim_names.h net_names.h |
|
50 |
+ |
|
51 |
+ |
|
52 |
+ # Build a lower case string table of capability names |
|
53 |
+@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\ |
|
54 |
+ -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \ |
|
55 |
+ tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ |
|
56 |
+ |
|
57 |
++# Build a lower case string table of address family names |
|
58 |
++# Transform lines from |
|
59 |
++# define AF_LOCAL 1 /* POSIX name for AF_UNIX */ |
|
60 |
++# #define AF_INET 2 /* Internet IP Protocol */ |
|
61 |
++# to |
|
62 |
++# [1] = "local", |
|
63 |
++# [2] = "inet", |
|
64 |
++# |
|
65 |
++# and build the securityfs entries for the mapping. |
|
66 |
++# Transforms lines from |
|
67 |
++# #define AF_INET 2 /* Internet IP Protocol */ |
|
68 |
++# to |
|
69 |
++# #define AA_FS_AF_MASK "local inet" |
|
70 |
++quiet_cmd_make-af = GEN $@ |
|
71 |
++cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ |
|
72 |
++ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \ |
|
73 |
++ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ |
|
74 |
++ echo "};" >> $@ ;\ |
|
75 |
++ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\ |
|
76 |
++ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\ |
|
77 |
++ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ |
|
78 |
++ |
|
79 |
++# Build a lower case string table of sock type names |
|
80 |
++# Transform lines from |
|
81 |
++# SOCK_STREAM = 1, |
|
82 |
++# to |
|
83 |
++# [1] = "stream", |
|
84 |
++quiet_cmd_make-sock = GEN $@ |
|
85 |
++cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ |
|
86 |
++ sed $^ >>$@ -r -n \ |
|
87 |
++ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ |
|
88 |
++ echo "};" >> $@ |
|
89 |
+ |
|
90 |
+ # Build a lower case string table of rlimit names. |
|
91 |
+ # Transforms lines from |
|
92 |
+@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ |
|
93 |
+ tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ |
|
94 |
+ |
|
95 |
+ $(obj)/capability.o : $(obj)/capability_names.h |
|
96 |
++$(obj)/net.o : $(obj)/net_names.h |
|
97 |
+ $(obj)/resource.o : $(obj)/rlim_names.h |
|
98 |
+ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ |
|
99 |
+ $(src)/Makefile |
|
100 |
+@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ |
|
101 |
+ $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ |
|
102 |
+ $(src)/Makefile |
|
103 |
+ $(call cmd,make-rlim) |
|
104 |
++$(obj)/net_names.h : $(srctree)/include/linux/socket.h \ |
|
105 |
++ $(srctree)/include/linux/net.h \ |
|
106 |
++ $(src)/Makefile |
|
107 |
++ $(call cmd,make-af) |
|
108 |
++ $(call cmd,make-sock) |
|
109 |
+diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c |
|
110 |
+index 5923d56..bd558db 100644 |
|
111 |
+--- a/security/apparmor/apparmorfs.c |
|
112 |
+@@ -807,6 +807,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = { |
|
113 |
+ AA_FS_DIR("policy", aa_fs_entry_policy), |
|
114 |
+ AA_FS_DIR("domain", aa_fs_entry_domain), |
|
115 |
+ AA_FS_DIR("file", aa_fs_entry_file), |
|
116 |
++ AA_FS_DIR("network", aa_fs_entry_network), |
|
117 |
+ AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), |
|
118 |
+ AA_FS_DIR("rlimit", aa_fs_entry_rlimit), |
|
119 |
+ AA_FS_DIR("caps", aa_fs_entry_caps), |
|
120 |
+diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h |
|
121 |
+index ba3dfd1..5d3c419 100644 |
|
122 |
+--- a/security/apparmor/include/audit.h |
|
123 |
+@@ -125,6 +125,10 @@ struct apparmor_audit_data { |
|
124 |
+ u32 denied; |
|
125 |
+ kuid_t ouid; |
|
126 |
+ } fs; |
|
127 |
++ struct { |
|
128 |
++ int type, protocol; |
|
129 |
++ struct sock *sk; |
|
130 |
++ } net; |
|
131 |
+ }; |
|
132 |
+ }; |
|
133 |
+ |
|
134 |
+diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h |
|
135 |
+new file mode 100644 |
|
136 |
+index 0000000..cb8a121 |
|
137 |
+--- /dev/null |
|
138 |
+@@ -0,0 +1,44 @@ |
|
139 |
++/* |
|
140 |
++ * AppArmor security module |
|
141 |
++ * |
|
142 |
++ * This file contains AppArmor network mediation definitions. |
|
143 |
++ * |
|
144 |
++ * Copyright (C) 1998-2008 Novell/SUSE |
|
145 |
++ * Copyright 2009-2012 Canonical Ltd. |
|
146 |
++ * |
|
147 |
++ * This program is free software; you can redistribute it and/or |
|
148 |
++ * modify it under the terms of the GNU General Public License as |
|
149 |
++ * published by the Free Software Foundation, version 2 of the |
|
150 |
++ * License. |
|
151 |
++ */ |
|
152 |
++ |
|
153 |
++#ifndef __AA_NET_H |
|
154 |
++#define __AA_NET_H |
|
155 |
++ |
|
156 |
++#include <net/sock.h> |
|
157 |
++ |
|
158 |
++#include "apparmorfs.h" |
|
159 |
++ |
|
160 |
++/* struct aa_net - network confinement data |
|
161 |
++ * @allowed: basic network families permissions |
|
162 |
++ * @audit_network: which network permissions to force audit |
|
163 |
++ * @quiet_network: which network permissions to quiet rejects |
|
164 |
++ */ |
|
165 |
++struct aa_net { |
|
166 |
++ u16 allow[AF_MAX]; |
|
167 |
++ u16 audit[AF_MAX]; |
|
168 |
++ u16 quiet[AF_MAX]; |
|
169 |
++}; |
|
170 |
++ |
|
171 |
++extern struct aa_fs_entry aa_fs_entry_network[]; |
|
172 |
++ |
|
173 |
++extern int aa_net_perm(int op, struct aa_profile *profile, u16 family, |
|
174 |
++ int type, int protocol, struct sock *sk); |
|
175 |
++extern int aa_revalidate_sk(int op, struct sock *sk); |
|
176 |
++ |
|
177 |
++static inline void aa_free_net_rules(struct aa_net *new) |
|
178 |
++{ |
|
179 |
++ /* NOP */ |
|
180 |
++} |
|
181 |
++ |
|
182 |
++#endif /* __AA_NET_H */ |
|
183 |
+diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h |
|
184 |
+index 52275f0..4fc4dac 100644 |
|
185 |
+--- a/security/apparmor/include/policy.h |
|
186 |
+@@ -27,6 +27,7 @@ |
|
187 |
+ #include "capability.h" |
|
188 |
+ #include "domain.h" |
|
189 |
+ #include "file.h" |
|
190 |
++#include "net.h" |
|
191 |
+ #include "resource.h" |
|
192 |
+ |
|
193 |
+ extern const char *const aa_profile_mode_names[]; |
|
194 |
+@@ -176,6 +177,7 @@ struct aa_replacedby { |
|
195 |
+ * @policy: general match rules governing policy |
|
196 |
+ * @file: The set of rules governing basic file access and domain transitions |
|
197 |
+ * @caps: capabilities for the profile |
|
198 |
++ * @net: network controls for the profile |
|
199 |
+ * @rlimits: rlimits for the profile |
|
200 |
+ * |
|
201 |
+ * @dents: dentries for the profiles file entries in apparmorfs |
|
202 |
+@@ -217,6 +219,7 @@ struct aa_profile { |
|
203 |
+ struct aa_policydb policy; |
|
204 |
+ struct aa_file_rules file; |
|
205 |
+ struct aa_caps caps; |
|
206 |
++ struct aa_net net; |
|
207 |
+ struct aa_rlimit rlimits; |
|
208 |
+ |
|
209 |
+ unsigned char *hash; |
|
210 |
+diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c |
|
211 |
+index 02cc952..de3b68a 100644 |
|
212 |
+--- a/security/apparmor/lsm.c |
|
213 |
+@@ -32,6 +32,7 @@ |
|
214 |
+ #include "include/context.h" |
|
215 |
+ #include "include/file.h" |
|
216 |
+ #include "include/ipc.h" |
|
217 |
++#include "include/net.h" |
|
218 |
+ #include "include/path.h" |
|
219 |
+ #include "include/policy.h" |
|
220 |
+ #include "include/procattr.h" |
|
221 |
+@@ -584,6 +585,104 @@ static int apparmor_task_setrlimit(struct task_struct *task, |
|
222 |
+ return error; |
|
223 |
+ } |
|
224 |
+ |
|
225 |
++static int apparmor_socket_create(int family, int type, int protocol, int kern) |
|
226 |
++{ |
|
227 |
++ struct aa_profile *profile; |
|
228 |
++ int error = 0; |
|
229 |
++ |
|
230 |
++ if (kern) |
|
231 |
++ return 0; |
|
232 |
++ |
|
233 |
++ profile = __aa_current_profile(); |
|
234 |
++ if (!unconfined(profile)) |
|
235 |
++ error = aa_net_perm(OP_CREATE, profile, family, type, protocol, |
|
236 |
++ NULL); |
|
237 |
++ return error; |
|
238 |
++} |
|
239 |
++ |
|
240 |
++static int apparmor_socket_bind(struct socket *sock, |
|
241 |
++ struct sockaddr *address, int addrlen) |
|
242 |
++{ |
|
243 |
++ struct sock *sk = sock->sk; |
|
244 |
++ |
|
245 |
++ return aa_revalidate_sk(OP_BIND, sk); |
|
246 |
++} |
|
247 |
++ |
|
248 |
++static int apparmor_socket_connect(struct socket *sock, |
|
249 |
++ struct sockaddr *address, int addrlen) |
|
250 |
++{ |
|
251 |
++ struct sock *sk = sock->sk; |
|
252 |
++ |
|
253 |
++ return aa_revalidate_sk(OP_CONNECT, sk); |
|
254 |
++} |
|
255 |
++ |
|
256 |
++static int apparmor_socket_listen(struct socket *sock, int backlog) |
|
257 |
++{ |
|
258 |
++ struct sock *sk = sock->sk; |
|
259 |
++ |
|
260 |
++ return aa_revalidate_sk(OP_LISTEN, sk); |
|
261 |
++} |
|
262 |
++ |
|
263 |
++static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) |
|
264 |
++{ |
|
265 |
++ struct sock *sk = sock->sk; |
|
266 |
++ |
|
267 |
++ return aa_revalidate_sk(OP_ACCEPT, sk); |
|
268 |
++} |
|
269 |
++ |
|
270 |
++static int apparmor_socket_sendmsg(struct socket *sock, |
|
271 |
++ struct msghdr *msg, int size) |
|
272 |
++{ |
|
273 |
++ struct sock *sk = sock->sk; |
|
274 |
++ |
|
275 |
++ return aa_revalidate_sk(OP_SENDMSG, sk); |
|
276 |
++} |
|
277 |
++ |
|
278 |
++static int apparmor_socket_recvmsg(struct socket *sock, |
|
279 |
++ struct msghdr *msg, int size, int flags) |
|
280 |
++{ |
|
281 |
++ struct sock *sk = sock->sk; |
|
282 |
++ |
|
283 |
++ return aa_revalidate_sk(OP_RECVMSG, sk); |
|
284 |
++} |
|
285 |
++ |
|
286 |
++static int apparmor_socket_getsockname(struct socket *sock) |
|
287 |
++{ |
|
288 |
++ struct sock *sk = sock->sk; |
|
289 |
++ |
|
290 |
++ return aa_revalidate_sk(OP_GETSOCKNAME, sk); |
|
291 |
++} |
|
292 |
++ |
|
293 |
++static int apparmor_socket_getpeername(struct socket *sock) |
|
294 |
++{ |
|
295 |
++ struct sock *sk = sock->sk; |
|
296 |
++ |
|
297 |
++ return aa_revalidate_sk(OP_GETPEERNAME, sk); |
|
298 |
++} |
|
299 |
++ |
|
300 |
++static int apparmor_socket_getsockopt(struct socket *sock, int level, |
|
301 |
++ int optname) |
|
302 |
++{ |
|
303 |
++ struct sock *sk = sock->sk; |
|
304 |
++ |
|
305 |
++ return aa_revalidate_sk(OP_GETSOCKOPT, sk); |
|
306 |
++} |
|
307 |
++ |
|
308 |
++static int apparmor_socket_setsockopt(struct socket *sock, int level, |
|
309 |
++ int optname) |
|
310 |
++{ |
|
311 |
++ struct sock *sk = sock->sk; |
|
312 |
++ |
|
313 |
++ return aa_revalidate_sk(OP_SETSOCKOPT, sk); |
|
314 |
++} |
|
315 |
++ |
|
316 |
++static int apparmor_socket_shutdown(struct socket *sock, int how) |
|
317 |
++{ |
|
318 |
++ struct sock *sk = sock->sk; |
|
319 |
++ |
|
320 |
++ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk); |
|
321 |
++} |
|
322 |
++ |
|
323 |
+ static struct security_hook_list apparmor_hooks[] = { |
|
324 |
+ LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), |
|
325 |
+ LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), |
|
326 |
+@@ -613,6 +712,19 @@ static struct security_hook_list apparmor_hooks[] = { |
|
327 |
+ LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), |
|
328 |
+ LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), |
|
329 |
+ |
|
330 |
++ LSM_HOOK_INIT(socket_create, apparmor_socket_create), |
|
331 |
++ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), |
|
332 |
++ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), |
|
333 |
++ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), |
|
334 |
++ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept), |
|
335 |
++ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg), |
|
336 |
++ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg), |
|
337 |
++ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname), |
|
338 |
++ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername), |
|
339 |
++ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), |
|
340 |
++ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), |
|
341 |
++ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), |
|
342 |
++ |
|
343 |
+ LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), |
|
344 |
+ LSM_HOOK_INIT(cred_free, apparmor_cred_free), |
|
345 |
+ LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), |
|
346 |
+diff --git a/security/apparmor/net.c b/security/apparmor/net.c |
|
347 |
+new file mode 100644 |
|
348 |
+index 0000000..003dd18 |
|
349 |
+--- /dev/null |
|
350 |
+@@ -0,0 +1,162 @@ |
|
351 |
++/* |
|
352 |
++ * AppArmor security module |
|
353 |
++ * |
|
354 |
++ * This file contains AppArmor network mediation |
|
355 |
++ * |
|
356 |
++ * Copyright (C) 1998-2008 Novell/SUSE |
|
357 |
++ * Copyright 2009-2012 Canonical Ltd. |
|
358 |
++ * |
|
359 |
++ * This program is free software; you can redistribute it and/or |
|
360 |
++ * modify it under the terms of the GNU General Public License as |
|
361 |
++ * published by the Free Software Foundation, version 2 of the |
|
362 |
++ * License. |
|
363 |
++ */ |
|
364 |
++ |
|
365 |
++#include "include/apparmor.h" |
|
366 |
++#include "include/audit.h" |
|
367 |
++#include "include/context.h" |
|
368 |
++#include "include/net.h" |
|
369 |
++#include "include/policy.h" |
|
370 |
++ |
|
371 |
++#include "net_names.h" |
|
372 |
++ |
|
373 |
++struct aa_fs_entry aa_fs_entry_network[] = { |
|
374 |
++ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK), |
|
375 |
++ { } |
|
376 |
++}; |
|
377 |
++ |
|
378 |
++/* audit callback for net specific fields */ |
|
379 |
++static void audit_cb(struct audit_buffer *ab, void *va) |
|
380 |
++{ |
|
381 |
++ struct common_audit_data *sa = va; |
|
382 |
++ |
|
383 |
++ audit_log_format(ab, " family="); |
|
384 |
++ if (address_family_names[sa->u.net->family]) { |
|
385 |
++ audit_log_string(ab, address_family_names[sa->u.net->family]); |
|
386 |
++ } else { |
|
387 |
++ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family); |
|
388 |
++ } |
|
389 |
++ audit_log_format(ab, " sock_type="); |
|
390 |
++ if (sock_type_names[sa->aad->net.type]) { |
|
391 |
++ audit_log_string(ab, sock_type_names[sa->aad->net.type]); |
|
392 |
++ } else { |
|
393 |
++ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type); |
|
394 |
++ } |
|
395 |
++ audit_log_format(ab, " protocol=%d", sa->aad->net.protocol); |
|
396 |
++} |
|
397 |
++ |
|
398 |
++/** |
|
399 |
++ * audit_net - audit network access |
|
400 |
++ * @profile: profile being enforced (NOT NULL) |
|
401 |
++ * @op: operation being checked |
|
402 |
++ * @family: network family |
|
403 |
++ * @type: network type |
|
404 |
++ * @protocol: network protocol |
|
405 |
++ * @sk: socket auditing is being applied to |
|
406 |
++ * @error: error code for failure else 0 |
|
407 |
++ * |
|
408 |
++ * Returns: %0 or sa->error else other errorcode on failure |
|
409 |
++ */ |
|
410 |
++static int audit_net(struct aa_profile *profile, int op, u16 family, int type, |
|
411 |
++ int protocol, struct sock *sk, int error) |
|
412 |
++{ |
|
413 |
++ int audit_type = AUDIT_APPARMOR_AUTO; |
|
414 |
++ struct common_audit_data sa; |
|
415 |
++ struct apparmor_audit_data aad = { }; |
|
416 |
++ struct lsm_network_audit net = { }; |
|
417 |
++ if (sk) { |
|
418 |
++ sa.type = LSM_AUDIT_DATA_NET; |
|
419 |
++ } else { |
|
420 |
++ sa.type = LSM_AUDIT_DATA_NONE; |
|
421 |
++ } |
|
422 |
++ /* todo fill in socket addr info */ |
|
423 |
++ sa.aad = &aad; |
|
424 |
++ sa.u.net = &net; |
|
425 |
++ sa.aad->op = op, |
|
426 |
++ sa.u.net->family = family; |
|
427 |
++ sa.u.net->sk = sk; |
|
428 |
++ sa.aad->net.type = type; |
|
429 |
++ sa.aad->net.protocol = protocol; |
|
430 |
++ sa.aad->error = error; |
|
431 |
++ |
|
432 |
++ if (likely(!sa.aad->error)) { |
|
433 |
++ u16 audit_mask = profile->net.audit[sa.u.net->family]; |
|
434 |
++ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && |
|
435 |
++ !(1 << sa.aad->net.type & audit_mask))) |
|
436 |
++ return 0; |
|
437 |
++ audit_type = AUDIT_APPARMOR_AUDIT; |
|
438 |
++ } else { |
|
439 |
++ u16 quiet_mask = profile->net.quiet[sa.u.net->family]; |
|
440 |
++ u16 kill_mask = 0; |
|
441 |
++ u16 denied = (1 << sa.aad->net.type) & ~quiet_mask; |
|
442 |
++ |
|
443 |
++ if (denied & kill_mask) |
|
444 |
++ audit_type = AUDIT_APPARMOR_KILL; |
|
445 |
++ |
|
446 |
++ if ((denied & quiet_mask) && |
|
447 |
++ AUDIT_MODE(profile) != AUDIT_NOQUIET && |
|
448 |
++ AUDIT_MODE(profile) != AUDIT_ALL) |
|
449 |
++ return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; |
|
450 |
++ } |
|
451 |
++ |
|
452 |
++ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb); |
|
453 |
++} |
|
454 |
++ |
|
455 |
++/** |
|
456 |
++ * aa_net_perm - very course network access check |
|
457 |
++ * @op: operation being checked |
|
458 |
++ * @profile: profile being enforced (NOT NULL) |
|
459 |
++ * @family: network family |
|
460 |
++ * @type: network type |
|
461 |
++ * @protocol: network protocol |
|
462 |
++ * |
|
463 |
++ * Returns: %0 else error if permission denied |
|
464 |
++ */ |
|
465 |
++int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type, |
|
466 |
++ int protocol, struct sock *sk) |
|
467 |
++{ |
|
468 |
++ u16 family_mask; |
|
469 |
++ int error; |
|
470 |
++ |
|
471 |
++ if ((family < 0) || (family >= AF_MAX)) |
|
472 |
++ return -EINVAL; |
|
473 |
++ |
|
474 |
++ if ((type < 0) || (type >= SOCK_MAX)) |
|
475 |
++ return -EINVAL; |
|
476 |
++ |
|
477 |
++ /* unix domain and netlink sockets are handled by ipc */ |
|
478 |
++ if (family == AF_UNIX || family == AF_NETLINK) |
|
479 |
++ return 0; |
|
480 |
++ |
|
481 |
++ family_mask = profile->net.allow[family]; |
|
482 |
++ |
|
483 |
++ error = (family_mask & (1 << type)) ? 0 : -EACCES; |
|
484 |
++ |
|
485 |
++ return audit_net(profile, op, family, type, protocol, sk, error); |
|
486 |
++} |
|
487 |
++ |
|
488 |
++/** |
|
489 |
++ * aa_revalidate_sk - Revalidate access to a sock |
|
490 |
++ * @op: operation being checked |
|
491 |
++ * @sk: sock being revalidated (NOT NULL) |
|
492 |
++ * |
|
493 |
++ * Returns: %0 else error if permission denied |
|
494 |
++ */ |
|
495 |
++int aa_revalidate_sk(int op, struct sock *sk) |
|
496 |
++{ |
|
497 |
++ struct aa_profile *profile; |
|
498 |
++ int error = 0; |
|
499 |
++ |
|
500 |
++ /* aa_revalidate_sk should not be called from interrupt context |
|
501 |
++ * don't mediate these calls as they are not task related |
|
502 |
++ */ |
|
503 |
++ if (in_interrupt()) |
|
504 |
++ return 0; |
|
505 |
++ |
|
506 |
++ profile = __aa_current_profile(); |
|
507 |
++ if (!unconfined(profile)) |
|
508 |
++ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type, |
|
509 |
++ sk->sk_protocol, sk); |
|
510 |
++ |
|
511 |
++ return error; |
|
512 |
++} |
|
513 |
+diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c |
|
514 |
+index 179e68d..f1a8541 100644 |
|
515 |
+--- a/security/apparmor/policy.c |
|
516 |
+@@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile) |
|
517 |
+ |
|
518 |
+ aa_free_file_rules(&profile->file); |
|
519 |
+ aa_free_cap_rules(&profile->caps); |
|
520 |
++ aa_free_net_rules(&profile->net); |
|
521 |
+ aa_free_rlimit_rules(&profile->rlimits); |
|
522 |
+ |
|
523 |
+ kzfree(profile->dirname); |
|
524 |
+diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c |
|
525 |
+index 1381206..7dc15ff 100644 |
|
526 |
+--- a/security/apparmor/policy_unpack.c |
|
527 |
+@@ -193,6 +193,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name) |
|
528 |
+ return 0; |
|
529 |
+ } |
|
530 |
+ |
|
531 |
++static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) |
|
532 |
++{ |
|
533 |
++ if (unpack_nameX(e, AA_U16, name)) { |
|
534 |
++ if (!inbounds(e, sizeof(u16))) |
|
535 |
++ return 0; |
|
536 |
++ if (data) |
|
537 |
++ *data = le16_to_cpu(get_unaligned((u16 *) e->pos)); |
|
538 |
++ e->pos += sizeof(u16); |
|
539 |
++ return 1; |
|
540 |
++ } |
|
541 |
++ return 0; |
|
542 |
++} |
|
543 |
++ |
|
544 |
+ static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) |
|
545 |
+ { |
|
546 |
+ if (unpack_nameX(e, AA_U32, name)) { |
|
547 |
+@@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) |
|
548 |
+ { |
|
549 |
+ struct aa_profile *profile = NULL; |
|
550 |
+ const char *name = NULL; |
|
551 |
++ size_t size = 0; |
|
552 |
+ int i, error = -EPROTO; |
|
553 |
+ kernel_cap_t tmpcap; |
|
554 |
+ u32 tmp; |
|
555 |
+@@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) |
|
556 |
+ if (!unpack_rlimits(e, profile)) |
|
557 |
+ goto fail; |
|
558 |
+ |
|
559 |
++ size = unpack_array(e, "net_allowed_af"); |
|
560 |
++ if (size) { |
|
561 |
++ |
|
562 |
++ for (i = 0; i < size; i++) { |
|
563 |
++ /* discard extraneous rules that this kernel will |
|
564 |
++ * never request |
|
565 |
++ */ |
|
566 |
++ if (i >= AF_MAX) { |
|
567 |
++ u16 tmp; |
|
568 |
++ if (!unpack_u16(e, &tmp, NULL) || |
|
569 |
++ !unpack_u16(e, &tmp, NULL) || |
|
570 |
++ !unpack_u16(e, &tmp, NULL)) |
|
571 |
++ goto fail; |
|
572 |
++ continue; |
|
573 |
++ } |
|
574 |
++ if (!unpack_u16(e, &profile->net.allow[i], NULL)) |
|
575 |
++ goto fail; |
|
576 |
++ if (!unpack_u16(e, &profile->net.audit[i], NULL)) |
|
577 |
++ goto fail; |
|
578 |
++ if (!unpack_u16(e, &profile->net.quiet[i], NULL)) |
|
579 |
++ goto fail; |
|
580 |
++ } |
|
581 |
++ if (!unpack_nameX(e, AA_ARRAYEND, NULL)) |
|
582 |
++ goto fail; |
|
583 |
++ } |
|
584 |
++ /* |
|
585 |
++ * allow unix domain and netlink sockets they are handled |
|
586 |
++ * by IPC |
|
587 |
++ */ |
|
588 |
++ profile->net.allow[AF_UNIX] = 0xffff; |
|
589 |
++ profile->net.allow[AF_NETLINK] = 0xffff; |
|
590 |
++ |
|
591 |
+ if (unpack_nameX(e, AA_STRUCT, "policydb")) { |
|
592 |
+ /* generic policy dfa - optional and may be NULL */ |
|
593 |
+ profile->policy.dfa = unpack_dfa(e); |
|
594 |
+-- |
|
595 |
+2.7.4 |
|
596 |
+ |
0 | 597 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,42 @@ |
0 |
+From 43d2482f8472a21571feadade4d945d3048aec00 Mon Sep 17 00:00:00 2001 |
|
1 |
+From: John Johansen <john.johansen@canonical.com> |
|
2 |
+Date: Fri, 29 Jun 2012 17:34:00 -0700 |
|
3 |
+Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network |
|
4 |
+ mediation |
|
5 |
+ |
|
6 |
+[ This is an out-of-tree patch distributed with the AppArmor source |
|
7 |
+ code (v2.13) ] |
|
8 |
+ |
|
9 |
+If a profile specified a quieting of network denials for a given rule by |
|
10 |
+either the quiet or deny rule qualifiers, the resultant quiet mask for |
|
11 |
+denied requests was applied incorrectly, resulting in two potential bugs. |
|
12 |
+1. The misapplied quiet mask would prevent denials from being correctly |
|
13 |
+ tested against the kill mask/mode. Thus network access requests that |
|
14 |
+ should have resulted in the application being killed did not. |
|
15 |
+ |
|
16 |
+2. The actual quieting of the denied network request was not being applied. |
|
17 |
+ This would result in network rejections always being logged even when |
|
18 |
+ they had been specifically marked as quieted. |
|
19 |
+ |
|
20 |
+Signed-off-by: John Johansen <john.johansen@canonical.com> |
|
21 |
+Signed-off-by: Srivatsa S. Bhat <srivatsa@csail.mit.edu> |
|
22 |
+--- |
|
23 |
+ security/apparmor/net.c | 2 +- |
|
24 |
+ 1 file changed, 1 insertion(+), 1 deletion(-) |
|
25 |
+ |
|
26 |
+diff --git a/security/apparmor/net.c b/security/apparmor/net.c |
|
27 |
+index 003dd18..6e6e5c9 100644 |
|
28 |
+--- a/security/apparmor/net.c |
|
29 |
+@@ -88,7 +88,7 @@ static int audit_net(struct aa_profile *profile, int op, u16 family, int type, |
|
30 |
+ } else { |
|
31 |
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family]; |
|
32 |
+ u16 kill_mask = 0; |
|
33 |
+- u16 denied = (1 << sa.aad->net.type) & ~quiet_mask; |
|
34 |
++ u16 denied = (1 << sa.aad->net.type); |
|
35 |
+ |
|
36 |
+ if (denied & kill_mask) |
|
37 |
+ audit_type = AUDIT_APPARMOR_KILL; |
|
38 |
+-- |
|
39 |
+2.7.4 |
|
40 |
+ |
0 | 41 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,966 @@ |
0 |
+From 4d628e0f2b5d6346131f117b7e61ca873b6ad99b Mon Sep 17 00:00:00 2001 |
|
1 |
+From: John Johansen <john.johansen@canonical.com> |
|
2 |
+Date: Wed, 16 May 2012 10:58:05 -0700 |
|
3 |
+Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount |
|
4 |
+ |
|
5 |
+[ This is an out-of-tree patch distributed with the AppArmor source |
|
6 |
+ code (v2.13) ] |
|
7 |
+ |
|
8 |
+Add the ability for apparmor to do mediation of mount operations. Mount |
|
9 |
+rules require an updated apparmor_parser (2.8 series) for policy compilation. |
|
10 |
+ |
|
11 |
+The basic form of the rules are. |
|
12 |
+ |
|
13 |
+ [audit] [deny] mount [conds]* [device] [ -> [conds] path], |
|
14 |
+ [audit] [deny] remount [conds]* [path], |
|
15 |
+ [audit] [deny] umount [conds]* [path], |
|
16 |
+ [audit] [deny] pivotroot [oldroot=<value>] <path> |
|
17 |
+ |
|
18 |
+ remount is just a short cut for mount options=remount |
|
19 |
+ |
|
20 |
+ where [conds] can be |
|
21 |
+ fstype=<expr> |
|
22 |
+ options=<expr> |
|
23 |
+ |
|
24 |
+Example mount commands |
|
25 |
+ mount, # allow all mounts, but not umount or pivotroot |
|
26 |
+ |
|
27 |
+ mount fstype=procfs, # allow mounting procfs anywhere |
|
28 |
+ |
|
29 |
+ mount options=(bind, ro) /foo -> /bar, # readonly bind mount |
|
30 |
+ |
|
31 |
+ mount /dev/sda -> /mnt, |
|
32 |
+ |
|
33 |
+ mount /dev/sd** -> /mnt/**, |
|
34 |
+ |
|
35 |
+ mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/ |
|
36 |
+ |
|
37 |
+ umount, |
|
38 |
+ |
|
39 |
+ umount /m*, |
|
40 |
+ |
|
41 |
+See the apparmor userspace for full documentation |
|
42 |
+ |
|
43 |
+Signed-off-by: John Johansen <john.johansen@canonical.com> |
|
44 |
+Acked-by: Kees Cook <kees@ubuntu.com> |
|
45 |
+Signed-off-by: Srivatsa S. Bhat <srivatsa@csail.mit.edu> |
|
46 |
+--- |
|
47 |
+ security/apparmor/Makefile | 2 +- |
|
48 |
+ security/apparmor/apparmorfs.c | 15 +- |
|
49 |
+ security/apparmor/audit.c | 4 + |
|
50 |
+ security/apparmor/domain.c | 2 +- |
|
51 |
+ security/apparmor/include/apparmor.h | 3 +- |
|
52 |
+ security/apparmor/include/audit.h | 11 + |
|
53 |
+ security/apparmor/include/domain.h | 2 + |
|
54 |
+ security/apparmor/include/mount.h | 54 +++ |
|
55 |
+ security/apparmor/lsm.c | 60 ++++ |
|
56 |
+ security/apparmor/mount.c | 620 +++++++++++++++++++++++++++++++++++ |
|
57 |
+ 10 files changed, 769 insertions(+), 4 deletions(-) |
|
58 |
+ create mode 100644 security/apparmor/include/mount.h |
|
59 |
+ create mode 100644 security/apparmor/mount.c |
|
60 |
+ |
|
61 |
+diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile |
|
62 |
+index 5dbb72f..89b3445 100644 |
|
63 |
+--- a/security/apparmor/Makefile |
|
64 |
+@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o |
|
65 |
+ |
|
66 |
+ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ |
|
67 |
+ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ |
|
68 |
+- resource.o sid.o file.o net.o |
|
69 |
++ resource.o sid.o file.o net.o mount.o |
|
70 |
+ apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o |
|
71 |
+ |
|
72 |
+ clean-files := capability_names.h rlim_names.h net_names.h |
|
73 |
+diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c |
|
74 |
+index bd558db..fa61086 100644 |
|
75 |
+--- a/security/apparmor/apparmorfs.c |
|
76 |
+@@ -800,7 +800,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = { |
|
77 |
+ |
|
78 |
+ static struct aa_fs_entry aa_fs_entry_policy[] = { |
|
79 |
+ AA_FS_FILE_BOOLEAN("set_load", 1), |
|
80 |
+- {} |
|
81 |
++ { } |
|
82 |
++}; |
|
83 |
++ |
|
84 |
++static struct aa_fs_entry aa_fs_entry_mount[] = { |
|
85 |
++ AA_FS_FILE_STRING("mask", "mount umount"), |
|
86 |
++ { } |
|
87 |
++}; |
|
88 |
++ |
|
89 |
++static struct aa_fs_entry aa_fs_entry_namespaces[] = { |
|
90 |
++ AA_FS_FILE_BOOLEAN("profile", 1), |
|
91 |
++ AA_FS_FILE_BOOLEAN("pivot_root", 1), |
|
92 |
++ { } |
|
93 |
+ }; |
|
94 |
+ |
|
95 |
+ static struct aa_fs_entry aa_fs_entry_features[] = { |
|
96 |
+@@ -808,6 +819,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = { |
|
97 |
+ AA_FS_DIR("domain", aa_fs_entry_domain), |
|
98 |
+ AA_FS_DIR("file", aa_fs_entry_file), |
|
99 |
+ AA_FS_DIR("network", aa_fs_entry_network), |
|
100 |
++ AA_FS_DIR("mount", aa_fs_entry_mount), |
|
101 |
++ AA_FS_DIR("namespaces", aa_fs_entry_namespaces), |
|
102 |
+ AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), |
|
103 |
+ AA_FS_DIR("rlimit", aa_fs_entry_rlimit), |
|
104 |
+ AA_FS_DIR("caps", aa_fs_entry_caps), |
|
105 |
+diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c |
|
106 |
+index 3a7f1da..c2a8b8a 100644 |
|
107 |
+--- a/security/apparmor/audit.c |
|
108 |
+@@ -44,6 +44,10 @@ const char *const op_table[] = { |
|
109 |
+ "file_mmap", |
|
110 |
+ "file_mprotect", |
|
111 |
+ |
|
112 |
++ "pivotroot", |
|
113 |
++ "mount", |
|
114 |
++ "umount", |
|
115 |
++ |
|
116 |
+ "create", |
|
117 |
+ "post_create", |
|
118 |
+ "bind", |
|
119 |
+diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c |
|
120 |
+index a4d90aa..dbd68f2 100644 |
|
121 |
+--- a/security/apparmor/domain.c |
|
122 |
+@@ -236,7 +236,7 @@ static const char *next_name(int xtype, const char *name) |
|
123 |
+ * |
|
124 |
+ * Returns: refcounted profile, or NULL on failure (MAYBE NULL) |
|
125 |
+ */ |
|
126 |
+-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) |
|
127 |
++struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) |
|
128 |
+ { |
|
129 |
+ struct aa_profile *new_profile = NULL; |
|
130 |
+ struct aa_namespace *ns = profile->ns; |
|
131 |
+diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h |
|
132 |
+index 5d721e9..b57da7b 100644 |
|
133 |
+--- a/security/apparmor/include/apparmor.h |
|
134 |
+@@ -30,8 +30,9 @@ |
|
135 |
+ #define AA_CLASS_NET 4 |
|
136 |
+ #define AA_CLASS_RLIMITS 5 |
|
137 |
+ #define AA_CLASS_DOMAIN 6 |
|
138 |
++#define AA_CLASS_MOUNT 7 |
|
139 |
+ |
|
140 |
+-#define AA_CLASS_LAST AA_CLASS_DOMAIN |
|
141 |
++#define AA_CLASS_LAST AA_CLASS_MOUNT |
|
142 |
+ |
|
143 |
+ /* Control parameters settable through module/boot flags */ |
|
144 |
+ extern enum audit_mode aa_g_audit; |
|
145 |
+diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h |
|
146 |
+index 5d3c419..b9f1d57 100644 |
|
147 |
+--- a/security/apparmor/include/audit.h |
|
148 |
+@@ -72,6 +72,10 @@ enum aa_ops { |
|
149 |
+ OP_FMMAP, |
|
150 |
+ OP_FMPROT, |
|
151 |
+ |
|
152 |
++ OP_PIVOTROOT, |
|
153 |
++ OP_MOUNT, |
|
154 |
++ OP_UMOUNT, |
|
155 |
++ |
|
156 |
+ OP_CREATE, |
|
157 |
+ OP_POST_CREATE, |
|
158 |
+ OP_BIND, |
|
159 |
+@@ -120,6 +124,13 @@ struct apparmor_audit_data { |
|
160 |
+ unsigned long max; |
|
161 |
+ } rlim; |
|
162 |
+ struct { |
|
163 |
++ const char *src_name; |
|
164 |
++ const char *type; |
|
165 |
++ const char *trans; |
|
166 |
++ const char *data; |
|
167 |
++ unsigned long flags; |
|
168 |
++ } mnt; |
|
169 |
++ struct { |
|
170 |
+ const char *target; |
|
171 |
+ u32 request; |
|
172 |
+ u32 denied; |
|
173 |
+diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h |
|
174 |
+index de04464..a3f70c5 100644 |
|
175 |
+--- a/security/apparmor/include/domain.h |
|
176 |
+@@ -23,6 +23,8 @@ struct aa_domain { |
|
177 |
+ char **table; |
|
178 |
+ }; |
|
179 |
+ |
|
180 |
++struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex); |
|
181 |
++ |
|
182 |
+ int apparmor_bprm_set_creds(struct linux_binprm *bprm); |
|
183 |
+ int apparmor_bprm_secureexec(struct linux_binprm *bprm); |
|
184 |
+ void apparmor_bprm_committing_creds(struct linux_binprm *bprm); |
|
185 |
+diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h |
|
186 |
+new file mode 100644 |
|
187 |
+index 0000000..a43b1d6 |
|
188 |
+--- /dev/null |
|
189 |
+@@ -0,0 +1,54 @@ |
|
190 |
++/* |
|
191 |
++ * AppArmor security module |
|
192 |
++ * |
|
193 |
++ * This file contains AppArmor file mediation function definitions. |
|
194 |
++ * |
|
195 |
++ * Copyright 2012 Canonical Ltd. |
|
196 |
++ * |
|
197 |
++ * This program is free software; you can redistribute it and/or |
|
198 |
++ * modify it under the terms of the GNU General Public License as |
|
199 |
++ * published by the Free Software Foundation, version 2 of the |
|
200 |
++ * License. |
|
201 |
++ */ |
|
202 |
++ |
|
203 |
++#ifndef __AA_MOUNT_H |
|
204 |
++#define __AA_MOUNT_H |
|
205 |
++ |
|
206 |
++#include <linux/fs.h> |
|
207 |
++#include <linux/path.h> |
|
208 |
++ |
|
209 |
++#include "domain.h" |
|
210 |
++#include "policy.h" |
|
211 |
++ |
|
212 |
++/* mount perms */ |
|
213 |
++#define AA_MAY_PIVOTROOT 0x01 |
|
214 |
++#define AA_MAY_MOUNT 0x02 |
|
215 |
++#define AA_MAY_UMOUNT 0x04 |
|
216 |
++#define AA_AUDIT_DATA 0x40 |
|
217 |
++#define AA_CONT_MATCH 0x40 |
|
218 |
++ |
|
219 |
++#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN) |
|
220 |
++ |
|
221 |
++int aa_remount(struct aa_profile *profile, const struct path *path, |
|
222 |
++ unsigned long flags, void *data); |
|
223 |
++ |
|
224 |
++int aa_bind_mount(struct aa_profile *profile, const struct path *path, |
|
225 |
++ const char *old_name, unsigned long flags); |
|
226 |
++ |
|
227 |
++ |
|
228 |
++int aa_mount_change_type(struct aa_profile *profile, const struct path *path, |
|
229 |
++ unsigned long flags); |
|
230 |
++ |
|
231 |
++int aa_move_mount(struct aa_profile *profile, const struct path *path, |
|
232 |
++ const char *old_name); |
|
233 |
++ |
|
234 |
++int aa_new_mount(struct aa_profile *profile, const char *dev_name, |
|
235 |
++ const struct path *path, const char *type, unsigned long flags, |
|
236 |
++ void *data); |
|
237 |
++ |
|
238 |
++int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags); |
|
239 |
++ |
|
240 |
++int aa_pivotroot(struct aa_profile *profile, const struct path *old_path, |
|
241 |
++ const struct path *new_path); |
|
242 |
++ |
|
243 |
++#endif /* __AA_MOUNT_H */ |
|
244 |
+diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c |
|
245 |
+index de3b68a..40c9fda 100644 |
|
246 |
+--- a/security/apparmor/lsm.c |
|
247 |
+@@ -36,6 +36,7 @@ |
|
248 |
+ #include "include/path.h" |
|
249 |
+ #include "include/policy.h" |
|
250 |
+ #include "include/procattr.h" |
|
251 |
++#include "include/mount.h" |
|
252 |
+ |
|
253 |
+ /* Flag indicating whether initialization completed */ |
|
254 |
+ int apparmor_initialized __initdata; |
|
255 |
+@@ -469,6 +470,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma, |
|
256 |
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); |
|
257 |
+ } |
|
258 |
+ |
|
259 |
++static int apparmor_sb_mount(const char *dev_name, const struct path *path, |
|
260 |
++ const char *type, unsigned long flags, void *data) |
|
261 |
++{ |
|
262 |
++ struct aa_profile *profile; |
|
263 |
++ int error = 0; |
|
264 |
++ |
|
265 |
++ /* Discard magic */ |
|
266 |
++ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) |
|
267 |
++ flags &= ~MS_MGC_MSK; |
|
268 |
++ |
|
269 |
++ flags &= ~AA_MS_IGNORE_MASK; |
|
270 |
++ |
|
271 |
++ profile = __aa_current_profile(); |
|
272 |
++ if (!unconfined(profile)) { |
|
273 |
++ if (flags & MS_REMOUNT) |
|
274 |
++ error = aa_remount(profile, path, flags, data); |
|
275 |
++ else if (flags & MS_BIND) |
|
276 |
++ error = aa_bind_mount(profile, path, dev_name, flags); |
|
277 |
++ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | |
|
278 |
++ MS_UNBINDABLE)) |
|
279 |
++ error = aa_mount_change_type(profile, path, flags); |
|
280 |
++ else if (flags & MS_MOVE) |
|
281 |
++ error = aa_move_mount(profile, path, dev_name); |
|
282 |
++ else |
|
283 |
++ error = aa_new_mount(profile, dev_name, path, type, |
|
284 |
++ flags, data); |
|
285 |
++ } |
|
286 |
++ return error; |
|
287 |
++} |
|
288 |
++ |
|
289 |
++static int apparmor_sb_umount(struct vfsmount *mnt, int flags) |
|
290 |
++{ |
|
291 |
++ struct aa_profile *profile; |
|
292 |
++ int error = 0; |
|
293 |
++ |
|
294 |
++ profile = __aa_current_profile(); |
|
295 |
++ if (!unconfined(profile)) |
|
296 |
++ error = aa_umount(profile, mnt, flags); |
|
297 |
++ |
|
298 |
++ return error; |
|
299 |
++} |
|
300 |
++ |
|
301 |
++static int apparmor_sb_pivotroot(const struct path *old_path, |
|
302 |
++ const struct path *new_path) |
|
303 |
++{ |
|
304 |
++ struct aa_profile *profile; |
|
305 |
++ int error = 0; |
|
306 |
++ |
|
307 |
++ profile = __aa_current_profile(); |
|
308 |
++ if (!unconfined(profile)) |
|
309 |
++ error = aa_pivotroot(profile, old_path, new_path); |
|
310 |
++ |
|
311 |
++ return error; |
|
312 |
++} |
|
313 |
++ |
|
314 |
+ static int apparmor_getprocattr(struct task_struct *task, char *name, |
|
315 |
+ char **value) |
|
316 |
+ { |
|
317 |
+@@ -689,6 +745,10 @@ static struct security_hook_list apparmor_hooks[] = { |
|
318 |
+ LSM_HOOK_INIT(capget, apparmor_capget), |
|
319 |
+ LSM_HOOK_INIT(capable, apparmor_capable), |
|
320 |
+ |
|
321 |
++ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount), |
|
322 |
++ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount), |
|
323 |
++ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot), |
|
324 |
++ |
|
325 |
+ LSM_HOOK_INIT(path_link, apparmor_path_link), |
|
326 |
+ LSM_HOOK_INIT(path_unlink, apparmor_path_unlink), |
|
327 |
+ LSM_HOOK_INIT(path_symlink, apparmor_path_symlink), |
|
328 |
+diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c |
|
329 |
+new file mode 100644 |
|
330 |
+index 0000000..9cf9170 |
|
331 |
+--- /dev/null |
|
332 |
+@@ -0,0 +1,620 @@ |
|
333 |
++/* |
|
334 |
++ * AppArmor security module |
|
335 |
++ * |
|
336 |
++ * This file contains AppArmor mediation of files |
|
337 |
++ * |
|
338 |
++ * Copyright (C) 1998-2008 Novell/SUSE |
|
339 |
++ * Copyright 2009-2012 Canonical Ltd. |
|
340 |
++ * |
|
341 |
++ * This program is free software; you can redistribute it and/or |
|
342 |
++ * modify it under the terms of the GNU General Public License as |
|
343 |
++ * published by the Free Software Foundation, version 2 of the |
|
344 |
++ * License. |
|
345 |
++ */ |
|
346 |
++ |
|
347 |
++#include <linux/fs.h> |
|
348 |
++#include <linux/mount.h> |
|
349 |
++#include <linux/namei.h> |
|
350 |
++ |
|
351 |
++#include "include/apparmor.h" |
|
352 |
++#include "include/audit.h" |
|
353 |
++#include "include/context.h" |
|
354 |
++#include "include/domain.h" |
|
355 |
++#include "include/file.h" |
|
356 |
++#include "include/match.h" |
|
357 |
++#include "include/mount.h" |
|
358 |
++#include "include/path.h" |
|
359 |
++#include "include/policy.h" |
|
360 |
++ |
|
361 |
++ |
|
362 |
++static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags) |
|
363 |
++{ |
|
364 |
++ if (flags & MS_RDONLY) |
|
365 |
++ audit_log_format(ab, "ro"); |
|
366 |
++ else |
|
367 |
++ audit_log_format(ab, "rw"); |
|
368 |
++ if (flags & MS_NOSUID) |
|
369 |
++ audit_log_format(ab, ", nosuid"); |
|
370 |
++ if (flags & MS_NODEV) |
|
371 |
++ audit_log_format(ab, ", nodev"); |
|
372 |
++ if (flags & MS_NOEXEC) |
|
373 |
++ audit_log_format(ab, ", noexec"); |
|
374 |
++ if (flags & MS_SYNCHRONOUS) |
|
375 |
++ audit_log_format(ab, ", sync"); |
|
376 |
++ if (flags & MS_REMOUNT) |
|
377 |
++ audit_log_format(ab, ", remount"); |
|
378 |
++ if (flags & MS_MANDLOCK) |
|
379 |
++ audit_log_format(ab, ", mand"); |
|
380 |
++ if (flags & MS_DIRSYNC) |
|
381 |
++ audit_log_format(ab, ", dirsync"); |
|
382 |
++ if (flags & MS_NOATIME) |
|
383 |
++ audit_log_format(ab, ", noatime"); |
|
384 |
++ if (flags & MS_NODIRATIME) |
|
385 |
++ audit_log_format(ab, ", nodiratime"); |
|
386 |
++ if (flags & MS_BIND) |
|
387 |
++ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind"); |
|
388 |
++ if (flags & MS_MOVE) |
|
389 |
++ audit_log_format(ab, ", move"); |
|
390 |
++ if (flags & MS_SILENT) |
|
391 |
++ audit_log_format(ab, ", silent"); |
|
392 |
++ if (flags & MS_POSIXACL) |
|
393 |
++ audit_log_format(ab, ", acl"); |
|
394 |
++ if (flags & MS_UNBINDABLE) |
|
395 |
++ audit_log_format(ab, flags & MS_REC ? ", runbindable" : |
|
396 |
++ ", unbindable"); |
|
397 |
++ if (flags & MS_PRIVATE) |
|
398 |
++ audit_log_format(ab, flags & MS_REC ? ", rprivate" : |
|
399 |
++ ", private"); |
|
400 |
++ if (flags & MS_SLAVE) |
|
401 |
++ audit_log_format(ab, flags & MS_REC ? ", rslave" : |
|
402 |
++ ", slave"); |
|
403 |
++ if (flags & MS_SHARED) |
|
404 |
++ audit_log_format(ab, flags & MS_REC ? ", rshared" : |
|
405 |
++ ", shared"); |
|
406 |
++ if (flags & MS_RELATIME) |
|
407 |
++ audit_log_format(ab, ", relatime"); |
|
408 |
++ if (flags & MS_I_VERSION) |
|
409 |
++ audit_log_format(ab, ", iversion"); |
|
410 |
++ if (flags & MS_STRICTATIME) |
|
411 |
++ audit_log_format(ab, ", strictatime"); |
|
412 |
++ if (flags & MS_NOUSER) |
|
413 |
++ audit_log_format(ab, ", nouser"); |
|
414 |
++} |
|
415 |
++ |
|
416 |
++/** |
|
417 |
++ * audit_cb - call back for mount specific audit fields |
|
418 |
++ * @ab: audit_buffer (NOT NULL) |
|
419 |
++ * @va: audit struct to audit values of (NOT NULL) |
|
420 |
++ */ |
|
421 |
++static void audit_cb(struct audit_buffer *ab, void *va) |
|
422 |
++{ |
|
423 |
++ struct common_audit_data *sa = va; |
|
424 |
++ |
|
425 |
++ if (sa->aad->mnt.type) { |
|
426 |
++ audit_log_format(ab, " fstype="); |
|
427 |
++ audit_log_untrustedstring(ab, sa->aad->mnt.type); |
|
428 |
++ } |
|
429 |
++ if (sa->aad->mnt.src_name) { |
|
430 |
++ audit_log_format(ab, " srcname="); |
|
431 |
++ audit_log_untrustedstring(ab, sa->aad->mnt.src_name); |
|
432 |
++ } |
|
433 |
++ if (sa->aad->mnt.trans) { |
|
434 |
++ audit_log_format(ab, " trans="); |
|
435 |
++ audit_log_untrustedstring(ab, sa->aad->mnt.trans); |
|
436 |
++ } |
|
437 |
++ if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) { |
|
438 |
++ audit_log_format(ab, " flags=\""); |
|
439 |
++ audit_mnt_flags(ab, sa->aad->mnt.flags); |
|
440 |
++ audit_log_format(ab, "\""); |
|
441 |
++ } |
|
442 |
++ if (sa->aad->mnt.data) { |
|
443 |
++ audit_log_format(ab, " options="); |
|
444 |
++ audit_log_untrustedstring(ab, sa->aad->mnt.data); |
|
445 |
++ } |
|
446 |
++} |
|
447 |
++ |
|
448 |
++/** |
|
449 |
++ * audit_mount - handle the auditing of mount operations |
|
450 |
++ * @profile: the profile being enforced (NOT NULL) |
|
451 |
++ * @gfp: allocation flags |
|
452 |
++ * @op: operation being mediated (NOT NULL) |
|
453 |
++ * @name: name of object being mediated (MAYBE NULL) |
|
454 |
++ * @src_name: src_name of object being mediated (MAYBE_NULL) |
|
455 |
++ * @type: type of filesystem (MAYBE_NULL) |
|
456 |
++ * @trans: name of trans (MAYBE NULL) |
|
457 |
++ * @flags: filesystem idependent mount flags |
|
458 |
++ * @data: filesystem mount flags |
|
459 |
++ * @request: permissions requested |
|
460 |
++ * @perms: the permissions computed for the request (NOT NULL) |
|
461 |
++ * @info: extra information message (MAYBE NULL) |
|
462 |
++ * @error: 0 if operation allowed else failure error code |
|
463 |
++ * |
|
464 |
++ * Returns: %0 or error on failure |
|
465 |
++ */ |
|
466 |
++static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op, |
|
467 |
++ const char *name, const char *src_name, |
|
468 |
++ const char *type, const char *trans, |
|
469 |
++ unsigned long flags, const void *data, u32 request, |
|
470 |
++ struct file_perms *perms, const char *info, int error) |
|
471 |
++{ |
|
472 |
++ int audit_type = AUDIT_APPARMOR_AUTO; |
|
473 |
++ struct common_audit_data sa = { }; |
|
474 |
++ struct apparmor_audit_data aad = { }; |
|
475 |
++ |
|
476 |
++ if (likely(!error)) { |
|
477 |
++ u32 mask = perms->audit; |
|
478 |
++ |
|
479 |
++ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) |
|
480 |
++ mask = 0xffff; |
|
481 |
++ |
|
482 |
++ /* mask off perms that are not being force audited */ |
|
483 |
++ request &= mask; |
|
484 |
++ |
|
485 |
++ if (likely(!request)) |
|
486 |
++ return 0; |
|
487 |
++ audit_type = AUDIT_APPARMOR_AUDIT; |
|
488 |
++ } else { |
|
489 |
++ /* only report permissions that were denied */ |
|
490 |
++ request = request & ~perms->allow; |
|
491 |
++ |
|
492 |
++ if (request & perms->kill) |
|
493 |
++ audit_type = AUDIT_APPARMOR_KILL; |
|
494 |
++ |
|
495 |
++ /* quiet known rejects, assumes quiet and kill do not overlap */ |
|
496 |
++ if ((request & perms->quiet) && |
|
497 |
++ AUDIT_MODE(profile) != AUDIT_NOQUIET && |
|
498 |
++ AUDIT_MODE(profile) != AUDIT_ALL) |
|
499 |
++ request &= ~perms->quiet; |
|
500 |
++ |
|
501 |
++ if (!request) |
|
502 |
++ return COMPLAIN_MODE(profile) ? |
|
503 |
++ complain_error(error) : error; |
|
504 |
++ } |
|
505 |
++ |
|
506 |
++ sa.type = LSM_AUDIT_DATA_NONE; |
|
507 |
++ sa.aad = &aad; |
|
508 |
++ sa.aad->op = op; |
|
509 |
++ sa.aad->name = name; |
|
510 |
++ sa.aad->mnt.src_name = src_name; |
|
511 |
++ sa.aad->mnt.type = type; |
|
512 |
++ sa.aad->mnt.trans = trans; |
|
513 |
++ sa.aad->mnt.flags = flags; |
|
514 |
++ if (data && (perms->audit & AA_AUDIT_DATA)) |
|
515 |
++ sa.aad->mnt.data = data; |
|
516 |
++ sa.aad->info = info; |
|
517 |
++ sa.aad->error = error; |
|
518 |
++ |
|
519 |
++ return aa_audit(audit_type, profile, gfp, &sa, audit_cb); |
|
520 |
++} |
|
521 |
++ |
|
522 |
++/** |
|
523 |
++ * match_mnt_flags - Do an ordered match on mount flags |
|
524 |
++ * @dfa: dfa to match against |
|
525 |
++ * @state: state to start in |
|
526 |
++ * @flags: mount flags to match against |
|
527 |
++ * |
|
528 |
++ * Mount flags are encoded as an ordered match. This is done instead of |
|
529 |
++ * checking against a simple bitmask, to allow for logical operations |
|
530 |
++ * on the flags. |
|
531 |
++ * |
|
532 |
++ * Returns: next state after flags match |
|
533 |
++ */ |
|
534 |
++static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state, |
|
535 |
++ unsigned long flags) |
|
536 |
++{ |
|
537 |
++ unsigned int i; |
|
538 |
++ |
|
539 |
++ for (i = 0; i <= 31 ; ++i) { |
|
540 |
++ if ((1 << i) & flags) |
|
541 |
++ state = aa_dfa_next(dfa, state, i + 1); |
|
542 |
++ } |
|
543 |
++ |
|
544 |
++ return state; |
|
545 |
++} |
|
546 |
++ |
|
547 |
++/** |
|
548 |
++ * compute_mnt_perms - compute mount permission associated with @state |
|
549 |
++ * @dfa: dfa to match against (NOT NULL) |
|
550 |
++ * @state: state match finished in |
|
551 |
++ * |
|
552 |
++ * Returns: mount permissions |
|
553 |
++ */ |
|
554 |
++static struct file_perms compute_mnt_perms(struct aa_dfa *dfa, |
|
555 |
++ unsigned int state) |
|
556 |
++{ |
|
557 |
++ struct file_perms perms; |
|
558 |
++ |
|
559 |
++ perms.kill = 0; |
|
560 |
++ perms.allow = dfa_user_allow(dfa, state); |
|
561 |
++ perms.audit = dfa_user_audit(dfa, state); |
|
562 |
++ perms.quiet = dfa_user_quiet(dfa, state); |
|
563 |
++ perms.xindex = dfa_user_xindex(dfa, state); |
|
564 |
++ |
|
565 |
++ return perms; |
|
566 |
++} |
|
567 |
++ |
|
568 |
++static const char const *mnt_info_table[] = { |
|
569 |
++ "match succeeded", |
|
570 |
++ "failed mntpnt match", |
|
571 |
++ "failed srcname match", |
|
572 |
++ "failed type match", |
|
573 |
++ "failed flags match", |
|
574 |
++ "failed data match" |
|
575 |
++}; |
|
576 |
++ |
|
577 |
++/* |
|
578 |
++ * Returns 0 on success else element that match failed in, this is the |
|
579 |
++ * index into the mnt_info_table above |
|
580 |
++ */ |
|
581 |
++static int do_match_mnt(struct aa_dfa *dfa, unsigned int start, |
|
582 |
++ const char *mntpnt, const char *devname, |
|
583 |
++ const char *type, unsigned long flags, |
|
584 |
++ void *data, bool binary, struct file_perms *perms) |
|
585 |
++{ |
|
586 |
++ unsigned int state; |
|
587 |
++ |
|
588 |
++ state = aa_dfa_match(dfa, start, mntpnt); |
|
589 |
++ state = aa_dfa_null_transition(dfa, state); |
|
590 |
++ if (!state) |
|
591 |
++ return 1; |
|
592 |
++ |
|
593 |
++ if (devname) |
|
594 |
++ state = aa_dfa_match(dfa, state, devname); |
|
595 |
++ state = aa_dfa_null_transition(dfa, state); |
|
596 |
++ if (!state) |
|
597 |
++ return 2; |
|
598 |
++ |
|
599 |
++ if (type) |
|
600 |
++ state = aa_dfa_match(dfa, state, type); |
|
601 |
++ state = aa_dfa_null_transition(dfa, state); |
|
602 |
++ if (!state) |
|
603 |
++ return 3; |
|
604 |
++ |
|
605 |
++ state = match_mnt_flags(dfa, state, flags); |
|
606 |
++ if (!state) |
|
607 |
++ return 4; |
|
608 |
++ *perms = compute_mnt_perms(dfa, state); |
|
609 |
++ if (perms->allow & AA_MAY_MOUNT) |
|
610 |
++ return 0; |
|
611 |
++ |
|
612 |
++ /* only match data if not binary and the DFA flags data is expected */ |
|
613 |
++ if (data && !binary && (perms->allow & AA_CONT_MATCH)) { |
|
614 |
++ state = aa_dfa_null_transition(dfa, state); |
|
615 |
++ if (!state) |
|
616 |
++ return 4; |
|
617 |
++ |
|
618 |
++ state = aa_dfa_match(dfa, state, data); |
|
619 |
++ if (!state) |
|
620 |
++ return 5; |
|
621 |
++ *perms = compute_mnt_perms(dfa, state); |
|
622 |
++ if (perms->allow & AA_MAY_MOUNT) |
|
623 |
++ return 0; |
|
624 |
++ } |
|
625 |
++ |
|
626 |
++ /* failed at end of flags match */ |
|
627 |
++ return 4; |
|
628 |
++} |
|
629 |
++ |
|
630 |
++/** |
|
631 |
++ * match_mnt - handle path matching for mount |
|
632 |
++ * @profile: the confining profile |
|
633 |
++ * @mntpnt: string for the mntpnt (NOT NULL) |
|
634 |
++ * @devname: string for the devname/src_name (MAYBE NULL) |
|
635 |
++ * @type: string for the dev type (MAYBE NULL) |
|
636 |
++ * @flags: mount flags to match |
|
637 |
++ * @data: fs mount data (MAYBE NULL) |
|
638 |
++ * @binary: whether @data is binary |
|
639 |
++ * @perms: Returns: permission found by the match |
|
640 |
++ * @info: Returns: infomation string about the match for logging |
|
641 |
++ * |
|
642 |
++ * Returns: 0 on success else error |
|
643 |
++ */ |
|
644 |
++static int match_mnt(struct aa_profile *profile, const char *mntpnt, |
|
645 |
++ const char *devname, const char *type, |
|
646 |
++ unsigned long flags, void *data, bool binary, |
|
647 |
++ struct file_perms *perms, const char **info) |
|
648 |
++{ |
|
649 |
++ int pos; |
|
650 |
++ |
|
651 |
++ if (!profile->policy.dfa) |
|
652 |
++ return -EACCES; |
|
653 |
++ |
|
654 |
++ pos = do_match_mnt(profile->policy.dfa, |
|
655 |
++ profile->policy.start[AA_CLASS_MOUNT], |
|
656 |
++ mntpnt, devname, type, flags, data, binary, perms); |
|
657 |
++ if (pos) { |
|
658 |
++ *info = mnt_info_table[pos]; |
|
659 |
++ return -EACCES; |
|
660 |
++ } |
|
661 |
++ |
|
662 |
++ return 0; |
|
663 |
++} |
|
664 |
++ |
|
665 |
++static int path_flags(struct aa_profile *profile, const struct path *path) |
|
666 |
++{ |
|
667 |
++ return profile->path_flags | |
|
668 |
++ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0; |
|
669 |
++} |
|
670 |
++ |
|
671 |
++int aa_remount(struct aa_profile *profile, const struct path *path, |
|
672 |
++ unsigned long flags, void *data) |
|
673 |
++{ |
|
674 |
++ struct file_perms perms = { }; |
|
675 |
++ const char *name, *info = NULL; |
|
676 |
++ char *buffer = NULL; |
|
677 |
++ int binary, error; |
|
678 |
++ |
|
679 |
++ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA; |
|
680 |
++ |
|
681 |
++ error = aa_path_name(path, path_flags(profile, path), &buffer, &name, |
|
682 |
++ &info); |
|
683 |
++ if (error) |
|
684 |
++ goto audit; |
|
685 |
++ |
|
686 |
++ error = match_mnt(profile, name, NULL, NULL, flags, data, binary, |
|
687 |
++ &perms, &info); |
|
688 |
++ |
|
689 |
++audit: |
|
690 |
++ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL, |
|
691 |
++ NULL, flags, data, AA_MAY_MOUNT, &perms, info, |
|
692 |
++ error); |
|
693 |
++ kfree(buffer); |
|
694 |
++ |
|
695 |
++ return error; |
|
696 |
++} |
|
697 |
++ |
|
698 |
++int aa_bind_mount(struct aa_profile *profile, const struct path *path, |
|
699 |
++ const char *dev_name, unsigned long flags) |
|
700 |
++{ |
|
701 |
++ struct file_perms perms = { }; |
|
702 |
++ char *buffer = NULL, *old_buffer = NULL; |
|
703 |
++ const char *name, *old_name = NULL, *info = NULL; |
|
704 |
++ struct path old_path; |
|
705 |
++ int error; |
|
706 |
++ |
|
707 |
++ if (!dev_name || !*dev_name) |
|
708 |
++ return -EINVAL; |
|
709 |
++ |
|
710 |
++ flags &= MS_REC | MS_BIND; |
|
711 |
++ |
|
712 |
++ error = aa_path_name(path, path_flags(profile, path), &buffer, &name, |
|
713 |
++ &info); |
|
714 |
++ if (error) |
|
715 |
++ goto audit; |
|
716 |
++ |
|
717 |
++ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); |
|
718 |
++ if (error) |
|
719 |
++ goto audit; |
|
720 |
++ |
|
721 |
++ error = aa_path_name(&old_path, path_flags(profile, &old_path), |
|
722 |
++ &old_buffer, &old_name, &info); |
|
723 |
++ path_put(&old_path); |
|
724 |
++ if (error) |
|
725 |
++ goto audit; |
|
726 |
++ |
|
727 |
++ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0, |
|
728 |
++ &perms, &info); |
|
729 |
++ |
|
730 |
++audit: |
|
731 |
++ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name, |
|
732 |
++ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms, |
|
733 |
++ info, error); |
|
734 |
++ kfree(buffer); |
|
735 |
++ kfree(old_buffer); |
|
736 |
++ |
|
737 |
++ return error; |
|
738 |
++} |
|
739 |
++ |
|
740 |
++int aa_mount_change_type(struct aa_profile *profile, const struct path *path, |
|
741 |
++ unsigned long flags) |
|
742 |
++{ |
|
743 |
++ struct file_perms perms = { }; |
|
744 |
++ char *buffer = NULL; |
|
745 |
++ const char *name, *info = NULL; |
|
746 |
++ int error; |
|
747 |
++ |
|
748 |
++ /* These are the flags allowed by do_change_type() */ |
|
749 |
++ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE | |
|
750 |
++ MS_UNBINDABLE); |
|
751 |
++ |
|
752 |
++ error = aa_path_name(path, path_flags(profile, path), &buffer, &name, |
|
753 |
++ &info); |
|
754 |
++ if (error) |
|
755 |
++ goto audit; |
|
756 |
++ |
|
757 |
++ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms, |
|
758 |
++ &info); |
|
759 |
++ |
|
760 |
++audit: |
|
761 |
++ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL, |
|
762 |
++ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info, |
|
763 |
++ error); |
|
764 |
++ kfree(buffer); |
|
765 |
++ |
|
766 |
++ return error; |
|
767 |
++} |
|
768 |
++ |
|
769 |
++int aa_move_mount(struct aa_profile *profile, const struct path *path, |
|
770 |
++ const char *orig_name) |
|
771 |
++{ |
|
772 |
++ struct file_perms perms = { }; |
|
773 |
++ char *buffer = NULL, *old_buffer = NULL; |
|
774 |
++ const char *name, *old_name = NULL, *info = NULL; |
|
775 |
++ struct path old_path; |
|
776 |
++ int error; |
|
777 |
++ |
|
778 |
++ if (!orig_name || !*orig_name) |
|
779 |
++ return -EINVAL; |
|
780 |
++ |
|
781 |
++ error = aa_path_name(path, path_flags(profile, path), &buffer, &name, |
|
782 |
++ &info); |
|
783 |
++ if (error) |
|
784 |
++ goto audit; |
|
785 |
++ |
|
786 |
++ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path); |
|
787 |
++ if (error) |
|
788 |
++ goto audit; |
|
789 |
++ |
|
790 |
++ error = aa_path_name(&old_path, path_flags(profile, &old_path), |
|
791 |
++ &old_buffer, &old_name, &info); |
|
792 |
++ path_put(&old_path); |
|
793 |
++ if (error) |
|
794 |
++ goto audit; |
|
795 |
++ |
|
796 |
++ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0, |
|
797 |
++ &perms, &info); |
|
798 |
++ |
|
799 |
++audit: |
|
800 |
++ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name, |
|
801 |
++ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms, |
|
802 |
++ info, error); |
|
803 |
++ kfree(buffer); |
|
804 |
++ kfree(old_buffer); |
|
805 |
++ |
|
806 |
++ return error; |
|
807 |
++} |
|
808 |
++ |
|
809 |
++int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name, |
|
810 |
++ const struct path *path, const char *type, unsigned long flags, |
|
811 |
++ void *data) |
|
812 |
++{ |
|
813 |
++ struct file_perms perms = { }; |
|
814 |
++ char *buffer = NULL, *dev_buffer = NULL; |
|
815 |
++ const char *name = NULL, *dev_name = NULL, *info = NULL; |
|
816 |
++ int binary = 1; |
|
817 |
++ int error; |
|
818 |
++ |
|
819 |
++ dev_name = orig_dev_name; |
|
820 |
++ if (type) { |
|
821 |
++ int requires_dev; |
|
822 |
++ struct file_system_type *fstype = get_fs_type(type); |
|
823 |
++ if (!fstype) |
|
824 |
++ return -ENODEV; |
|
825 |
++ |
|
826 |
++ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA; |
|
827 |
++ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV; |
|
828 |
++ put_filesystem(fstype); |
|
829 |
++ |
|
830 |
++ if (requires_dev) { |
|
831 |
++ struct path dev_path; |
|
832 |
++ |
|
833 |
++ if (!dev_name || !*dev_name) { |
|
834 |
++ error = -ENOENT; |
|
835 |
++ goto out; |
|
836 |
++ } |
|
837 |
++ |
|
838 |
++ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path); |
|
839 |
++ if (error) |
|
840 |
++ goto audit; |
|
841 |
++ |
|
842 |
++ error = aa_path_name(&dev_path, |
|
843 |
++ path_flags(profile, &dev_path), |
|
844 |
++ &dev_buffer, &dev_name, &info); |
|
845 |
++ path_put(&dev_path); |
|
846 |
++ if (error) |
|
847 |
++ goto audit; |
|
848 |
++ } |
|
849 |
++ } |
|
850 |
++ |
|
851 |
++ error = aa_path_name(path, path_flags(profile, path), &buffer, &name, |
|
852 |
++ &info); |
|
853 |
++ if (error) |
|
854 |
++ goto audit; |
|
855 |
++ |
|
856 |
++ error = match_mnt(profile, name, dev_name, type, flags, data, binary, |
|
857 |
++ &perms, &info); |
|
858 |
++ |
|
859 |
++audit: |
|
860 |
++ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name, |
|
861 |
++ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info, |
|
862 |
++ error); |
|
863 |
++ kfree(buffer); |
|
864 |
++ kfree(dev_buffer); |
|
865 |
++ |
|
866 |
++out: |
|
867 |
++ return error; |
|
868 |
++ |
|
869 |
++} |
|
870 |
++ |
|
871 |
++int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags) |
|
872 |
++{ |
|
873 |
++ struct file_perms perms = { }; |
|
874 |
++ char *buffer = NULL; |
|
875 |
++ const char *name, *info = NULL; |
|
876 |
++ int error; |
|
877 |
++ |
|
878 |
++ struct path path = { mnt, mnt->mnt_root }; |
|
879 |
++ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name, |
|
880 |
++ &info); |
|
881 |
++ if (error) |
|
882 |
++ goto audit; |
|
883 |
++ |
|
884 |
++ if (!error && profile->policy.dfa) { |
|
885 |
++ unsigned int state; |
|
886 |
++ state = aa_dfa_match(profile->policy.dfa, |
|
887 |
++ profile->policy.start[AA_CLASS_MOUNT], |
|
888 |
++ name); |
|
889 |
++ perms = compute_mnt_perms(profile->policy.dfa, state); |
|
890 |
++ } |
|
891 |
++ |
|
892 |
++ if (AA_MAY_UMOUNT & ~perms.allow) |
|
893 |
++ error = -EACCES; |
|
894 |
++ |
|
895 |
++audit: |
|
896 |
++ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL, |
|
897 |
++ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error); |
|
898 |
++ kfree(buffer); |
|
899 |
++ |
|
900 |
++ return error; |
|
901 |
++} |
|
902 |
++ |
|
903 |
++int aa_pivotroot(struct aa_profile *profile, const struct path *old_path, |
|
904 |
++ const struct path *new_path) |
|
905 |
++{ |
|
906 |
++ struct file_perms perms = { }; |
|
907 |
++ struct aa_profile *target = NULL; |
|
908 |
++ char *old_buffer = NULL, *new_buffer = NULL; |
|
909 |
++ const char *old_name, *new_name = NULL, *info = NULL; |
|
910 |
++ int error; |
|
911 |
++ |
|
912 |
++ error = aa_path_name(old_path, path_flags(profile, old_path), |
|
913 |
++ &old_buffer, &old_name, &info); |
|
914 |
++ if (error) |
|
915 |
++ goto audit; |
|
916 |
++ |
|
917 |
++ error = aa_path_name(new_path, path_flags(profile, new_path), |
|
918 |
++ &new_buffer, &new_name, &info); |
|
919 |
++ if (error) |
|
920 |
++ goto audit; |
|
921 |
++ |
|
922 |
++ if (profile->policy.dfa) { |
|
923 |
++ unsigned int state; |
|
924 |
++ state = aa_dfa_match(profile->policy.dfa, |
|
925 |
++ profile->policy.start[AA_CLASS_MOUNT], |
|
926 |
++ new_name); |
|
927 |
++ state = aa_dfa_null_transition(profile->policy.dfa, state); |
|
928 |
++ state = aa_dfa_match(profile->policy.dfa, state, old_name); |
|
929 |
++ perms = compute_mnt_perms(profile->policy.dfa, state); |
|
930 |
++ } |
|
931 |
++ |
|
932 |
++ if (AA_MAY_PIVOTROOT & perms.allow) { |
|
933 |
++ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) { |
|
934 |
++ target = x_table_lookup(profile, perms.xindex); |
|
935 |
++ if (!target) |
|
936 |
++ error = -ENOENT; |
|
937 |
++ else |
|
938 |
++ error = aa_replace_current_profile(target); |
|
939 |
++ } |
|
940 |
++ } else |
|
941 |
++ error = -EACCES; |
|
942 |
++ |
|
943 |
++audit: |
|
944 |
++ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name, |
|
945 |
++ old_name, NULL, target ? target->base.name : NULL, |
|
946 |
++ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error); |
|
947 |
++ aa_put_profile(target); |
|
948 |
++ kfree(old_buffer); |
|
949 |
++ kfree(new_buffer); |
|
950 |
++ |
|
951 |
++ return error; |
|
952 |
++} |
|
953 |
+-- |
|
954 |
+2.7.4 |
|
955 |
+ |
... | ... |
@@ -2,7 +2,7 @@ |
2 | 2 |
Summary: Kernel |
3 | 3 |
Name: linux-aws |
4 | 4 |
Version: 4.9.111 |
5 |
-Release: 4%{?kat_build:.%kat_build}%{?dist} |
|
5 |
+Release: 5%{?kat_build:.%kat_build}%{?dist} |
|
6 | 6 |
License: GPLv2 |
7 | 7 |
URL: http://www.kernel.org/ |
8 | 8 |
Group: System Environment/Kernel |
... | ... |
@@ -85,6 +85,12 @@ Patch62: 0151-ipv6-prevent-speculative-execution.patch |
85 | 85 |
Patch64: 0153-net-mpls-prevent-speculative-execution.patch |
86 | 86 |
Patch65: 0154-udf-prevent-speculative-execution.patch |
87 | 87 |
Patch66: 0155-userns-prevent-speculative-execution.patch |
88 |
+ |
|
89 |
+# Out-of-tree patches from AppArmor: |
|
90 |
+Patch71: 0001-UBUNTU-SAUCE-AppArmor-basic-networking-rules.patch |
|
91 |
+Patch72: 0002-apparmor-Fix-quieting-of-audit-messages-for-network-.patch |
|
92 |
+Patch73: 0003-UBUNTU-SAUCE-apparmor-Add-the-ability-to-mediate-mou.patch |
|
93 |
+ |
|
88 | 94 |
# Amazon AWS |
89 | 95 |
Patch101: 0002-lib-cpumask-Make-CPUMASK_OFFSTACK-usable-without-deb.patch |
90 | 96 |
Patch102: 0009-bump-the-default-TTL-to-255.patch |
... | ... |
@@ -263,6 +269,10 @@ This package contains the 'perf' performance analysis tools for Linux kernel. |
263 | 263 |
%patch65 -p1 |
264 | 264 |
%patch66 -p1 |
265 | 265 |
|
266 |
+%patch71 -p1 |
|
267 |
+%patch72 -p1 |
|
268 |
+%patch73 -p1 |
|
269 |
+ |
|
266 | 270 |
%patch101 -p1 |
267 | 271 |
%patch102 -p1 |
268 | 272 |
%patch103 -p1 |
... | ... |
@@ -467,6 +477,8 @@ ln -sf %{name}-%{uname_r}.cfg /boot/photon.cfg |
467 | 467 |
/usr/share/doc/* |
468 | 468 |
|
469 | 469 |
%changelog |
470 |
+* Thu Jul 19 2018 Srivatsa S. Bhat <srivatsa@csail.mit.edu> 4.9.111-5 |
|
471 |
+- Apply out-of-tree patches needed for AppArmor. |
|
470 | 472 |
* Thu Jul 17 2018 Srinidhi Rao <srinidhir@vmware.com> 4.9.111-4 |
471 | 473 |
- Fix CVE-2018-10322 |
472 | 474 |
* Thu Jul 12 2018 Srinidhi Rao <srinidhir@vmware.com> 4.9.111-3 |
... | ... |
@@ -2,7 +2,7 @@ |
2 | 2 |
Summary: Kernel |
3 | 3 |
Name: linux-secure |
4 | 4 |
Version: 4.9.111 |
5 |
-Release: 3%{?kat_build:.%kat_build}%{?dist} |
|
5 |
+Release: 4%{?kat_build:.%kat_build}%{?dist} |
|
6 | 6 |
License: GPLv2 |
7 | 7 |
URL: http://www.kernel.org/ |
8 | 8 |
Group: System Environment/Kernel |
... | ... |
@@ -92,6 +92,10 @@ Patch64: 0153-net-mpls-prevent-speculative-execution.patch |
92 | 92 |
Patch65: 0154-udf-prevent-speculative-execution.patch |
93 | 93 |
Patch66: 0155-userns-prevent-speculative-execution.patch |
94 | 94 |
|
95 |
+# Out-of-tree patches from AppArmor: |
|
96 |
+Patch71: 0001-UBUNTU-SAUCE-AppArmor-basic-networking-rules.patch |
|
97 |
+Patch72: 0002-apparmor-Fix-quieting-of-audit-messages-for-network-.patch |
|
98 |
+Patch73: 0003-UBUNTU-SAUCE-apparmor-Add-the-ability-to-mediate-mou.patch |
|
95 | 99 |
|
96 | 100 |
# NSX requirements (should be removed) |
97 | 101 |
Patch99: LKCM.patch |
... | ... |
@@ -232,6 +236,10 @@ EOF |
232 | 232 |
%patch65 -p1 |
233 | 233 |
%patch66 -p1 |
234 | 234 |
|
235 |
+%patch71 -p1 |
|
236 |
+%patch72 -p1 |
|
237 |
+%patch73 -p1 |
|
238 |
+ |
|
235 | 239 |
# secure |
236 | 240 |
%patch13 -p1 |
237 | 241 |
%patch14 -p1 |
... | ... |
@@ -362,6 +370,8 @@ ln -sf linux-%{uname_r}.cfg /boot/photon.cfg |
362 | 362 |
/usr/src/linux-headers-%{uname_r} |
363 | 363 |
|
364 | 364 |
%changelog |
365 |
+* Thu Jul 19 2018 Srivatsa S. Bhat <srivatsa@csail.mit.edu> 4.9.111-4 |
|
366 |
+- Apply out-of-tree patches needed for AppArmor. |
|
365 | 367 |
* Thu Jul 17 2018 Srinidhi Rao <srinidhir@vmware.com> 4.9.111-3 |
366 | 368 |
- Fix CVE-2018-10322 |
367 | 369 |
* Thu Jul 12 2018 Srinidhi Rao <srinidhir@vmware.com> 4.9.111-2 |
... | ... |
@@ -2,7 +2,7 @@ |
2 | 2 |
Summary: Kernel |
3 | 3 |
Name: linux |
4 | 4 |
Version: 4.9.111 |
5 |
-Release: 4%{?kat_build:.%kat_build}%{?dist} |
|
5 |
+Release: 5%{?kat_build:.%kat_build}%{?dist} |
|
6 | 6 |
License: GPLv2 |
7 | 7 |
URL: http://www.kernel.org/ |
8 | 8 |
Group: System Environment/Kernel |
... | ... |
@@ -91,6 +91,10 @@ Patch64: 0153-net-mpls-prevent-speculative-execution.patch |
91 | 91 |
Patch65: 0154-udf-prevent-speculative-execution.patch |
92 | 92 |
Patch66: 0155-userns-prevent-speculative-execution.patch |
93 | 93 |
|
94 |
+# Out-of-tree patches from AppArmor: |
|
95 |
+Patch71: 0001-UBUNTU-SAUCE-AppArmor-basic-networking-rules.patch |
|
96 |
+Patch72: 0002-apparmor-Fix-quieting-of-audit-messages-for-network-.patch |
|
97 |
+Patch73: 0003-UBUNTU-SAUCE-apparmor-Add-the-ability-to-mediate-mou.patch |
|
94 | 98 |
|
95 | 99 |
%if 0%{?kat_build:1} |
96 | 100 |
Patch1000: %{kat_build}.patch |
... | ... |
@@ -223,6 +227,9 @@ This package contains the 'perf' performance analysis tools for Linux kernel. |
223 | 223 |
%patch65 -p1 |
224 | 224 |
%patch66 -p1 |
225 | 225 |
|
226 |
+%patch71 -p1 |
|
227 |
+%patch72 -p1 |
|
228 |
+%patch73 -p1 |
|
226 | 229 |
|
227 | 230 |
%if 0%{?kat_build:1} |
228 | 231 |
%patch1000 -p1 |
... | ... |
@@ -390,6 +397,8 @@ ln -sf %{name}-%{uname_r}.cfg /boot/photon.cfg |
390 | 390 |
/usr/share/doc/* |
391 | 391 |
|
392 | 392 |
%changelog |
393 |
+* Thu Jul 19 2018 Srivatsa S. Bhat <srivatsa@csail.mit.edu> 4.9.111-5 |
|
394 |
+- Apply out-of-tree patches needed for AppArmor. |
|
393 | 395 |
* Thu Jul 17 2018 Srinidhi Rao <srinidhir@vmware.com> 4.9.111-4 |
394 | 396 |
- Fix CVE-2018-10322 |
395 | 397 |
* Thu Jul 12 2018 Srinidhi Rao <srinidhir@vmware.com> 4.9.111-3 |