]>
Commit | Line | Data |
---|---|---|
c3701be9 DM |
1 | From e83b058f391e96a2a640fb2e2812d50ef67e0f43 Mon Sep 17 00:00:00 2001 |
2 | From: John Johansen <john.johansen@canonical.com> | |
3 | Date: Mon, 4 Oct 2010 15:03:36 -0700 | |
4 | Subject: [PATCH 2/4] UBUNTU: SAUCE: AppArmor: basic networking rules | |
5 | ||
6 | Base support for network mediation. | |
7 | ||
8 | Signed-off-by: John Johansen <john.johansen@canonical.com> | |
9 | --- | |
10 | security/apparmor/.gitignore | 1 + | |
11 | security/apparmor/Makefile | 42 +++++++++- | |
12 | security/apparmor/apparmorfs.c | 1 + | |
13 | security/apparmor/include/audit.h | 4 + | |
14 | security/apparmor/include/net.h | 44 ++++++++++ | |
15 | security/apparmor/include/policy.h | 3 + | |
16 | security/apparmor/lsm.c | 112 +++++++++++++++++++++++++ | |
17 | security/apparmor/net.c | 162 +++++++++++++++++++++++++++++++++++++ | |
18 | security/apparmor/policy.c | 1 + | |
19 | security/apparmor/policy_unpack.c | 46 +++++++++++ | |
20 | 10 files changed, 414 insertions(+), 2 deletions(-) | |
21 | create mode 100644 security/apparmor/include/net.h | |
22 | create mode 100644 security/apparmor/net.c | |
23 | ||
24 | diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore | |
25 | index 9cdec70..d5b291e 100644 | |
26 | --- a/security/apparmor/.gitignore | |
27 | +++ b/security/apparmor/.gitignore | |
28 | @@ -1,5 +1,6 @@ | |
29 | # | |
30 | # Generated include files | |
31 | # | |
32 | +net_names.h | |
33 | capability_names.h | |
34 | rlim_names.h | |
35 | diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile | |
36 | index 5706b74..e270692 100644 | |
37 | --- a/security/apparmor/Makefile | |
38 | +++ b/security/apparmor/Makefile | |
39 | @@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o | |
40 | ||
41 | apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ | |
42 | path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ | |
43 | - resource.o sid.o file.o | |
44 | + resource.o sid.o file.o net.o | |
45 | ||
46 | -clean-files := capability_names.h rlim_names.h | |
47 | +clean-files := capability_names.h rlim_names.h net_names.h | |
48 | ||
49 | ||
50 | # Build a lower case string table of capability names | |
51 | @@ -20,6 +20,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\ | |
52 | -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\ | |
53 | echo "};" >> $@ | |
54 | ||
55 | +# Build a lower case string table of address family names | |
56 | +# Transform lines from | |
57 | +# define AF_LOCAL 1 /* POSIX name for AF_UNIX */ | |
58 | +# #define AF_INET 2 /* Internet IP Protocol */ | |
59 | +# to | |
60 | +# [1] = "local", | |
61 | +# [2] = "inet", | |
62 | +# | |
63 | +# and build the securityfs entries for the mapping. | |
64 | +# Transforms lines from | |
65 | +# #define AF_INET 2 /* Internet IP Protocol */ | |
66 | +# to | |
67 | +# #define AA_FS_AF_MASK "local inet" | |
68 | +quiet_cmd_make-af = GEN $@ | |
69 | +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ | |
70 | + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \ | |
71 | + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ | |
72 | + echo "};" >> $@ ;\ | |
73 | + echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\ | |
74 | + sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\ | |
75 | + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ | |
76 | + | |
77 | +# Build a lower case string table of sock type names | |
78 | +# Transform lines from | |
79 | +# SOCK_STREAM = 1, | |
80 | +# to | |
81 | +# [1] = "stream", | |
82 | +quiet_cmd_make-sock = GEN $@ | |
83 | +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ | |
84 | + sed $^ >>$@ -r -n \ | |
85 | + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ | |
86 | + echo "};" >> $@ | |
87 | ||
88 | # Build a lower case string table of rlimit names. | |
89 | # Transforms lines from | |
90 | @@ -56,6 +88,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ | |
91 | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ | |
92 | ||
93 | $(obj)/capability.o : $(obj)/capability_names.h | |
94 | +$(obj)/net.o : $(obj)/net_names.h | |
95 | $(obj)/resource.o : $(obj)/rlim_names.h | |
96 | $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ | |
97 | $(src)/Makefile | |
98 | @@ -63,3 +96,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ | |
99 | $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ | |
100 | $(src)/Makefile | |
101 | $(call cmd,make-rlim) | |
102 | +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \ | |
103 | + $(srctree)/include/linux/net.h \ | |
104 | + $(src)/Makefile | |
105 | + $(call cmd,make-af) | |
106 | + $(call cmd,make-sock) | |
107 | diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c | |
108 | index 42b7c9f..114fb23 100644 | |
109 | --- a/security/apparmor/apparmorfs.c | |
110 | +++ b/security/apparmor/apparmorfs.c | |
111 | @@ -429,6 +429,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = { | |
112 | static struct aa_fs_entry aa_fs_entry_features[] = { | |
113 | AA_FS_DIR("domain", aa_fs_entry_domain), | |
114 | AA_FS_DIR("file", aa_fs_entry_file), | |
115 | + AA_FS_DIR("network", aa_fs_entry_network), | |
116 | AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), | |
117 | AA_FS_DIR("rlimit", aa_fs_entry_rlimit), | |
118 | { } | |
119 | diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h | |
120 | index 69d8cae..4af6523 100644 | |
121 | --- a/security/apparmor/include/audit.h | |
122 | +++ b/security/apparmor/include/audit.h | |
123 | @@ -127,6 +127,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 | +++ b/security/apparmor/include/net.h | |
139 | @@ -0,0 +1,44 @@ | |
140 | +/* | |
141 | + * AppArmor security module | |
142 | + * | |
143 | + * This file contains AppArmor network mediation definitions. | |
144 | + * | |
145 | + * Copyright (C) 1998-2008 Novell/SUSE | |
146 | + * Copyright 2009-2012 Canonical Ltd. | |
147 | + * | |
148 | + * This program is free software; you can redistribute it and/or | |
149 | + * modify it under the terms of the GNU General Public License as | |
150 | + * published by the Free Software Foundation, version 2 of the | |
151 | + * License. | |
152 | + */ | |
153 | + | |
154 | +#ifndef __AA_NET_H | |
155 | +#define __AA_NET_H | |
156 | + | |
157 | +#include <net/sock.h> | |
158 | + | |
159 | +#include "apparmorfs.h" | |
160 | + | |
161 | +/* struct aa_net - network confinement data | |
162 | + * @allowed: basic network families permissions | |
163 | + * @audit_network: which network permissions to force audit | |
164 | + * @quiet_network: which network permissions to quiet rejects | |
165 | + */ | |
166 | +struct aa_net { | |
167 | + u16 allow[AF_MAX]; | |
168 | + u16 audit[AF_MAX]; | |
169 | + u16 quiet[AF_MAX]; | |
170 | +}; | |
171 | + | |
172 | +extern struct aa_fs_entry aa_fs_entry_network[]; | |
173 | + | |
174 | +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family, | |
175 | + int type, int protocol, struct sock *sk); | |
176 | +extern int aa_revalidate_sk(int op, struct sock *sk); | |
177 | + | |
178 | +static inline void aa_free_net_rules(struct aa_net *new) | |
179 | +{ | |
180 | + /* NOP */ | |
181 | +} | |
182 | + | |
183 | +#endif /* __AA_NET_H */ | |
184 | diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h | |
185 | index bda4569..eb13a73 100644 | |
186 | --- a/security/apparmor/include/policy.h | |
187 | +++ b/security/apparmor/include/policy.h | |
188 | @@ -27,6 +27,7 @@ | |
189 | #include "capability.h" | |
190 | #include "domain.h" | |
191 | #include "file.h" | |
192 | +#include "net.h" | |
193 | #include "resource.h" | |
194 | ||
195 | extern const char *const profile_mode_names[]; | |
196 | @@ -157,6 +158,7 @@ struct aa_policydb { | |
197 | * @policy: general match rules governing policy | |
198 | * @file: The set of rules governing basic file access and domain transitions | |
199 | * @caps: capabilities for the profile | |
200 | + * @net: network controls for the profile | |
201 | * @rlimits: rlimits for the profile | |
202 | * | |
203 | * The AppArmor profile contains the basic confinement data. Each profile | |
204 | @@ -194,6 +196,7 @@ struct aa_profile { | |
205 | struct aa_policydb policy; | |
206 | struct aa_file_rules file; | |
207 | struct aa_caps caps; | |
208 | + struct aa_net net; | |
209 | struct aa_rlimit rlimits; | |
210 | }; | |
211 | ||
212 | diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c | |
213 | index b21830e..1bce440 100644 | |
214 | --- a/security/apparmor/lsm.c | |
215 | +++ b/security/apparmor/lsm.c | |
216 | @@ -32,6 +32,7 @@ | |
217 | #include "include/context.h" | |
218 | #include "include/file.h" | |
219 | #include "include/ipc.h" | |
220 | +#include "include/net.h" | |
221 | #include "include/path.h" | |
222 | #include "include/policy.h" | |
223 | #include "include/procattr.h" | |
224 | @@ -614,6 +615,104 @@ static int apparmor_task_setrlimit(struct task_struct *task, | |
225 | return error; | |
226 | } | |
227 | ||
228 | +static int apparmor_socket_create(int family, int type, int protocol, int kern) | |
229 | +{ | |
230 | + struct aa_profile *profile; | |
231 | + int error = 0; | |
232 | + | |
233 | + if (kern) | |
234 | + return 0; | |
235 | + | |
236 | + profile = __aa_current_profile(); | |
237 | + if (!unconfined(profile)) | |
238 | + error = aa_net_perm(OP_CREATE, profile, family, type, protocol, | |
239 | + NULL); | |
240 | + return error; | |
241 | +} | |
242 | + | |
243 | +static int apparmor_socket_bind(struct socket *sock, | |
244 | + struct sockaddr *address, int addrlen) | |
245 | +{ | |
246 | + struct sock *sk = sock->sk; | |
247 | + | |
248 | + return aa_revalidate_sk(OP_BIND, sk); | |
249 | +} | |
250 | + | |
251 | +static int apparmor_socket_connect(struct socket *sock, | |
252 | + struct sockaddr *address, int addrlen) | |
253 | +{ | |
254 | + struct sock *sk = sock->sk; | |
255 | + | |
256 | + return aa_revalidate_sk(OP_CONNECT, sk); | |
257 | +} | |
258 | + | |
259 | +static int apparmor_socket_listen(struct socket *sock, int backlog) | |
260 | +{ | |
261 | + struct sock *sk = sock->sk; | |
262 | + | |
263 | + return aa_revalidate_sk(OP_LISTEN, sk); | |
264 | +} | |
265 | + | |
266 | +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) | |
267 | +{ | |
268 | + struct sock *sk = sock->sk; | |
269 | + | |
270 | + return aa_revalidate_sk(OP_ACCEPT, sk); | |
271 | +} | |
272 | + | |
273 | +static int apparmor_socket_sendmsg(struct socket *sock, | |
274 | + struct msghdr *msg, int size) | |
275 | +{ | |
276 | + struct sock *sk = sock->sk; | |
277 | + | |
278 | + return aa_revalidate_sk(OP_SENDMSG, sk); | |
279 | +} | |
280 | + | |
281 | +static int apparmor_socket_recvmsg(struct socket *sock, | |
282 | + struct msghdr *msg, int size, int flags) | |
283 | +{ | |
284 | + struct sock *sk = sock->sk; | |
285 | + | |
286 | + return aa_revalidate_sk(OP_RECVMSG, sk); | |
287 | +} | |
288 | + | |
289 | +static int apparmor_socket_getsockname(struct socket *sock) | |
290 | +{ | |
291 | + struct sock *sk = sock->sk; | |
292 | + | |
293 | + return aa_revalidate_sk(OP_GETSOCKNAME, sk); | |
294 | +} | |
295 | + | |
296 | +static int apparmor_socket_getpeername(struct socket *sock) | |
297 | +{ | |
298 | + struct sock *sk = sock->sk; | |
299 | + | |
300 | + return aa_revalidate_sk(OP_GETPEERNAME, sk); | |
301 | +} | |
302 | + | |
303 | +static int apparmor_socket_getsockopt(struct socket *sock, int level, | |
304 | + int optname) | |
305 | +{ | |
306 | + struct sock *sk = sock->sk; | |
307 | + | |
308 | + return aa_revalidate_sk(OP_GETSOCKOPT, sk); | |
309 | +} | |
310 | + | |
311 | +static int apparmor_socket_setsockopt(struct socket *sock, int level, | |
312 | + int optname) | |
313 | +{ | |
314 | + struct sock *sk = sock->sk; | |
315 | + | |
316 | + return aa_revalidate_sk(OP_SETSOCKOPT, sk); | |
317 | +} | |
318 | + | |
319 | +static int apparmor_socket_shutdown(struct socket *sock, int how) | |
320 | +{ | |
321 | + struct sock *sk = sock->sk; | |
322 | + | |
323 | + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk); | |
324 | +} | |
325 | + | |
326 | static struct security_operations apparmor_ops = { | |
327 | .name = "apparmor", | |
328 | ||
329 | @@ -646,6 +745,19 @@ static struct security_operations apparmor_ops = { | |
330 | .getprocattr = apparmor_getprocattr, | |
331 | .setprocattr = apparmor_setprocattr, | |
332 | ||
333 | + .socket_create = apparmor_socket_create, | |
334 | + .socket_bind = apparmor_socket_bind, | |
335 | + .socket_connect = apparmor_socket_connect, | |
336 | + .socket_listen = apparmor_socket_listen, | |
337 | + .socket_accept = apparmor_socket_accept, | |
338 | + .socket_sendmsg = apparmor_socket_sendmsg, | |
339 | + .socket_recvmsg = apparmor_socket_recvmsg, | |
340 | + .socket_getsockname = apparmor_socket_getsockname, | |
341 | + .socket_getpeername = apparmor_socket_getpeername, | |
342 | + .socket_getsockopt = apparmor_socket_getsockopt, | |
343 | + .socket_setsockopt = apparmor_socket_setsockopt, | |
344 | + .socket_shutdown = apparmor_socket_shutdown, | |
345 | + | |
346 | .cred_alloc_blank = apparmor_cred_alloc_blank, | |
347 | .cred_free = apparmor_cred_free, | |
348 | .cred_prepare = apparmor_cred_prepare, | |
349 | diff --git a/security/apparmor/net.c b/security/apparmor/net.c | |
350 | new file mode 100644 | |
351 | index 0000000..003dd18 | |
352 | --- /dev/null | |
353 | +++ b/security/apparmor/net.c | |
354 | @@ -0,0 +1,162 @@ | |
355 | +/* | |
356 | + * AppArmor security module | |
357 | + * | |
358 | + * This file contains AppArmor network mediation | |
359 | + * | |
360 | + * Copyright (C) 1998-2008 Novell/SUSE | |
361 | + * Copyright 2009-2012 Canonical Ltd. | |
362 | + * | |
363 | + * This program is free software; you can redistribute it and/or | |
364 | + * modify it under the terms of the GNU General Public License as | |
365 | + * published by the Free Software Foundation, version 2 of the | |
366 | + * License. | |
367 | + */ | |
368 | + | |
369 | +#include "include/apparmor.h" | |
370 | +#include "include/audit.h" | |
371 | +#include "include/context.h" | |
372 | +#include "include/net.h" | |
373 | +#include "include/policy.h" | |
374 | + | |
375 | +#include "net_names.h" | |
376 | + | |
377 | +struct aa_fs_entry aa_fs_entry_network[] = { | |
378 | + AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK), | |
379 | + { } | |
380 | +}; | |
381 | + | |
382 | +/* audit callback for net specific fields */ | |
383 | +static void audit_cb(struct audit_buffer *ab, void *va) | |
384 | +{ | |
385 | + struct common_audit_data *sa = va; | |
386 | + | |
387 | + audit_log_format(ab, " family="); | |
388 | + if (address_family_names[sa->u.net->family]) { | |
389 | + audit_log_string(ab, address_family_names[sa->u.net->family]); | |
390 | + } else { | |
391 | + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family); | |
392 | + } | |
393 | + audit_log_format(ab, " sock_type="); | |
394 | + if (sock_type_names[sa->aad->net.type]) { | |
395 | + audit_log_string(ab, sock_type_names[sa->aad->net.type]); | |
396 | + } else { | |
397 | + audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type); | |
398 | + } | |
399 | + audit_log_format(ab, " protocol=%d", sa->aad->net.protocol); | |
400 | +} | |
401 | + | |
402 | +/** | |
403 | + * audit_net - audit network access | |
404 | + * @profile: profile being enforced (NOT NULL) | |
405 | + * @op: operation being checked | |
406 | + * @family: network family | |
407 | + * @type: network type | |
408 | + * @protocol: network protocol | |
409 | + * @sk: socket auditing is being applied to | |
410 | + * @error: error code for failure else 0 | |
411 | + * | |
412 | + * Returns: %0 or sa->error else other errorcode on failure | |
413 | + */ | |
414 | +static int audit_net(struct aa_profile *profile, int op, u16 family, int type, | |
415 | + int protocol, struct sock *sk, int error) | |
416 | +{ | |
417 | + int audit_type = AUDIT_APPARMOR_AUTO; | |
418 | + struct common_audit_data sa; | |
419 | + struct apparmor_audit_data aad = { }; | |
420 | + struct lsm_network_audit net = { }; | |
421 | + if (sk) { | |
422 | + sa.type = LSM_AUDIT_DATA_NET; | |
423 | + } else { | |
424 | + sa.type = LSM_AUDIT_DATA_NONE; | |
425 | + } | |
426 | + /* todo fill in socket addr info */ | |
427 | + sa.aad = &aad; | |
428 | + sa.u.net = &net; | |
429 | + sa.aad->op = op, | |
430 | + sa.u.net->family = family; | |
431 | + sa.u.net->sk = sk; | |
432 | + sa.aad->net.type = type; | |
433 | + sa.aad->net.protocol = protocol; | |
434 | + sa.aad->error = error; | |
435 | + | |
436 | + if (likely(!sa.aad->error)) { | |
437 | + u16 audit_mask = profile->net.audit[sa.u.net->family]; | |
438 | + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && | |
439 | + !(1 << sa.aad->net.type & audit_mask))) | |
440 | + return 0; | |
441 | + audit_type = AUDIT_APPARMOR_AUDIT; | |
442 | + } else { | |
443 | + u16 quiet_mask = profile->net.quiet[sa.u.net->family]; | |
444 | + u16 kill_mask = 0; | |
445 | + u16 denied = (1 << sa.aad->net.type) & ~quiet_mask; | |
446 | + | |
447 | + if (denied & kill_mask) | |
448 | + audit_type = AUDIT_APPARMOR_KILL; | |
449 | + | |
450 | + if ((denied & quiet_mask) && | |
451 | + AUDIT_MODE(profile) != AUDIT_NOQUIET && | |
452 | + AUDIT_MODE(profile) != AUDIT_ALL) | |
453 | + return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; | |
454 | + } | |
455 | + | |
456 | + return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb); | |
457 | +} | |
458 | + | |
459 | +/** | |
460 | + * aa_net_perm - very course network access check | |
461 | + * @op: operation being checked | |
462 | + * @profile: profile being enforced (NOT NULL) | |
463 | + * @family: network family | |
464 | + * @type: network type | |
465 | + * @protocol: network protocol | |
466 | + * | |
467 | + * Returns: %0 else error if permission denied | |
468 | + */ | |
469 | +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type, | |
470 | + int protocol, struct sock *sk) | |
471 | +{ | |
472 | + u16 family_mask; | |
473 | + int error; | |
474 | + | |
475 | + if ((family < 0) || (family >= AF_MAX)) | |
476 | + return -EINVAL; | |
477 | + | |
478 | + if ((type < 0) || (type >= SOCK_MAX)) | |
479 | + return -EINVAL; | |
480 | + | |
481 | + /* unix domain and netlink sockets are handled by ipc */ | |
482 | + if (family == AF_UNIX || family == AF_NETLINK) | |
483 | + return 0; | |
484 | + | |
485 | + family_mask = profile->net.allow[family]; | |
486 | + | |
487 | + error = (family_mask & (1 << type)) ? 0 : -EACCES; | |
488 | + | |
489 | + return audit_net(profile, op, family, type, protocol, sk, error); | |
490 | +} | |
491 | + | |
492 | +/** | |
493 | + * aa_revalidate_sk - Revalidate access to a sock | |
494 | + * @op: operation being checked | |
495 | + * @sk: sock being revalidated (NOT NULL) | |
496 | + * | |
497 | + * Returns: %0 else error if permission denied | |
498 | + */ | |
499 | +int aa_revalidate_sk(int op, struct sock *sk) | |
500 | +{ | |
501 | + struct aa_profile *profile; | |
502 | + int error = 0; | |
503 | + | |
504 | + /* aa_revalidate_sk should not be called from interrupt context | |
505 | + * don't mediate these calls as they are not task related | |
506 | + */ | |
507 | + if (in_interrupt()) | |
508 | + return 0; | |
509 | + | |
510 | + profile = __aa_current_profile(); | |
511 | + if (!unconfined(profile)) | |
512 | + error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type, | |
513 | + sk->sk_protocol, sk); | |
514 | + | |
515 | + return error; | |
516 | +} | |
517 | diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c | |
518 | index 8132003..56e5304 100644 | |
519 | --- a/security/apparmor/policy.c | |
520 | +++ b/security/apparmor/policy.c | |
521 | @@ -747,6 +747,7 @@ static void free_profile(struct aa_profile *profile) | |
522 | ||
523 | aa_free_file_rules(&profile->file); | |
524 | aa_free_cap_rules(&profile->caps); | |
525 | + aa_free_net_rules(&profile->net); | |
526 | aa_free_rlimit_rules(&profile->rlimits); | |
527 | ||
528 | aa_free_sid(profile->sid); | |
529 | diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c | |
530 | index 329b1fd..1b90dfa 100644 | |
531 | --- a/security/apparmor/policy_unpack.c | |
532 | +++ b/security/apparmor/policy_unpack.c | |
533 | @@ -193,6 +193,19 @@ fail: | |
534 | return 0; | |
535 | } | |
536 | ||
537 | +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) | |
538 | +{ | |
539 | + if (unpack_nameX(e, AA_U16, name)) { | |
540 | + if (!inbounds(e, sizeof(u16))) | |
541 | + return 0; | |
542 | + if (data) | |
543 | + *data = le16_to_cpu(get_unaligned((u16 *) e->pos)); | |
544 | + e->pos += sizeof(u16); | |
545 | + return 1; | |
546 | + } | |
547 | + return 0; | |
548 | +} | |
549 | + | |
550 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) | |
551 | { | |
552 | if (unpack_nameX(e, AA_U32, name)) { | |
553 | @@ -471,6 +484,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) | |
554 | { | |
555 | struct aa_profile *profile = NULL; | |
556 | const char *name = NULL; | |
557 | + size_t size = 0; | |
558 | int i, error = -EPROTO; | |
559 | kernel_cap_t tmpcap; | |
560 | u32 tmp; | |
561 | @@ -564,6 +578,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) | |
562 | if (!unpack_rlimits(e, profile)) | |
563 | goto fail; | |
564 | ||
565 | + size = unpack_array(e, "net_allowed_af"); | |
566 | + if (size) { | |
567 | + | |
568 | + for (i = 0; i < size; i++) { | |
569 | + /* discard extraneous rules that this kernel will | |
570 | + * never request | |
571 | + */ | |
572 | + if (i >= AF_MAX) { | |
573 | + u16 tmp; | |
574 | + if (!unpack_u16(e, &tmp, NULL) || | |
575 | + !unpack_u16(e, &tmp, NULL) || | |
576 | + !unpack_u16(e, &tmp, NULL)) | |
577 | + goto fail; | |
578 | + continue; | |
579 | + } | |
580 | + if (!unpack_u16(e, &profile->net.allow[i], NULL)) | |
581 | + goto fail; | |
582 | + if (!unpack_u16(e, &profile->net.audit[i], NULL)) | |
583 | + goto fail; | |
584 | + if (!unpack_u16(e, &profile->net.quiet[i], NULL)) | |
585 | + goto fail; | |
586 | + } | |
587 | + if (!unpack_nameX(e, AA_ARRAYEND, NULL)) | |
588 | + goto fail; | |
589 | + } | |
590 | + /* | |
591 | + * allow unix domain and netlink sockets they are handled | |
592 | + * by IPC | |
593 | + */ | |
594 | + profile->net.allow[AF_UNIX] = 0xffff; | |
595 | + profile->net.allow[AF_NETLINK] = 0xffff; | |
596 | + | |
597 | if (unpack_nameX(e, AA_STRUCT, "policydb")) { | |
598 | /* generic policy dfa - optional and may be NULL */ | |
599 | profile->policy.dfa = unpack_dfa(e); | |
600 | -- | |
601 | 1.8.3.2 | |
602 |