]>
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 | |
a6877ea3 | 203 | @@ -121,9 +121,15 @@ struct apparmor_audit_data { |
daaa955e | 204 | struct aa_label *peer; |
a6877ea3 JR |
205 | union { |
206 | struct { | |
29e30844 | 207 | - const char *target; |
a6877ea3 | 208 | kuid_t ouid; |
daaa955e | 209 | + const char *target; |
a6877ea3 | 210 | } fs; |
daaa955e AM |
211 | + struct { |
212 | + int type, protocol; | |
213 | + struct sock *peer_sk; | |
214 | + void *addr; | |
215 | + int addrlen; | |
216 | + } net; | |
a6877ea3 JR |
217 | struct { |
218 | int rlim; | |
219 | unsigned long max; | |
daaa955e AM |
220 | diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h |
221 | new file mode 100644 | |
222 | index 000000000000..140c8efcf364 | |
223 | --- /dev/null | |
224 | +++ b/security/apparmor/include/net.h | |
225 | @@ -0,0 +1,114 @@ | |
226 | +/* | |
227 | + * AppArmor security module | |
228 | + * | |
229 | + * This file contains AppArmor network mediation definitions. | |
230 | + * | |
231 | + * Copyright (C) 1998-2008 Novell/SUSE | |
232 | + * Copyright 2009-2017 Canonical Ltd. | |
233 | + * | |
234 | + * This program is free software; you can redistribute it and/or | |
235 | + * modify it under the terms of the GNU General Public License as | |
236 | + * published by the Free Software Foundation, version 2 of the | |
237 | + * License. | |
238 | + */ | |
239 | + | |
240 | +#ifndef __AA_NET_H | |
241 | +#define __AA_NET_H | |
242 | + | |
243 | +#include <net/sock.h> | |
244 | +#include <linux/path.h> | |
245 | + | |
246 | +#include "apparmorfs.h" | |
247 | +#include "label.h" | |
248 | +#include "perms.h" | |
249 | +#include "policy.h" | |
250 | + | |
251 | +#define AA_MAY_SEND AA_MAY_WRITE | |
252 | +#define AA_MAY_RECEIVE AA_MAY_READ | |
253 | + | |
254 | +#define AA_MAY_SHUTDOWN AA_MAY_DELETE | |
255 | + | |
256 | +#define AA_MAY_CONNECT AA_MAY_OPEN | |
257 | +#define AA_MAY_ACCEPT 0x00100000 | |
258 | + | |
259 | +#define AA_MAY_BIND 0x00200000 | |
260 | +#define AA_MAY_LISTEN 0x00400000 | |
261 | + | |
262 | +#define AA_MAY_SETOPT 0x01000000 | |
263 | +#define AA_MAY_GETOPT 0x02000000 | |
264 | + | |
265 | +#define NET_PERMS_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ | |
266 | + AA_MAY_SHUTDOWN | AA_MAY_BIND | AA_MAY_LISTEN | \ | |
267 | + AA_MAY_CONNECT | AA_MAY_ACCEPT | AA_MAY_SETATTR | \ | |
268 | + AA_MAY_GETATTR | AA_MAY_SETOPT | AA_MAY_GETOPT) | |
269 | + | |
270 | +#define NET_FS_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ | |
271 | + AA_MAY_SHUTDOWN | AA_MAY_CONNECT | AA_MAY_RENAME |\ | |
272 | + AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_CHMOD | \ | |
273 | + AA_MAY_CHOWN | AA_MAY_CHGRP | AA_MAY_LOCK | \ | |
274 | + AA_MAY_MPROT) | |
275 | + | |
276 | +#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \ | |
277 | + AA_MAY_ACCEPT) | |
278 | +struct aa_sk_ctx { | |
279 | + struct aa_label *label; | |
280 | + struct aa_label *peer; | |
281 | + struct path path; | |
282 | +}; | |
283 | + | |
284 | +#define SK_CTX(X) ((X)->sk_security) | |
285 | +#define SOCK_ctx(X) SOCK_INODE(X)->i_security | |
286 | +#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \ | |
287 | + struct lsm_network_audit NAME ## _net = { .sk = (SK), \ | |
288 | + .family = (F)}; \ | |
289 | + DEFINE_AUDIT_DATA(NAME, \ | |
290 | + ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \ | |
291 | + LSM_AUDIT_DATA_NONE, \ | |
292 | + OP); \ | |
293 | + NAME.u.net = &(NAME ## _net); \ | |
294 | + aad(&NAME)->net.type = (T); \ | |
295 | + aad(&NAME)->net.protocol = (P) | |
296 | + | |
297 | +#define DEFINE_AUDIT_SK(NAME, OP, SK) \ | |
298 | + DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ | |
299 | + (SK)->sk_protocol) | |
300 | + | |
301 | +/* struct aa_net - network confinement data | |
302 | + * @allow: basic network families permissions | |
303 | + * @audit: which network permissions to force audit | |
304 | + * @quiet: which network permissions to quiet rejects | |
305 | + */ | |
306 | +struct aa_net { | |
307 | + u16 allow[AF_MAX]; | |
308 | + u16 audit[AF_MAX]; | |
309 | + u16 quiet[AF_MAX]; | |
310 | +}; | |
311 | + | |
312 | + | |
313 | +extern struct aa_sfs_entry aa_sfs_entry_network[]; | |
314 | + | |
315 | +void audit_net_cb(struct audit_buffer *ab, void *va); | |
316 | +int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, | |
317 | + u32 request, u16 family, int type); | |
318 | +int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, | |
319 | + int type, int protocol); | |
320 | +static inline int aa_profile_af_sk_perm(struct aa_profile *profile, | |
321 | + struct common_audit_data *sa, | |
322 | + u32 request, | |
323 | + struct sock *sk) | |
324 | +{ | |
325 | + return aa_profile_af_perm(profile, sa, request, sk->sk_family, | |
326 | + sk->sk_type); | |
327 | +} | |
328 | +int aa_sk_perm(const char *op, u32 request, struct sock *sk); | |
329 | + | |
330 | +int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, | |
331 | + struct socket *sock); | |
332 | + | |
333 | + | |
334 | +static inline void aa_free_net_rules(struct aa_net *new) | |
335 | +{ | |
336 | + /* NOP */ | |
337 | +} | |
338 | + | |
339 | +#endif /* __AA_NET_H */ | |
340 | diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h | |
341 | index 2b27bb79aec4..af04d5a7d73d 100644 | |
342 | --- a/security/apparmor/include/perms.h | |
343 | +++ b/security/apparmor/include/perms.h | |
344 | @@ -135,9 +135,10 @@ extern struct aa_perms allperms; | |
345 | ||
346 | ||
347 | void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask); | |
348 | -void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask); | |
349 | +void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, | |
350 | + u32 mask); | |
351 | void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, | |
352 | - u32 chrsmask, const char **names, u32 namesmask); | |
353 | + u32 chrsmask, const char * const *names, u32 namesmask); | |
354 | void aa_apply_modes_to_perms(struct aa_profile *profile, | |
355 | struct aa_perms *perms); | |
356 | void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, | |
357 | diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h | |
358 | index 17fe41a9cac3..4364088a0b9e 100644 | |
359 | --- a/security/apparmor/include/policy.h | |
360 | +++ b/security/apparmor/include/policy.h | |
361 | @@ -30,6 +30,7 @@ | |
362 | #include "file.h" | |
363 | #include "lib.h" | |
364 | #include "label.h" | |
365 | +#include "net.h" | |
366 | #include "perms.h" | |
367 | #include "resource.h" | |
368 | ||
369 | @@ -111,6 +112,7 @@ struct aa_data { | |
370 | * @policy: general match rules governing policy | |
371 | * @file: The set of rules governing basic file access and domain transitions | |
372 | * @caps: capabilities for the profile | |
373 | + * @net: network controls for the profile | |
374 | * @rlimits: rlimits for the profile | |
375 | * | |
376 | * @dents: dentries for the profiles file entries in apparmorfs | |
377 | @@ -148,6 +150,7 @@ struct aa_profile { | |
378 | struct aa_policydb policy; | |
379 | struct aa_file_rules file; | |
380 | struct aa_caps caps; | |
381 | + struct aa_net net; | |
382 | struct aa_rlimit rlimits; | |
383 | ||
384 | struct aa_loaddata *rawdata; | |
385 | @@ -220,6 +223,16 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile, | |
386 | return 0; | |
387 | } | |
388 | ||
389 | +static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, | |
390 | + u16 AF) { | |
391 | + unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); | |
392 | + u16 be_af = cpu_to_be16(AF); | |
393 | + | |
394 | + if (!state) | |
395 | + return 0; | |
396 | + return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); | |
397 | +} | |
398 | + | |
399 | /** | |
400 | * aa_get_profile - increment refcount on profile @p | |
401 | * @p: profile (MAYBE NULL) | |
402 | diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c | |
403 | index 08ca26bcca77..8818621b5d95 100644 | |
404 | --- a/security/apparmor/lib.c | |
405 | +++ b/security/apparmor/lib.c | |
406 | @@ -211,7 +211,8 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask) | |
407 | *str = '\0'; | |
408 | } | |
409 | ||
410 | -void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) | |
411 | +void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, | |
412 | + u32 mask) | |
413 | { | |
414 | const char *fmt = "%s"; | |
415 | unsigned int i, perm = 1; | |
416 | @@ -229,7 +230,7 @@ void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) | |
417 | } | |
418 | ||
419 | void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, | |
420 | - u32 chrsmask, const char **names, u32 namesmask) | |
421 | + u32 chrsmask, const char * const *names, u32 namesmask) | |
422 | { | |
423 | char str[33]; | |
424 | ||
425 | diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c | |
426 | index 4ad0b3a45142..cc5ab23a2d84 100644 | |
427 | --- a/security/apparmor/lsm.c | |
428 | +++ b/security/apparmor/lsm.c | |
429 | @@ -33,6 +33,7 @@ | |
430 | #include "include/context.h" | |
431 | #include "include/file.h" | |
432 | #include "include/ipc.h" | |
433 | +#include "include/net.h" | |
434 | #include "include/path.h" | |
435 | #include "include/label.h" | |
436 | #include "include/policy.h" | |
437 | @@ -736,6 +737,368 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info, | |
438 | return error; | |
439 | } | |
440 | ||
441 | +/** | |
442 | + * apparmor_sk_alloc_security - allocate and attach the sk_security field | |
443 | + */ | |
444 | +static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags) | |
445 | +{ | |
446 | + struct aa_sk_ctx *ctx; | |
447 | + | |
448 | + ctx = kzalloc(sizeof(*ctx), flags); | |
449 | + if (!ctx) | |
450 | + return -ENOMEM; | |
451 | + | |
452 | + SK_CTX(sk) = ctx; | |
453 | + | |
454 | + return 0; | |
455 | +} | |
456 | + | |
457 | +/** | |
458 | + * apparmor_sk_free_security - free the sk_security field | |
459 | + */ | |
460 | +static void apparmor_sk_free_security(struct sock *sk) | |
461 | +{ | |
462 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
463 | + | |
464 | + SK_CTX(sk) = NULL; | |
465 | + aa_put_label(ctx->label); | |
466 | + aa_put_label(ctx->peer); | |
467 | + path_put(&ctx->path); | |
468 | + kfree(ctx); | |
469 | +} | |
470 | + | |
471 | +/** | |
472 | + * apparmor_clone_security - clone the sk_security field | |
473 | + */ | |
474 | +static void apparmor_sk_clone_security(const struct sock *sk, | |
475 | + struct sock *newsk) | |
476 | +{ | |
477 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
478 | + struct aa_sk_ctx *new = SK_CTX(newsk); | |
479 | + | |
480 | + new->label = aa_get_label(ctx->label); | |
481 | + new->peer = aa_get_label(ctx->peer); | |
482 | + new->path = ctx->path; | |
483 | + path_get(&new->path); | |
484 | +} | |
485 | + | |
486 | +static int aa_sock_create_perm(struct aa_label *label, int family, int type, | |
487 | + int protocol) | |
488 | +{ | |
489 | + AA_BUG(!label); | |
490 | + AA_BUG(in_interrupt()); | |
491 | + | |
492 | + return aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, family, type, | |
493 | + protocol); | |
494 | +} | |
495 | + | |
496 | + | |
497 | +/** | |
498 | + * apparmor_socket_create - check perms before creating a new socket | |
499 | + */ | |
500 | +static int apparmor_socket_create(int family, int type, int protocol, int kern) | |
501 | +{ | |
502 | + struct aa_label *label; | |
503 | + int error = 0; | |
504 | + | |
505 | + label = begin_current_label_crit_section(); | |
506 | + if (!(kern || unconfined(label))) | |
507 | + error = aa_sock_create_perm(label, family, type, protocol); | |
508 | + end_current_label_crit_section(label); | |
509 | + | |
510 | + return error; | |
511 | +} | |
512 | + | |
513 | +/** | |
514 | + * apparmor_socket_post_create - setup the per-socket security struct | |
515 | + * | |
516 | + * Note: | |
517 | + * - kernel sockets currently labeled unconfined but we may want to | |
518 | + * move to a special kernel label | |
519 | + * - socket may not have sk here if created with sock_create_lite or | |
520 | + * sock_alloc. These should be accept cases which will be handled in | |
521 | + * sock_graft. | |
522 | + */ | |
523 | +static int apparmor_socket_post_create(struct socket *sock, int family, | |
524 | + int type, int protocol, int kern) | |
525 | +{ | |
526 | + struct aa_label *label; | |
527 | + | |
528 | + if (kern) { | |
529 | + struct aa_ns *ns = aa_get_current_ns(); | |
530 | + | |
531 | + label = aa_get_label(ns_unconfined(ns)); | |
532 | + aa_put_ns(ns); | |
533 | + } else | |
534 | + label = aa_get_current_label(); | |
535 | + | |
536 | + if (sock->sk) { | |
537 | + struct aa_sk_ctx *ctx = SK_CTX(sock->sk); | |
538 | + | |
539 | + aa_put_label(ctx->label); | |
540 | + ctx->label = aa_get_label(label); | |
541 | + } | |
542 | + aa_put_label(label); | |
543 | + | |
544 | + return 0; | |
545 | +} | |
546 | + | |
547 | +/** | |
548 | + * apparmor_socket_bind - check perms before bind addr to socket | |
549 | + */ | |
550 | +static int apparmor_socket_bind(struct socket *sock, | |
551 | + struct sockaddr *address, int addrlen) | |
552 | +{ | |
553 | + AA_BUG(!sock); | |
554 | + AA_BUG(!sock->sk); | |
555 | + AA_BUG(!address); | |
556 | + AA_BUG(in_interrupt()); | |
557 | + | |
558 | + return aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk); | |
559 | +} | |
560 | + | |
561 | +/** | |
562 | + * apparmor_socket_connect - check perms before connecting @sock to @address | |
563 | + */ | |
564 | +static int apparmor_socket_connect(struct socket *sock, | |
565 | + struct sockaddr *address, int addrlen) | |
566 | +{ | |
567 | + AA_BUG(!sock); | |
568 | + AA_BUG(!sock->sk); | |
569 | + AA_BUG(!address); | |
570 | + AA_BUG(in_interrupt()); | |
571 | + | |
572 | + return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk); | |
573 | +} | |
574 | + | |
575 | +/** | |
576 | + * apparmor_socket_list - check perms before allowing listen | |
577 | + */ | |
578 | +static int apparmor_socket_listen(struct socket *sock, int backlog) | |
579 | +{ | |
580 | + AA_BUG(!sock); | |
581 | + AA_BUG(!sock->sk); | |
582 | + AA_BUG(in_interrupt()); | |
583 | + | |
584 | + return aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk); | |
585 | +} | |
586 | + | |
587 | +/** | |
588 | + * apparmor_socket_accept - check perms before accepting a new connection. | |
589 | + * | |
590 | + * Note: while @newsock is created and has some information, the accept | |
591 | + * has not been done. | |
592 | + */ | |
593 | +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) | |
594 | +{ | |
595 | + AA_BUG(!sock); | |
596 | + AA_BUG(!sock->sk); | |
597 | + AA_BUG(!newsock); | |
598 | + AA_BUG(in_interrupt()); | |
599 | + | |
600 | + return aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk); | |
601 | +} | |
602 | + | |
603 | +static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock, | |
604 | + struct msghdr *msg, int size) | |
605 | +{ | |
606 | + AA_BUG(!sock); | |
607 | + AA_BUG(!sock->sk); | |
608 | + AA_BUG(!msg); | |
609 | + AA_BUG(in_interrupt()); | |
610 | + | |
611 | + return aa_sk_perm(op, request, sock->sk); | |
612 | +} | |
613 | + | |
614 | +/** | |
615 | + * apparmor_socket_sendmsg - check perms before sending msg to another socket | |
616 | + */ | |
617 | +static int apparmor_socket_sendmsg(struct socket *sock, | |
618 | + struct msghdr *msg, int size) | |
619 | +{ | |
620 | + return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size); | |
621 | +} | |
622 | + | |
623 | +/** | |
624 | + * apparmor_socket_recvmsg - check perms before receiving a message | |
625 | + */ | |
626 | +static int apparmor_socket_recvmsg(struct socket *sock, | |
627 | + struct msghdr *msg, int size, int flags) | |
628 | +{ | |
629 | + return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size); | |
630 | +} | |
631 | + | |
632 | +/* revaliation, get/set attr, shutdown */ | |
633 | +static int aa_sock_perm(const char *op, u32 request, struct socket *sock) | |
634 | +{ | |
635 | + AA_BUG(!sock); | |
636 | + AA_BUG(!sock->sk); | |
637 | + AA_BUG(in_interrupt()); | |
638 | + | |
639 | + return aa_sk_perm(op, request, sock->sk); | |
640 | +} | |
641 | + | |
642 | +/** | |
643 | + * apparmor_socket_getsockname - check perms before getting the local address | |
644 | + */ | |
645 | +static int apparmor_socket_getsockname(struct socket *sock) | |
646 | +{ | |
647 | + return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock); | |
648 | +} | |
649 | + | |
650 | +/** | |
651 | + * apparmor_socket_getpeername - check perms before getting remote address | |
652 | + */ | |
653 | +static int apparmor_socket_getpeername(struct socket *sock) | |
654 | +{ | |
655 | + return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock); | |
656 | +} | |
657 | + | |
658 | +/* revaliation, get/set attr, opt */ | |
659 | +static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, | |
660 | + int level, int optname) | |
661 | +{ | |
662 | + AA_BUG(!sock); | |
663 | + AA_BUG(!sock->sk); | |
664 | + AA_BUG(in_interrupt()); | |
665 | + | |
666 | + return aa_sk_perm(op, request, sock->sk); | |
667 | +} | |
668 | + | |
669 | +/** | |
670 | + * apparmor_getsockopt - check perms before getting socket options | |
671 | + */ | |
672 | +static int apparmor_socket_getsockopt(struct socket *sock, int level, | |
673 | + int optname) | |
674 | +{ | |
675 | + return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock, | |
676 | + level, optname); | |
677 | +} | |
678 | + | |
679 | +/** | |
680 | + * apparmor_setsockopt - check perms before setting socket options | |
681 | + */ | |
682 | +static int apparmor_socket_setsockopt(struct socket *sock, int level, | |
683 | + int optname) | |
684 | +{ | |
685 | + return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock, | |
686 | + level, optname); | |
687 | +} | |
688 | + | |
689 | +/** | |
690 | + * apparmor_socket_shutdown - check perms before shutting down @sock conn | |
691 | + */ | |
692 | +static int apparmor_socket_shutdown(struct socket *sock, int how) | |
693 | +{ | |
694 | + return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock); | |
695 | +} | |
696 | + | |
697 | +/** | |
698 | + * apparmor_socket_sock_recv_skb - check perms before associating skb to sk | |
699 | + * | |
700 | + * Note: can not sleep may be called with locks held | |
701 | + * | |
702 | + * dont want protocol specific in __skb_recv_datagram() | |
703 | + * to deny an incoming connection socket_sock_rcv_skb() | |
704 | + */ | |
705 | +static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |
706 | +{ | |
707 | + return 0; | |
708 | +} | |
709 | + | |
710 | + | |
711 | +static struct aa_label *sk_peer_label(struct sock *sk) | |
712 | +{ | |
713 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
714 | + | |
715 | + if (ctx->peer) | |
716 | + return ctx->peer; | |
717 | + | |
718 | + return ERR_PTR(-ENOPROTOOPT); | |
719 | +} | |
720 | + | |
721 | +/** | |
722 | + * apparmor_socket_getpeersec_stream - get security context of peer | |
723 | + * | |
724 | + * Note: for tcp only valid if using ipsec or cipso on lan | |
725 | + */ | |
726 | +static int apparmor_socket_getpeersec_stream(struct socket *sock, | |
727 | + char __user *optval, | |
728 | + int __user *optlen, | |
729 | + unsigned int len) | |
730 | +{ | |
731 | + char *name; | |
732 | + int slen, error = 0; | |
733 | + struct aa_label *label; | |
734 | + struct aa_label *peer; | |
735 | + | |
736 | + label = begin_current_label_crit_section(); | |
737 | + peer = sk_peer_label(sock->sk); | |
738 | + if (IS_ERR(peer)) { | |
739 | + error = PTR_ERR(peer); | |
740 | + goto done; | |
741 | + } | |
742 | + slen = aa_label_asxprint(&name, labels_ns(label), peer, | |
743 | + FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | | |
744 | + FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); | |
745 | + /* don't include terminating \0 in slen, it breaks some apps */ | |
746 | + if (slen < 0) { | |
747 | + error = -ENOMEM; | |
748 | + } else { | |
749 | + if (slen > len) { | |
750 | + error = -ERANGE; | |
751 | + } else if (copy_to_user(optval, name, slen)) { | |
752 | + error = -EFAULT; | |
753 | + goto out; | |
754 | + } | |
755 | + if (put_user(slen, optlen)) | |
756 | + error = -EFAULT; | |
757 | +out: | |
758 | + kfree(name); | |
759 | + | |
760 | + } | |
761 | + | |
762 | +done: | |
763 | + end_current_label_crit_section(label); | |
764 | + | |
765 | + return error; | |
766 | +} | |
767 | + | |
768 | +/** | |
769 | + * apparmor_socket_getpeersec_dgram - get security label of packet | |
770 | + * @sock: the peer socket | |
771 | + * @skb: packet data | |
772 | + * @secid: pointer to where to put the secid of the packet | |
773 | + * | |
774 | + * Sets the netlabel socket state on sk from parent | |
775 | + */ | |
776 | +static int apparmor_socket_getpeersec_dgram(struct socket *sock, | |
777 | + struct sk_buff *skb, u32 *secid) | |
778 | + | |
779 | +{ | |
780 | + /* TODO: requires secid support */ | |
781 | + return -ENOPROTOOPT; | |
782 | +} | |
783 | + | |
784 | +/** | |
785 | + * apparmor_sock_graft - Initialize newly created socket | |
786 | + * @sk: child sock | |
787 | + * @parent: parent socket | |
788 | + * | |
789 | + * Note: could set off of SOCK_CTX(parent) but need to track inode and we can | |
790 | + * just set sk security information off of current creating process label | |
791 | + * Labeling of sk for accept case - probably should be sock based | |
792 | + * instead of task, because of the case where an implicitly labeled | |
793 | + * socket is shared by different tasks. | |
794 | + */ | |
795 | +static void apparmor_sock_graft(struct sock *sk, struct socket *parent) | |
796 | +{ | |
797 | + struct aa_sk_ctx *ctx = SK_CTX(sk); | |
798 | + | |
799 | + if (!ctx->label) | |
800 | + ctx->label = aa_get_current_label(); | |
801 | +} | |
802 | + | |
803 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |
804 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), | |
805 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), | |
806 | @@ -770,6 +1133,30 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |
807 | LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), | |
808 | LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), | |
809 | ||
810 | + LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security), | |
811 | + LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), | |
812 | + LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), | |
813 | + | |
814 | + LSM_HOOK_INIT(socket_create, apparmor_socket_create), | |
815 | + LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create), | |
816 | + LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), | |
817 | + LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), | |
818 | + LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), | |
819 | + LSM_HOOK_INIT(socket_accept, apparmor_socket_accept), | |
820 | + LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg), | |
821 | + LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg), | |
822 | + LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname), | |
823 | + LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername), | |
824 | + LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), | |
825 | + LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), | |
826 | + LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), | |
827 | + LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb), | |
828 | + LSM_HOOK_INIT(socket_getpeersec_stream, | |
829 | + apparmor_socket_getpeersec_stream), | |
830 | + LSM_HOOK_INIT(socket_getpeersec_dgram, | |
831 | + apparmor_socket_getpeersec_dgram), | |
832 | + LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), | |
833 | + | |
834 | LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), | |
835 | LSM_HOOK_INIT(cred_free, apparmor_cred_free), | |
836 | LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), | |
837 | diff --git a/security/apparmor/net.c b/security/apparmor/net.c | |
838 | new file mode 100644 | |
839 | index 000000000000..33d54435f8d6 | |
840 | --- /dev/null | |
841 | +++ b/security/apparmor/net.c | |
842 | @@ -0,0 +1,184 @@ | |
843 | +/* | |
844 | + * AppArmor security module | |
845 | + * | |
846 | + * This file contains AppArmor network mediation | |
847 | + * | |
848 | + * Copyright (C) 1998-2008 Novell/SUSE | |
849 | + * Copyright 2009-2017 Canonical Ltd. | |
850 | + * | |
851 | + * This program is free software; you can redistribute it and/or | |
852 | + * modify it under the terms of the GNU General Public License as | |
853 | + * published by the Free Software Foundation, version 2 of the | |
854 | + * License. | |
855 | + */ | |
856 | + | |
857 | +#include "include/apparmor.h" | |
858 | +#include "include/audit.h" | |
859 | +#include "include/context.h" | |
860 | +#include "include/label.h" | |
861 | +#include "include/net.h" | |
862 | +#include "include/policy.h" | |
863 | + | |
864 | +#include "net_names.h" | |
865 | + | |
866 | + | |
867 | +struct aa_sfs_entry aa_sfs_entry_network[] = { | |
868 | + AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), | |
869 | + { } | |
870 | +}; | |
871 | + | |
872 | +static const char * const net_mask_names[] = { | |
873 | + "unknown", | |
874 | + "send", | |
875 | + "receive", | |
876 | + "unknown", | |
877 | + | |
878 | + "create", | |
879 | + "shutdown", | |
880 | + "connect", | |
881 | + "unknown", | |
882 | + | |
883 | + "setattr", | |
884 | + "getattr", | |
885 | + "setcred", | |
886 | + "getcred", | |
887 | + | |
888 | + "chmod", | |
889 | + "chown", | |
890 | + "chgrp", | |
891 | + "lock", | |
892 | + | |
893 | + "mmap", | |
894 | + "mprot", | |
895 | + "unknown", | |
896 | + "unknown", | |
897 | + | |
898 | + "accept", | |
899 | + "bind", | |
900 | + "listen", | |
901 | + "unknown", | |
902 | + | |
903 | + "setopt", | |
904 | + "getopt", | |
905 | + "unknown", | |
906 | + "unknown", | |
907 | + | |
908 | + "unknown", | |
909 | + "unknown", | |
910 | + "unknown", | |
911 | + "unknown", | |
912 | +}; | |
913 | + | |
914 | + | |
915 | +/* audit callback for net specific fields */ | |
916 | +void audit_net_cb(struct audit_buffer *ab, void *va) | |
917 | +{ | |
918 | + struct common_audit_data *sa = va; | |
919 | + | |
920 | + audit_log_format(ab, " family="); | |
921 | + if (address_family_names[sa->u.net->family]) | |
922 | + audit_log_string(ab, address_family_names[sa->u.net->family]); | |
923 | + else | |
924 | + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family); | |
925 | + audit_log_format(ab, " sock_type="); | |
926 | + if (sock_type_names[aad(sa)->net.type]) | |
927 | + audit_log_string(ab, sock_type_names[aad(sa)->net.type]); | |
928 | + else | |
929 | + audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type); | |
930 | + audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); | |
931 | + | |
932 | + if (aad(sa)->request & NET_PERMS_MASK) { | |
933 | + audit_log_format(ab, " requested_mask="); | |
934 | + aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0, | |
935 | + net_mask_names, NET_PERMS_MASK); | |
936 | + | |
937 | + if (aad(sa)->denied & NET_PERMS_MASK) { | |
938 | + audit_log_format(ab, " denied_mask="); | |
939 | + aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0, | |
940 | + net_mask_names, NET_PERMS_MASK); | |
941 | + } | |
942 | + } | |
943 | + if (aad(sa)->peer) { | |
944 | + audit_log_format(ab, " peer="); | |
945 | + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, | |
946 | + FLAGS_NONE, GFP_ATOMIC); | |
947 | + } | |
948 | +} | |
949 | + | |
950 | + | |
951 | +/* Generic af perm */ | |
952 | +int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, | |
953 | + u32 request, u16 family, int type) | |
954 | +{ | |
955 | + struct aa_perms perms = { }; | |
956 | + | |
957 | + AA_BUG(family >= AF_MAX); | |
958 | + AA_BUG(type < 0 || type >= SOCK_MAX); | |
959 | + | |
960 | + if (profile_unconfined(profile)) | |
961 | + return 0; | |
962 | + | |
963 | + perms.allow = (profile->net.allow[family] & (1 << type)) ? | |
964 | + ALL_PERMS_MASK : 0; | |
965 | + perms.audit = (profile->net.audit[family] & (1 << type)) ? | |
966 | + ALL_PERMS_MASK : 0; | |
967 | + perms.quiet = (profile->net.quiet[family] & (1 << type)) ? | |
968 | + ALL_PERMS_MASK : 0; | |
969 | + aa_apply_modes_to_perms(profile, &perms); | |
970 | + | |
971 | + return aa_check_perms(profile, &perms, request, sa, audit_net_cb); | |
972 | +} | |
973 | + | |
974 | +int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, | |
975 | + int type, int protocol) | |
976 | +{ | |
977 | + struct aa_profile *profile; | |
978 | + DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); | |
979 | + | |
980 | + return fn_for_each_confined(label, profile, | |
981 | + aa_profile_af_perm(profile, &sa, request, family, | |
982 | + type)); | |
983 | +} | |
984 | + | |
985 | +static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, | |
986 | + struct sock *sk) | |
987 | +{ | |
988 | + struct aa_profile *profile; | |
989 | + DEFINE_AUDIT_SK(sa, op, sk); | |
990 | + | |
991 | + AA_BUG(!label); | |
992 | + AA_BUG(!sk); | |
993 | + | |
994 | + if (unconfined(label)) | |
995 | + return 0; | |
996 | + | |
997 | + return fn_for_each_confined(label, profile, | |
998 | + aa_profile_af_sk_perm(profile, &sa, request, sk)); | |
999 | +} | |
1000 | + | |
1001 | +int aa_sk_perm(const char *op, u32 request, struct sock *sk) | |
1002 | +{ | |
1003 | + struct aa_label *label; | |
1004 | + int error; | |
1005 | + | |
1006 | + AA_BUG(!sk); | |
1007 | + AA_BUG(in_interrupt()); | |
1008 | + | |
1009 | + /* TODO: switch to begin_current_label ???? */ | |
1010 | + label = begin_current_label_crit_section(); | |
1011 | + error = aa_label_sk_perm(label, op, request, sk); | |
1012 | + end_current_label_crit_section(label); | |
1013 | + | |
1014 | + return error; | |
1015 | +} | |
1016 | + | |
1017 | + | |
1018 | +int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, | |
1019 | + struct socket *sock) | |
1020 | +{ | |
1021 | + AA_BUG(!label); | |
1022 | + AA_BUG(!sock); | |
1023 | + AA_BUG(!sock->sk); | |
1024 | + | |
1025 | + return aa_label_sk_perm(label, op, request, sock->sk); | |
1026 | +} | |
1027 | diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c | |
1028 | index 4ede87c30f8b..5a2aec358322 100644 | |
1029 | --- a/security/apparmor/policy_unpack.c | |
1030 | +++ b/security/apparmor/policy_unpack.c | |
1031 | @@ -275,6 +275,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name) | |
1032 | return 0; | |
1033 | } | |
1034 | ||
1035 | +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) | |
1036 | +{ | |
1037 | + if (unpack_nameX(e, AA_U16, name)) { | |
1038 | + if (!inbounds(e, sizeof(u16))) | |
1039 | + return 0; | |
1040 | + if (data) | |
1041 | + *data = le16_to_cpu(get_unaligned((__le16 *) e->pos)); | |
1042 | + e->pos += sizeof(u16); | |
1043 | + return 1; | |
1044 | + } | |
1045 | + return 0; | |
1046 | +} | |
1047 | + | |
1048 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) | |
1049 | { | |
1050 | if (unpack_nameX(e, AA_U32, name)) { | |
1051 | @@ -584,7 +597,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |
1052 | struct aa_profile *profile = NULL; | |
1053 | const char *tmpname, *tmpns = NULL, *name = NULL; | |
1054 | const char *info = "failed to unpack profile"; | |
1055 | - size_t ns_len; | |
1056 | + size_t size = 0, ns_len; | |
1057 | struct rhashtable_params params = { 0 }; | |
1058 | char *key = NULL; | |
1059 | struct aa_data *data; | |
1060 | @@ -717,6 +730,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |
1061 | goto fail; | |
1062 | } | |
1063 | ||
1064 | + size = unpack_array(e, "net_allowed_af"); | |
1065 | + if (size) { | |
1066 | + | |
1067 | + for (i = 0; i < size; i++) { | |
1068 | + /* discard extraneous rules that this kernel will | |
1069 | + * never request | |
1070 | + */ | |
1071 | + if (i >= AF_MAX) { | |
1072 | + u16 tmp; | |
1073 | + | |
1074 | + if (!unpack_u16(e, &tmp, NULL) || | |
1075 | + !unpack_u16(e, &tmp, NULL) || | |
1076 | + !unpack_u16(e, &tmp, NULL)) | |
1077 | + goto fail; | |
1078 | + continue; | |
1079 | + } | |
1080 | + if (!unpack_u16(e, &profile->net.allow[i], NULL)) | |
1081 | + goto fail; | |
1082 | + if (!unpack_u16(e, &profile->net.audit[i], NULL)) | |
1083 | + goto fail; | |
1084 | + if (!unpack_u16(e, &profile->net.quiet[i], NULL)) | |
1085 | + goto fail; | |
1086 | + } | |
1087 | + if (!unpack_nameX(e, AA_ARRAYEND, NULL)) | |
1088 | + goto fail; | |
1089 | + } | |
1090 | + if (VERSION_LT(e->version, v7)) { | |
1091 | + /* pre v7 policy always allowed these */ | |
1092 | + profile->net.allow[AF_UNIX] = 0xffff; | |
1093 | + profile->net.allow[AF_NETLINK] = 0xffff; | |
1094 | + } | |
1095 | + | |
1096 | if (unpack_nameX(e, AA_STRUCT, "policydb")) { | |
1097 | /* generic policy dfa - optional and may be NULL */ | |
1098 | info = "failed to unpack policydb"; | |
1099 | -- | |
1100 | 2.11.0 | |
1101 |