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