]>
Commit | Line | Data |
---|---|---|
daaa955e AM |
1 | From 853cbdfb6924857a2ee2a1cd5b9fa494f8e7efa2 Mon Sep 17 00:00:00 2001 |
2 | From: John Johansen <john.johansen@canonical.com> | |
3 | Date: Tue, 18 Jul 2017 23:18:33 -0700 | |
4 | Subject: [PATCH 12/17] apparmor: add base infastructure for socket mediation | |
5 | ||
6 | Provide a basic mediation of sockets. This is not a full net mediation | |
7 | but just whether a spcific family of socket can be used by an | |
8 | application, along with setting up some basic infrastructure for | |
9 | network mediation to follow. | |
10 | ||
11 | the user space rule hav the basic form of | |
12 | NETWORK RULE = [ QUALIFIERS ] 'network' [ DOMAIN ] | |
13 | [ TYPE | PROTOCOL ] | |
14 | ||
15 | DOMAIN = ( 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | | |
16 | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | | |
17 | 'netbeui' | 'security' | 'key' | 'packet' | 'ash' | | |
18 | 'econet' | 'atmsvc' | 'sna' | 'irda' | 'pppox' | | |
19 | 'wanpipe' | 'bluetooth' | 'netlink' | 'unix' | 'rds' | | |
20 | 'llc' | 'can' | 'tipc' | 'iucv' | 'rxrpc' | 'isdn' | | |
21 | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | | |
22 | 'vsock' | 'mpls' | 'ib' | 'kcm' ) ',' | |
23 | ||
24 | TYPE = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | | |
25 | 'packet' ) | |
26 | ||
27 | PROTOCOL = ( 'tcp' | 'udp' | 'icmp' ) | |
28 | ||
29 | eg. | |
30 | network, | |
31 | network inet, | |
32 | ||
33 | Signed-off-by: John Johansen <john.johansen@canonical.com> | |
34 | Acked-by: Seth Arnold <seth.arnold@canonical.com> | |
35 | (cherry picked from commit 56387cbe3f287034ee6959cb9e8f419889e38bd9) | |
36 | --- | |
37 | security/apparmor/.gitignore | 1 + | |
38 | security/apparmor/Makefile | 43 ++++- | |
39 | security/apparmor/apparmorfs.c | 1 + | |
40 | security/apparmor/file.c | 30 +++ | |
41 | security/apparmor/include/audit.h | 26 ++- | |
42 | security/apparmor/include/net.h | 114 +++++++++++ | |
43 | security/apparmor/include/perms.h | 5 +- | |
44 | security/apparmor/include/policy.h | 13 ++ | |
45 | security/apparmor/lib.c | 5 +- | |
46 | security/apparmor/lsm.c | 387 +++++++++++++++++++++++++++++++++++++ | |
47 | security/apparmor/net.c | 184 ++++++++++++++++++ | |
48 | security/apparmor/policy_unpack.c | 47 ++++- | |
49 | 12 files changed, 840 insertions(+), 16 deletions(-) | |
50 | create mode 100644 security/apparmor/include/net.h | |
51 | create mode 100644 security/apparmor/net.c | |
52 | ||
53 | diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore | |
54 | index 9cdec70d72b8..d5b291e94264 100644 | |
55 | --- a/security/apparmor/.gitignore | |
56 | +++ b/security/apparmor/.gitignore | |
57 | @@ -1,5 +1,6 @@ | |
58 | # | |
59 | # Generated include files | |
60 | # | |
61 | +net_names.h | |
62 | capability_names.h | |
63 | rlim_names.h | |
64 | diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile | |
65 | index 81a34426d024..dafdd387d42b 100644 | |
66 | --- a/security/apparmor/Makefile | |
67 | +++ b/security/apparmor/Makefile | |
68 | @@ -4,11 +4,44 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o | |
69 | ||
70 | apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ | |
71 | path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ | |
72 | - resource.o secid.o file.o policy_ns.o label.o mount.o | |
73 | + resource.o secid.o file.o policy_ns.o label.o mount.o net.o | |
74 | apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o | |
75 | ||
76 | -clean-files := capability_names.h rlim_names.h | |
77 | +clean-files := capability_names.h rlim_names.h net_names.h | |
78 | ||
79 | +# Build a lower case string table of address family names | |
80 | +# Transform lines from | |
81 | +# #define AF_LOCAL 1 /* POSIX name for AF_UNIX */ | |
82 | +# #define AF_INET 2 /* Internet IP Protocol */ | |
83 | +# to | |
84 | +# [1] = "local", | |
85 | +# [2] = "inet", | |
86 | +# | |
87 | +# and build the securityfs entries for the mapping. | |
88 | +# Transforms lines from | |
89 | +# #define AF_INET 2 /* Internet IP Protocol */ | |
90 | +# to | |
91 | +# #define AA_SFS_AF_MASK "local inet" | |
92 | +quiet_cmd_make-af = GEN $@ | |
93 | +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ | |
94 | + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ | |
95 | + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ | |
96 | + echo "};" >> $@ ;\ | |
97 | + printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\ | |
98 | + sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ | |
99 | + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\ | |
100 | + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ | |
101 | + | |
102 | +# Build a lower case string table of sock type names | |
103 | +# Transform lines from | |
104 | +# SOCK_STREAM = 1, | |
105 | +# to | |
106 | +# [1] = "stream", | |
107 | +quiet_cmd_make-sock = GEN $@ | |
108 | +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ | |
109 | + sed $^ >>$@ -r -n \ | |
110 | + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ | |
111 | + echo "};" >> $@ | |
112 | ||
113 | # Build a lower case string table of capability names | |
114 | # Transforms lines from | |
115 | @@ -61,6 +94,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ | |
116 | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ | |
117 | ||
118 | $(obj)/capability.o : $(obj)/capability_names.h | |
119 | +$(obj)/net.o : $(obj)/net_names.h | |
120 | $(obj)/resource.o : $(obj)/rlim_names.h | |
121 | $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ | |
122 | $(src)/Makefile | |
123 | @@ -68,3 +102,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ | |
124 | $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ | |
125 | $(src)/Makefile | |
126 | $(call cmd,make-rlim) | |
127 | +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \ | |
128 | + $(srctree)/include/linux/net.h \ | |
129 | + $(src)/Makefile | |
130 | + $(call cmd,make-af) | |
131 | + $(call cmd,make-sock) | |
132 | diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c | |
133 | index 7acea14c850b..125dad5c3fde 100644 | |
134 | --- a/security/apparmor/apparmorfs.c | |
135 | +++ b/security/apparmor/apparmorfs.c | |
136 | @@ -2202,6 +2202,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { | |
137 | AA_SFS_DIR("policy", aa_sfs_entry_policy), | |
138 | AA_SFS_DIR("domain", aa_sfs_entry_domain), | |
139 | AA_SFS_DIR("file", aa_sfs_entry_file), | |
140 | + AA_SFS_DIR("network", aa_sfs_entry_network), | |
141 | AA_SFS_DIR("mount", aa_sfs_entry_mount), | |
142 | AA_SFS_DIR("namespaces", aa_sfs_entry_ns), | |
143 | AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), | |
144 | diff --git a/security/apparmor/file.c b/security/apparmor/file.c | |
145 | index 3382518b87fa..db80221891c6 100644 | |
146 | --- a/security/apparmor/file.c | |
147 | +++ b/security/apparmor/file.c | |
148 | @@ -21,6 +21,7 @@ | |
149 | #include "include/context.h" | |
150 | #include "include/file.h" | |
151 | #include "include/match.h" | |
152 | +#include "include/net.h" | |
153 | #include "include/path.h" | |
154 | #include "include/policy.h" | |
155 | #include "include/label.h" | |
156 | @@ -566,6 +567,32 @@ static int __file_path_perm(const char *op, struct aa_label *label, | |
157 | return error; | |
158 | } | |
159 | ||
160 | +static int __file_sock_perm(const char *op, struct aa_label *label, | |
161 | + struct aa_label *flabel, struct file *file, | |
162 | + u32 request, u32 denied) | |
163 | +{ | |
164 | + struct socket *sock = (struct socket *) file->private_data; | |
165 | + int error; | |
166 | + | |
167 | + AA_BUG(!sock); | |
168 | + | |
169 | + /* revalidation due to label out of date. No revocation at this time */ | |
170 | + if (!denied && aa_label_is_subset(flabel, label)) | |
171 | + return 0; | |
172 | + | |
173 | + /* TODO: improve to skip profiles cached in flabel */ | |
174 | + error = aa_sock_file_perm(label, op, request, sock); | |
175 | + if (denied) { | |
176 | + /* TODO: improve to skip profiles checked above */ | |
177 | + /* check every profile in file label to is cached */ | |
178 | + last_error(error, aa_sock_file_perm(flabel, op, request, sock)); | |
179 | + } | |
180 | + if (!error) | |
181 | + update_file_ctx(file_ctx(file), label, request); | |
182 | + | |
183 | + return error; | |
184 | +} | |
185 | + | |
186 | /** | |
187 | * aa_file_perm - do permission revalidation check & audit for @file | |
188 | * @op: operation being checked | |
189 | @@ -610,6 +637,9 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file, | |
190 | error = __file_path_perm(op, label, flabel, file, request, | |
191 | denied); | |
192 | ||
193 | + else if (S_ISSOCK(file_inode(file)->i_mode)) | |
194 | + error = __file_sock_perm(op, label, flabel, file, request, | |
195 | + denied); | |
196 | done: | |
197 | rcu_read_unlock(); | |
198 | ||
199 | diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h | |
200 | index 620e81169659..ff4316e1068d 100644 | |
201 | --- a/security/apparmor/include/audit.h | |
202 | +++ b/security/apparmor/include/audit.h | |
203 | @@ -121,21 +121,29 @@ struct apparmor_audit_data { | |
204 | /* these entries require a custom callback fn */ | |
205 | struct { | |
206 | struct aa_label *peer; | |
207 | - struct { | |
208 | - const char *target; | |
209 | - kuid_t ouid; | |
210 | - } fs; | |
211 | + union { | |
212 | + struct { | |
213 | + kuid_t ouid; | |
214 | + const char *target; | |
215 | + } fs; | |
216 | + struct { | |
217 | + int type, protocol; | |
218 | + struct sock *peer_sk; | |
219 | + void *addr; | |
220 | + int addrlen; | |
221 | + } net; | |
222 | + int signal; | |
223 | + struct { | |
224 | + int rlim; | |
225 | + unsigned long max; | |
226 | + } rlim; | |
227 | + }; | |
228 | }; | |
229 | struct { | |
230 | struct aa_profile *profile; | |
231 | const char *ns; | |
232 | long pos; | |
233 | } iface; | |
234 | - int signal; | |
235 | - struct { | |
236 | - int rlim; | |
237 | - unsigned long max; | |
238 | - } rlim; | |
239 | struct { | |
240 | const char *src_name; | |
241 | const char *type; | |
242 | diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h | |
243 | new file mode 100644 | |
244 | index 000000000000..140c8efcf364 | |
245 | --- /dev/null | |
246 | +++ b/security/apparmor/include/net.h | |
247 | @@ -0,0 +1,114 @@ | |
248 | +/* | |
249 | + * AppArmor security module | |
250 | + * | |
251 | + * This file contains AppArmor network mediation definitions. | |
252 | + * | |
253 | + * Copyright (C) 1998-2008 Novell/SUSE | |
254 | + * Copyright 2009-2017 Canonical Ltd. | |
255 | + * | |
256 | + * This program is free software; you can redistribute it and/or | |
257 | + * modify it under the terms of the GNU General Public License as | |
258 | + * published by the Free Software Foundation, version 2 of the | |
259 | + * License. | |
260 | + */ | |
261 | + | |
262 | +#ifndef __AA_NET_H | |
263 | +#define __AA_NET_H | |
264 | + | |
265 | +#include <net/sock.h> | |
266 | +#include <linux/path.h> | |
267 | + | |
268 | +#include "apparmorfs.h" | |
269 | +#include "label.h" | |
270 | +#include "perms.h" | |
271 | +#include "policy.h" | |
272 | + | |
273 | +#define AA_MAY_SEND AA_MAY_WRITE | |
274 | +#define AA_MAY_RECEIVE AA_MAY_READ | |
275 | + | |
276 | +#define AA_MAY_SHUTDOWN AA_MAY_DELETE | |
277 | + | |
278 | +#define AA_MAY_CONNECT AA_MAY_OPEN | |
279 | +#define AA_MAY_ACCEPT 0x00100000 | |
280 | + | |
281 | +#define AA_MAY_BIND 0x00200000 | |
282 | +#define AA_MAY_LISTEN 0x00400000 | |
283 | + | |
284 | +#define AA_MAY_SETOPT 0x01000000 | |
285 | +#define AA_MAY_GETOPT 0x02000000 | |
286 | + | |
287 | +#define NET_PERMS_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ | |
288 | + AA_MAY_SHUTDOWN | AA_MAY_BIND | AA_MAY_LISTEN | \ | |
289 | + AA_MAY_CONNECT | AA_MAY_ACCEPT | AA_MAY_SETATTR | \ | |
290 | + AA_MAY_GETATTR | AA_MAY_SETOPT | AA_MAY_GETOPT) | |
291 | + | |
292 | +#define NET_FS_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ | |
293 | + AA_MAY_SHUTDOWN | AA_MAY_CONNECT | AA_MAY_RENAME |\ | |
294 | + AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_CHMOD | \ | |
295 | + AA_MAY_CHOWN | AA_MAY_CHGRP | AA_MAY_LOCK | \ | |
296 | + AA_MAY_MPROT) | |
297 | + | |
298 | +#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \ | |
299 | + AA_MAY_ACCEPT) | |
300 | +struct aa_sk_ctx { | |
301 | + struct aa_label *label; | |
302 | + struct aa_label *peer; | |
303 | + struct path path; | |
304 | +}; | |
305 | + | |
306 | +#define SK_CTX(X) ((X)->sk_security) | |
307 | +#define SOCK_ctx(X) SOCK_INODE(X)->i_security | |
308 | +#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \ | |
309 | + struct lsm_network_audit NAME ## _net = { .sk = (SK), \ | |
310 | + .family = (F)}; \ | |
311 | + DEFINE_AUDIT_DATA(NAME, \ | |
312 | + ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \ | |
313 | + LSM_AUDIT_DATA_NONE, \ | |
314 | + OP); \ | |
315 | + NAME.u.net = &(NAME ## _net); \ | |
316 | + aad(&NAME)->net.type = (T); \ | |
317 | + aad(&NAME)->net.protocol = (P) | |
318 | + | |
319 | +#define DEFINE_AUDIT_SK(NAME, OP, SK) \ | |
320 | + DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ | |
321 | + (SK)->sk_protocol) | |
322 | + | |
323 | +/* struct aa_net - network confinement data | |
324 | + * @allow: basic network families permissions | |
325 | + * @audit: which network permissions to force audit | |
326 | + * @quiet: which network permissions to quiet rejects | |
327 | + */ | |
328 | +struct aa_net { | |
329 | + u16 allow[AF_MAX]; | |
330 | + u16 audit[AF_MAX]; | |
331 | + u16 quiet[AF_MAX]; | |
332 | +}; | |
333 | + | |
334 | + | |
335 | +extern struct aa_sfs_entry aa_sfs_entry_network[]; | |
336 | + | |
337 | +void audit_net_cb(struct audit_buffer *ab, void *va); | |
338 | +int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, | |
339 | + u32 request, u16 family, int type); | |
340 | +int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, | |
341 | + int type, int protocol); | |
342 | +static inline int aa_profile_af_sk_perm(struct aa_profile *profile, | |
343 | + struct common_audit_data *sa, | |
344 | + u32 request, | |
345 | + struct sock *sk) | |
346 | +{ | |
347 | + return aa_profile_af_perm(profile, sa, request, sk->sk_family, | |
348 | + sk->sk_type); | |
349 | +} | |
350 | +int aa_sk_perm(const char *op, u32 request, struct sock *sk); | |
351 | + | |
352 | +int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, | |
353 | + struct socket *sock); | |
354 | + | |
355 | + | |
356 | +static inline void aa_free_net_rules(struct aa_net *new) | |
357 | +{ | |
358 | + /* NOP */ | |
359 | +} | |
360 | + | |
361 | +#endif /* __AA_NET_H */ | |
362 | diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h | |
363 | index 2b27bb79aec4..af04d5a7d73d 100644 | |
364 | --- a/security/apparmor/include/perms.h | |
365 | +++ b/security/apparmor/include/perms.h | |
366 | @@ -135,9 +135,10 @@ extern struct aa_perms allperms; | |
367 | ||
368 | ||
369 | void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask); | |
370 | -void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask); | |
371 | +void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, | |
372 | + u32 mask); | |
373 | void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, | |
374 | - u32 chrsmask, const char **names, u32 namesmask); | |
375 | + u32 chrsmask, const char * const *names, u32 namesmask); | |
376 | void aa_apply_modes_to_perms(struct aa_profile *profile, | |
377 | struct aa_perms *perms); | |
378 | void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, | |
379 | diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h | |
380 | index 17fe41a9cac3..4364088a0b9e 100644 | |
381 | --- a/security/apparmor/include/policy.h | |
382 | +++ b/security/apparmor/include/policy.h | |
383 | @@ -30,6 +30,7 @@ | |
384 | #include "file.h" | |
385 | #include "lib.h" | |
386 | #include "label.h" | |
387 | +#include "net.h" | |
388 | #include "perms.h" | |
389 | #include "resource.h" | |
390 | ||
391 | @@ -111,6 +112,7 @@ struct aa_data { | |
392 | * @policy: general match rules governing policy | |
393 | * @file: The set of rules governing basic file access and domain transitions | |
394 | * @caps: capabilities for the profile | |
395 | + * @net: network controls for the profile | |
396 | * @rlimits: rlimits for the profile | |
397 | * | |
398 | * @dents: dentries for the profiles file entries in apparmorfs | |
399 | @@ -148,6 +150,7 @@ struct aa_profile { | |
400 | struct aa_policydb policy; | |
401 | struct aa_file_rules file; | |
402 | struct aa_caps caps; | |
403 | + struct aa_net net; | |
404 | struct aa_rlimit rlimits; | |
405 | ||
406 | struct aa_loaddata *rawdata; | |
407 | @@ -220,6 +223,16 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile, | |
408 | return 0; | |
409 | } | |
410 | ||
411 | +static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, | |
412 | + u16 AF) { | |
413 | + unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); | |
414 | + u16 be_af = cpu_to_be16(AF); | |
415 | + | |
416 | + if (!state) | |
417 | + return 0; | |
418 | + return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); | |
419 | +} | |
420 | + | |
421 | /** | |
422 | * aa_get_profile - increment refcount on profile @p | |
423 | * @p: profile (MAYBE NULL) | |
424 | diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c | |
425 | index 08ca26bcca77..8818621b5d95 100644 | |
426 | --- a/security/apparmor/lib.c | |
427 | +++ b/security/apparmor/lib.c | |
428 | @@ -211,7 +211,8 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask) | |
429 | *str = '\0'; | |
430 | } | |
431 | ||
432 | -void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) | |
433 | +void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, | |
434 | + u32 mask) | |
435 | { | |
436 | const char *fmt = "%s"; | |
437 | unsigned int i, perm = 1; | |
438 | @@ -229,7 +230,7 @@ void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) | |
439 | } | |
440 | ||
441 | void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, | |
442 | - u32 chrsmask, const char **names, u32 namesmask) | |
443 | + u32 chrsmask, const char * const *names, u32 namesmask) | |
444 | { | |
445 | char str[33]; | |
446 | ||
447 | diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c | |
448 | index 4ad0b3a45142..cc5ab23a2d84 100644 | |
449 | --- a/security/apparmor/lsm.c | |
450 | +++ b/security/apparmor/lsm.c | |
451 | @@ -33,6 +33,7 @@ | |
452 | #include "include/context.h" | |
453 | #include "include/file.h" | |
454 | #include "include/ipc.h" | |
455 | +#include "include/net.h" | |
456 | #include "include/path.h" | |
457 | #include "include/label.h" | |
458 | #include "include/policy.h" | |
459 | @@ -736,6 +737,368 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info, | |
460 | return error; | |
461 | } | |
462 | ||
463 | +/** | |
464 | + * apparmor_sk_alloc_security - allocate and attach the sk_security field | |
465 | + */ | |
466 | +static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags) | |
467 | +{ | |
468 | + struct aa_sk_ctx *ctx; | |
469 | + | |
470 | + ctx = kzalloc(sizeof(*ctx), flags); | |
471 | + if (!ctx) | |
472 | + return -ENOMEM; | |
473 | + | |
474 | + SK_CTX(sk) = ctx; | |
475 | + | |
476 | + return 0; | |
477 | +} | |
478 | + | |
479 | +/** | |
480 | + * apparmor_sk_free_security - free the sk_security field | |
481 | + */ | |
482 | +static void apparmor_sk_free_security(struct sock *sk) | |
483 | +{ | |
484 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
485 | + | |
486 | + SK_CTX(sk) = NULL; | |
487 | + aa_put_label(ctx->label); | |
488 | + aa_put_label(ctx->peer); | |
489 | + path_put(&ctx->path); | |
490 | + kfree(ctx); | |
491 | +} | |
492 | + | |
493 | +/** | |
494 | + * apparmor_clone_security - clone the sk_security field | |
495 | + */ | |
496 | +static void apparmor_sk_clone_security(const struct sock *sk, | |
497 | + struct sock *newsk) | |
498 | +{ | |
499 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
500 | + struct aa_sk_ctx *new = SK_CTX(newsk); | |
501 | + | |
502 | + new->label = aa_get_label(ctx->label); | |
503 | + new->peer = aa_get_label(ctx->peer); | |
504 | + new->path = ctx->path; | |
505 | + path_get(&new->path); | |
506 | +} | |
507 | + | |
508 | +static int aa_sock_create_perm(struct aa_label *label, int family, int type, | |
509 | + int protocol) | |
510 | +{ | |
511 | + AA_BUG(!label); | |
512 | + AA_BUG(in_interrupt()); | |
513 | + | |
514 | + return aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, family, type, | |
515 | + protocol); | |
516 | +} | |
517 | + | |
518 | + | |
519 | +/** | |
520 | + * apparmor_socket_create - check perms before creating a new socket | |
521 | + */ | |
522 | +static int apparmor_socket_create(int family, int type, int protocol, int kern) | |
523 | +{ | |
524 | + struct aa_label *label; | |
525 | + int error = 0; | |
526 | + | |
527 | + label = begin_current_label_crit_section(); | |
528 | + if (!(kern || unconfined(label))) | |
529 | + error = aa_sock_create_perm(label, family, type, protocol); | |
530 | + end_current_label_crit_section(label); | |
531 | + | |
532 | + return error; | |
533 | +} | |
534 | + | |
535 | +/** | |
536 | + * apparmor_socket_post_create - setup the per-socket security struct | |
537 | + * | |
538 | + * Note: | |
539 | + * - kernel sockets currently labeled unconfined but we may want to | |
540 | + * move to a special kernel label | |
541 | + * - socket may not have sk here if created with sock_create_lite or | |
542 | + * sock_alloc. These should be accept cases which will be handled in | |
543 | + * sock_graft. | |
544 | + */ | |
545 | +static int apparmor_socket_post_create(struct socket *sock, int family, | |
546 | + int type, int protocol, int kern) | |
547 | +{ | |
548 | + struct aa_label *label; | |
549 | + | |
550 | + if (kern) { | |
551 | + struct aa_ns *ns = aa_get_current_ns(); | |
552 | + | |
553 | + label = aa_get_label(ns_unconfined(ns)); | |
554 | + aa_put_ns(ns); | |
555 | + } else | |
556 | + label = aa_get_current_label(); | |
557 | + | |
558 | + if (sock->sk) { | |
559 | + struct aa_sk_ctx *ctx = SK_CTX(sock->sk); | |
560 | + | |
561 | + aa_put_label(ctx->label); | |
562 | + ctx->label = aa_get_label(label); | |
563 | + } | |
564 | + aa_put_label(label); | |
565 | + | |
566 | + return 0; | |
567 | +} | |
568 | + | |
569 | +/** | |
570 | + * apparmor_socket_bind - check perms before bind addr to socket | |
571 | + */ | |
572 | +static int apparmor_socket_bind(struct socket *sock, | |
573 | + struct sockaddr *address, int addrlen) | |
574 | +{ | |
575 | + AA_BUG(!sock); | |
576 | + AA_BUG(!sock->sk); | |
577 | + AA_BUG(!address); | |
578 | + AA_BUG(in_interrupt()); | |
579 | + | |
580 | + return aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk); | |
581 | +} | |
582 | + | |
583 | +/** | |
584 | + * apparmor_socket_connect - check perms before connecting @sock to @address | |
585 | + */ | |
586 | +static int apparmor_socket_connect(struct socket *sock, | |
587 | + struct sockaddr *address, int addrlen) | |
588 | +{ | |
589 | + AA_BUG(!sock); | |
590 | + AA_BUG(!sock->sk); | |
591 | + AA_BUG(!address); | |
592 | + AA_BUG(in_interrupt()); | |
593 | + | |
594 | + return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk); | |
595 | +} | |
596 | + | |
597 | +/** | |
598 | + * apparmor_socket_list - check perms before allowing listen | |
599 | + */ | |
600 | +static int apparmor_socket_listen(struct socket *sock, int backlog) | |
601 | +{ | |
602 | + AA_BUG(!sock); | |
603 | + AA_BUG(!sock->sk); | |
604 | + AA_BUG(in_interrupt()); | |
605 | + | |
606 | + return aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk); | |
607 | +} | |
608 | + | |
609 | +/** | |
610 | + * apparmor_socket_accept - check perms before accepting a new connection. | |
611 | + * | |
612 | + * Note: while @newsock is created and has some information, the accept | |
613 | + * has not been done. | |
614 | + */ | |
615 | +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) | |
616 | +{ | |
617 | + AA_BUG(!sock); | |
618 | + AA_BUG(!sock->sk); | |
619 | + AA_BUG(!newsock); | |
620 | + AA_BUG(in_interrupt()); | |
621 | + | |
622 | + return aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk); | |
623 | +} | |
624 | + | |
625 | +static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock, | |
626 | + struct msghdr *msg, int size) | |
627 | +{ | |
628 | + AA_BUG(!sock); | |
629 | + AA_BUG(!sock->sk); | |
630 | + AA_BUG(!msg); | |
631 | + AA_BUG(in_interrupt()); | |
632 | + | |
633 | + return aa_sk_perm(op, request, sock->sk); | |
634 | +} | |
635 | + | |
636 | +/** | |
637 | + * apparmor_socket_sendmsg - check perms before sending msg to another socket | |
638 | + */ | |
639 | +static int apparmor_socket_sendmsg(struct socket *sock, | |
640 | + struct msghdr *msg, int size) | |
641 | +{ | |
642 | + return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size); | |
643 | +} | |
644 | + | |
645 | +/** | |
646 | + * apparmor_socket_recvmsg - check perms before receiving a message | |
647 | + */ | |
648 | +static int apparmor_socket_recvmsg(struct socket *sock, | |
649 | + struct msghdr *msg, int size, int flags) | |
650 | +{ | |
651 | + return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size); | |
652 | +} | |
653 | + | |
654 | +/* revaliation, get/set attr, shutdown */ | |
655 | +static int aa_sock_perm(const char *op, u32 request, struct socket *sock) | |
656 | +{ | |
657 | + AA_BUG(!sock); | |
658 | + AA_BUG(!sock->sk); | |
659 | + AA_BUG(in_interrupt()); | |
660 | + | |
661 | + return aa_sk_perm(op, request, sock->sk); | |
662 | +} | |
663 | + | |
664 | +/** | |
665 | + * apparmor_socket_getsockname - check perms before getting the local address | |
666 | + */ | |
667 | +static int apparmor_socket_getsockname(struct socket *sock) | |
668 | +{ | |
669 | + return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock); | |
670 | +} | |
671 | + | |
672 | +/** | |
673 | + * apparmor_socket_getpeername - check perms before getting remote address | |
674 | + */ | |
675 | +static int apparmor_socket_getpeername(struct socket *sock) | |
676 | +{ | |
677 | + return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock); | |
678 | +} | |
679 | + | |
680 | +/* revaliation, get/set attr, opt */ | |
681 | +static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, | |
682 | + int level, int optname) | |
683 | +{ | |
684 | + AA_BUG(!sock); | |
685 | + AA_BUG(!sock->sk); | |
686 | + AA_BUG(in_interrupt()); | |
687 | + | |
688 | + return aa_sk_perm(op, request, sock->sk); | |
689 | +} | |
690 | + | |
691 | +/** | |
692 | + * apparmor_getsockopt - check perms before getting socket options | |
693 | + */ | |
694 | +static int apparmor_socket_getsockopt(struct socket *sock, int level, | |
695 | + int optname) | |
696 | +{ | |
697 | + return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock, | |
698 | + level, optname); | |
699 | +} | |
700 | + | |
701 | +/** | |
702 | + * apparmor_setsockopt - check perms before setting socket options | |
703 | + */ | |
704 | +static int apparmor_socket_setsockopt(struct socket *sock, int level, | |
705 | + int optname) | |
706 | +{ | |
707 | + return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock, | |
708 | + level, optname); | |
709 | +} | |
710 | + | |
711 | +/** | |
712 | + * apparmor_socket_shutdown - check perms before shutting down @sock conn | |
713 | + */ | |
714 | +static int apparmor_socket_shutdown(struct socket *sock, int how) | |
715 | +{ | |
716 | + return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock); | |
717 | +} | |
718 | + | |
719 | +/** | |
720 | + * apparmor_socket_sock_recv_skb - check perms before associating skb to sk | |
721 | + * | |
722 | + * Note: can not sleep may be called with locks held | |
723 | + * | |
724 | + * dont want protocol specific in __skb_recv_datagram() | |
725 | + * to deny an incoming connection socket_sock_rcv_skb() | |
726 | + */ | |
727 | +static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |
728 | +{ | |
729 | + return 0; | |
730 | +} | |
731 | + | |
732 | + | |
733 | +static struct aa_label *sk_peer_label(struct sock *sk) | |
734 | +{ | |
735 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
736 | + | |
737 | + if (ctx->peer) | |
738 | + return ctx->peer; | |
739 | + | |
740 | + return ERR_PTR(-ENOPROTOOPT); | |
741 | +} | |
742 | + | |
743 | +/** | |
744 | + * apparmor_socket_getpeersec_stream - get security context of peer | |
745 | + * | |
746 | + * Note: for tcp only valid if using ipsec or cipso on lan | |
747 | + */ | |
748 | +static int apparmor_socket_getpeersec_stream(struct socket *sock, | |
749 | + char __user *optval, | |
750 | + int __user *optlen, | |
751 | + unsigned int len) | |
752 | +{ | |
753 | + char *name; | |
754 | + int slen, error = 0; | |
755 | + struct aa_label *label; | |
756 | + struct aa_label *peer; | |
757 | + | |
758 | + label = begin_current_label_crit_section(); | |
759 | + peer = sk_peer_label(sock->sk); | |
760 | + if (IS_ERR(peer)) { | |
761 | + error = PTR_ERR(peer); | |
762 | + goto done; | |
763 | + } | |
764 | + slen = aa_label_asxprint(&name, labels_ns(label), peer, | |
765 | + FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | | |
766 | + FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); | |
767 | + /* don't include terminating \0 in slen, it breaks some apps */ | |
768 | + if (slen < 0) { | |
769 | + error = -ENOMEM; | |
770 | + } else { | |
771 | + if (slen > len) { | |
772 | + error = -ERANGE; | |
773 | + } else if (copy_to_user(optval, name, slen)) { | |
774 | + error = -EFAULT; | |
775 | + goto out; | |
776 | + } | |
777 | + if (put_user(slen, optlen)) | |
778 | + error = -EFAULT; | |
779 | +out: | |
780 | + kfree(name); | |
781 | + | |
782 | + } | |
783 | + | |
784 | +done: | |
785 | + end_current_label_crit_section(label); | |
786 | + | |
787 | + return error; | |
788 | +} | |
789 | + | |
790 | +/** | |
791 | + * apparmor_socket_getpeersec_dgram - get security label of packet | |
792 | + * @sock: the peer socket | |
793 | + * @skb: packet data | |
794 | + * @secid: pointer to where to put the secid of the packet | |
795 | + * | |
796 | + * Sets the netlabel socket state on sk from parent | |
797 | + */ | |
798 | +static int apparmor_socket_getpeersec_dgram(struct socket *sock, | |
799 | + struct sk_buff *skb, u32 *secid) | |
800 | + | |
801 | +{ | |
802 | + /* TODO: requires secid support */ | |
803 | + return -ENOPROTOOPT; | |
804 | +} | |
805 | + | |
806 | +/** | |
807 | + * apparmor_sock_graft - Initialize newly created socket | |
808 | + * @sk: child sock | |
809 | + * @parent: parent socket | |
810 | + * | |
811 | + * Note: could set off of SOCK_CTX(parent) but need to track inode and we can | |
812 | + * just set sk security information off of current creating process label | |
813 | + * Labeling of sk for accept case - probably should be sock based | |
814 | + * instead of task, because of the case where an implicitly labeled | |
815 | + * socket is shared by different tasks. | |
816 | + */ | |
817 | +static void apparmor_sock_graft(struct sock *sk, struct socket *parent) | |
818 | +{ | |
819 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
820 | + | |
821 | + if (!ctx->label) | |
822 | + ctx->label = aa_get_current_label(); | |
823 | +} | |
824 | + | |
825 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |
826 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), | |
827 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), | |
828 | @@ -770,6 +1133,30 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |
829 | LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), | |
830 | LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), | |
831 | ||
832 | + LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security), | |
833 | + LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), | |
834 | + LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), | |
835 | + | |
836 | + LSM_HOOK_INIT(socket_create, apparmor_socket_create), | |
837 | + LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create), | |
838 | + LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), | |
839 | + LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), | |
840 | + LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), | |
841 | + LSM_HOOK_INIT(socket_accept, apparmor_socket_accept), | |
842 | + LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg), | |
843 | + LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg), | |
844 | + LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname), | |
845 | + LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername), | |
846 | + LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), | |
847 | + LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), | |
848 | + LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), | |
849 | + LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb), | |
850 | + LSM_HOOK_INIT(socket_getpeersec_stream, | |
851 | + apparmor_socket_getpeersec_stream), | |
852 | + LSM_HOOK_INIT(socket_getpeersec_dgram, | |
853 | + apparmor_socket_getpeersec_dgram), | |
854 | + LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), | |
855 | + | |
856 | LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), | |
857 | LSM_HOOK_INIT(cred_free, apparmor_cred_free), | |
858 | LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), | |
859 | diff --git a/security/apparmor/net.c b/security/apparmor/net.c | |
860 | new file mode 100644 | |
861 | index 000000000000..33d54435f8d6 | |
862 | --- /dev/null | |
863 | +++ b/security/apparmor/net.c | |
864 | @@ -0,0 +1,184 @@ | |
865 | +/* | |
866 | + * AppArmor security module | |
867 | + * | |
868 | + * This file contains AppArmor network mediation | |
869 | + * | |
870 | + * Copyright (C) 1998-2008 Novell/SUSE | |
871 | + * Copyright 2009-2017 Canonical Ltd. | |
872 | + * | |
873 | + * This program is free software; you can redistribute it and/or | |
874 | + * modify it under the terms of the GNU General Public License as | |
875 | + * published by the Free Software Foundation, version 2 of the | |
876 | + * License. | |
877 | + */ | |
878 | + | |
879 | +#include "include/apparmor.h" | |
880 | +#include "include/audit.h" | |
881 | +#include "include/context.h" | |
882 | +#include "include/label.h" | |
883 | +#include "include/net.h" | |
884 | +#include "include/policy.h" | |
885 | + | |
886 | +#include "net_names.h" | |
887 | + | |
888 | + | |
889 | +struct aa_sfs_entry aa_sfs_entry_network[] = { | |
890 | + AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), | |
891 | + { } | |
892 | +}; | |
893 | + | |
894 | +static const char * const net_mask_names[] = { | |
895 | + "unknown", | |
896 | + "send", | |
897 | + "receive", | |
898 | + "unknown", | |
899 | + | |
900 | + "create", | |
901 | + "shutdown", | |
902 | + "connect", | |
903 | + "unknown", | |
904 | + | |
905 | + "setattr", | |
906 | + "getattr", | |
907 | + "setcred", | |
908 | + "getcred", | |
909 | + | |
910 | + "chmod", | |
911 | + "chown", | |
912 | + "chgrp", | |
913 | + "lock", | |
914 | + | |
915 | + "mmap", | |
916 | + "mprot", | |
917 | + "unknown", | |
918 | + "unknown", | |
919 | + | |
920 | + "accept", | |
921 | + "bind", | |
922 | + "listen", | |
923 | + "unknown", | |
924 | + | |
925 | + "setopt", | |
926 | + "getopt", | |
927 | + "unknown", | |
928 | + "unknown", | |
929 | + | |
930 | + "unknown", | |
931 | + "unknown", | |
932 | + "unknown", | |
933 | + "unknown", | |
934 | +}; | |
935 | + | |
936 | + | |
937 | +/* audit callback for net specific fields */ | |
938 | +void audit_net_cb(struct audit_buffer *ab, void *va) | |
939 | +{ | |
940 | + struct common_audit_data *sa = va; | |
941 | + | |
942 | + audit_log_format(ab, " family="); | |
943 | + if (address_family_names[sa->u.net->family]) | |
944 | + audit_log_string(ab, address_family_names[sa->u.net->family]); | |
945 | + else | |
946 | + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family); | |
947 | + audit_log_format(ab, " sock_type="); | |
948 | + if (sock_type_names[aad(sa)->net.type]) | |
949 | + audit_log_string(ab, sock_type_names[aad(sa)->net.type]); | |
950 | + else | |
951 | + audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type); | |
952 | + audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); | |
953 | + | |
954 | + if (aad(sa)->request & NET_PERMS_MASK) { | |
955 | + audit_log_format(ab, " requested_mask="); | |
956 | + aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0, | |
957 | + net_mask_names, NET_PERMS_MASK); | |
958 | + | |
959 | + if (aad(sa)->denied & NET_PERMS_MASK) { | |
960 | + audit_log_format(ab, " denied_mask="); | |
961 | + aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0, | |
962 | + net_mask_names, NET_PERMS_MASK); | |
963 | + } | |
964 | + } | |
965 | + if (aad(sa)->peer) { | |
966 | + audit_log_format(ab, " peer="); | |
967 | + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, | |
968 | + FLAGS_NONE, GFP_ATOMIC); | |
969 | + } | |
970 | +} | |
971 | + | |
972 | + | |
973 | +/* Generic af perm */ | |
974 | +int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, | |
975 | + u32 request, u16 family, int type) | |
976 | +{ | |
977 | + struct aa_perms perms = { }; | |
978 | + | |
979 | + AA_BUG(family >= AF_MAX); | |
980 | + AA_BUG(type < 0 || type >= SOCK_MAX); | |
981 | + | |
982 | + if (profile_unconfined(profile)) | |
983 | + return 0; | |
984 | + | |
985 | + perms.allow = (profile->net.allow[family] & (1 << type)) ? | |
986 | + ALL_PERMS_MASK : 0; | |
987 | + perms.audit = (profile->net.audit[family] & (1 << type)) ? | |
988 | + ALL_PERMS_MASK : 0; | |
989 | + perms.quiet = (profile->net.quiet[family] & (1 << type)) ? | |
990 | + ALL_PERMS_MASK : 0; | |
991 | + aa_apply_modes_to_perms(profile, &perms); | |
992 | + | |
993 | + return aa_check_perms(profile, &perms, request, sa, audit_net_cb); | |
994 | +} | |
995 | + | |
996 | +int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, | |
997 | + int type, int protocol) | |
998 | +{ | |
999 | + struct aa_profile *profile; | |
1000 | + DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); | |
1001 | + | |
1002 | + return fn_for_each_confined(label, profile, | |
1003 | + aa_profile_af_perm(profile, &sa, request, family, | |
1004 | + type)); | |
1005 | +} | |
1006 | + | |
1007 | +static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, | |
1008 | + struct sock *sk) | |
1009 | +{ | |
1010 | + struct aa_profile *profile; | |
1011 | + DEFINE_AUDIT_SK(sa, op, sk); | |
1012 | + | |
1013 | + AA_BUG(!label); | |
1014 | + AA_BUG(!sk); | |
1015 | + | |
1016 | + if (unconfined(label)) | |
1017 | + return 0; | |
1018 | + | |
1019 | + return fn_for_each_confined(label, profile, | |
1020 | + aa_profile_af_sk_perm(profile, &sa, request, sk)); | |
1021 | +} | |
1022 | + | |
1023 | +int aa_sk_perm(const char *op, u32 request, struct sock *sk) | |
1024 | +{ | |
1025 | + struct aa_label *label; | |
1026 | + int error; | |
1027 | + | |
1028 | + AA_BUG(!sk); | |
1029 | + AA_BUG(in_interrupt()); | |
1030 | + | |
1031 | + /* TODO: switch to begin_current_label ???? */ | |
1032 | + label = begin_current_label_crit_section(); | |
1033 | + error = aa_label_sk_perm(label, op, request, sk); | |
1034 | + end_current_label_crit_section(label); | |
1035 | + | |
1036 | + return error; | |
1037 | +} | |
1038 | + | |
1039 | + | |
1040 | +int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, | |
1041 | + struct socket *sock) | |
1042 | +{ | |
1043 | + AA_BUG(!label); | |
1044 | + AA_BUG(!sock); | |
1045 | + AA_BUG(!sock->sk); | |
1046 | + | |
1047 | + return aa_label_sk_perm(label, op, request, sock->sk); | |
1048 | +} | |
1049 | diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c | |
1050 | index 4ede87c30f8b..5a2aec358322 100644 | |
1051 | --- a/security/apparmor/policy_unpack.c | |
1052 | +++ b/security/apparmor/policy_unpack.c | |
1053 | @@ -275,6 +275,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name) | |
1054 | return 0; | |
1055 | } | |
1056 | ||
1057 | +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) | |
1058 | +{ | |
1059 | + if (unpack_nameX(e, AA_U16, name)) { | |
1060 | + if (!inbounds(e, sizeof(u16))) | |
1061 | + return 0; | |
1062 | + if (data) | |
1063 | + *data = le16_to_cpu(get_unaligned((__le16 *) e->pos)); | |
1064 | + e->pos += sizeof(u16); | |
1065 | + return 1; | |
1066 | + } | |
1067 | + return 0; | |
1068 | +} | |
1069 | + | |
1070 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) | |
1071 | { | |
1072 | if (unpack_nameX(e, AA_U32, name)) { | |
1073 | @@ -584,7 +597,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |
1074 | struct aa_profile *profile = NULL; | |
1075 | const char *tmpname, *tmpns = NULL, *name = NULL; | |
1076 | const char *info = "failed to unpack profile"; | |
1077 | - size_t ns_len; | |
1078 | + size_t size = 0, ns_len; | |
1079 | struct rhashtable_params params = { 0 }; | |
1080 | char *key = NULL; | |
1081 | struct aa_data *data; | |
1082 | @@ -717,6 +730,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |
1083 | goto fail; | |
1084 | } | |
1085 | ||
1086 | + size = unpack_array(e, "net_allowed_af"); | |
1087 | + if (size) { | |
1088 | + | |
1089 | + for (i = 0; i < size; i++) { | |
1090 | + /* discard extraneous rules that this kernel will | |
1091 | + * never request | |
1092 | + */ | |
1093 | + if (i >= AF_MAX) { | |
1094 | + u16 tmp; | |
1095 | + | |
1096 | + if (!unpack_u16(e, &tmp, NULL) || | |
1097 | + !unpack_u16(e, &tmp, NULL) || | |
1098 | + !unpack_u16(e, &tmp, NULL)) | |
1099 | + goto fail; | |
1100 | + continue; | |
1101 | + } | |
1102 | + if (!unpack_u16(e, &profile->net.allow[i], NULL)) | |
1103 | + goto fail; | |
1104 | + if (!unpack_u16(e, &profile->net.audit[i], NULL)) | |
1105 | + goto fail; | |
1106 | + if (!unpack_u16(e, &profile->net.quiet[i], NULL)) | |
1107 | + goto fail; | |
1108 | + } | |
1109 | + if (!unpack_nameX(e, AA_ARRAYEND, NULL)) | |
1110 | + goto fail; | |
1111 | + } | |
1112 | + if (VERSION_LT(e->version, v7)) { | |
1113 | + /* pre v7 policy always allowed these */ | |
1114 | + profile->net.allow[AF_UNIX] = 0xffff; | |
1115 | + profile->net.allow[AF_NETLINK] = 0xffff; | |
1116 | + } | |
1117 | + | |
1118 | if (unpack_nameX(e, AA_STRUCT, "policydb")) { | |
1119 | /* generic policy dfa - optional and may be NULL */ | |
1120 | info = "failed to unpack policydb"; | |
1121 | -- | |
1122 | 2.11.0 | |
1123 |