]>
Commit | Line | Data |
---|---|---|
948a1326 | 1 | From 0ae314bc92d8b22250f04f85e4bd36ee9ed30890 Mon Sep 17 00:00:00 2001 |
76514441 | 2 | From: John Johansen <john.johansen@canonical.com> |
fc63ffa9 AM |
3 | Date: Mon, 4 Oct 2010 15:03:36 -0700 |
4 | Subject: [PATCH 1/3] AppArmor: compatibility patch for v5 network controll | |
76514441 | 5 | |
fc63ffa9 | 6 | Add compatibility for v5 network rules. |
76514441 AM |
7 | |
8 | Signed-off-by: John Johansen <john.johansen@canonical.com> | |
9 | --- | |
fc63ffa9 | 10 | include/linux/lsm_audit.h | 4 + |
948a1326 | 11 | security/apparmor/Makefile | 19 ++++- |
fc63ffa9 AM |
12 | security/apparmor/include/net.h | 40 +++++++++ |
13 | security/apparmor/include/policy.h | 3 + | |
14 | security/apparmor/lsm.c | 112 +++++++++++++++++++++++ | |
15 | security/apparmor/net.c | 170 ++++++++++++++++++++++++++++++++++++ | |
16 | security/apparmor/policy.c | 1 + | |
17 | security/apparmor/policy_unpack.c | 48 ++++++++++- | |
948a1326 | 18 | 8 files changed, 394 insertions(+), 3 deletions(-) |
76514441 | 19 | create mode 100644 security/apparmor/include/net.h |
76514441 | 20 | create mode 100644 security/apparmor/net.c |
76514441 | 21 | |
76514441 | 22 | diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h |
fc63ffa9 | 23 | index 112a550..d5f3dd7 100644 |
76514441 AM |
24 | --- a/include/linux/lsm_audit.h |
25 | +++ b/include/linux/lsm_audit.h | |
fc63ffa9 AM |
26 | @@ -123,6 +123,10 @@ struct common_audit_data { |
27 | u32 denied; | |
28 | uid_t ouid; | |
29 | } fs; | |
76514441 AM |
30 | + struct { |
31 | + int type, protocol; | |
32 | + struct sock *sk; | |
33 | + } net; | |
fc63ffa9 AM |
34 | }; |
35 | } apparmor_audit_data; | |
36 | #endif | |
37 | diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile | |
948a1326 | 38 | index 2dafe50..7cefef9 100644 |
fc63ffa9 AM |
39 | --- a/security/apparmor/Makefile |
40 | +++ b/security/apparmor/Makefile | |
948a1326 | 41 | @@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o |
ceaf2cfb | 42 | |
fc63ffa9 AM |
43 | apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ |
44 | path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ | |
45 | - resource.o sid.o file.o | |
46 | + resource.o sid.o file.o net.o | |
ceaf2cfb | 47 | |
948a1326 JR |
48 | -clean-files := capability_names.h rlim_names.h |
49 | +clean-files := capability_names.h rlim_names.h af_names.h | |
ceaf2cfb | 50 | |
ceaf2cfb | 51 | |
948a1326 JR |
52 | # Build a lower case string table of capability names |
53 | @@ -44,9 +44,24 @@ cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\ | |
54 | sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\ | |
55 | echo "};" >> $@ | |
56 | ||
57 | +# Build a lower case string table of address family names. | |
58 | +# Transform lines from | |
59 | +# #define AF_INET 2 /* Internet IP Protocol */ | |
60 | +# to | |
61 | +# [2] = "inet", | |
ceaf2cfb | 62 | +quiet_cmd_make-af = GEN $@ |
948a1326 JR |
63 | +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ |
64 | + sed $< >> $@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \ | |
65 | + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+).*/[\2] = "\L\1",/p';\ | |
66 | + echo "};" >> $@ | |
67 | + | |
ceaf2cfb | 68 | + |
fc63ffa9 | 69 | $(obj)/capability.o : $(obj)/capability_names.h |
fc63ffa9 | 70 | $(obj)/resource.o : $(obj)/rlim_names.h |
948a1326 | 71 | +$(obj)/net.o : $(obj)/af_names.h |
fc63ffa9 AM |
72 | $(obj)/capability_names.h : $(srctree)/include/linux/capability.h |
73 | $(call cmd,make-caps) | |
948a1326 JR |
74 | $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h |
75 | $(call cmd,make-rlim) | |
76 | +$(obj)/af_names.h : $(srctree)/include/linux/socket.h | |
77 | + $(call cmd,make-af) | |
78 | \ No newline at end of file | |
fc63ffa9 | 79 | diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h |
ceaf2cfb | 80 | new file mode 100644 |
fc63ffa9 | 81 | index 0000000..3c7d599 |
ceaf2cfb | 82 | --- /dev/null |
fc63ffa9 AM |
83 | +++ b/security/apparmor/include/net.h |
84 | @@ -0,0 +1,40 @@ | |
9474138d AM |
85 | +/* |
86 | + * AppArmor security module | |
87 | + * | |
fc63ffa9 | 88 | + * This file contains AppArmor network mediation definitions. |
9474138d AM |
89 | + * |
90 | + * Copyright (C) 1998-2008 Novell/SUSE | |
ceaf2cfb | 91 | + * Copyright 2009-2010 Canonical Ltd. |
9474138d AM |
92 | + * |
93 | + * This program is free software; you can redistribute it and/or | |
94 | + * modify it under the terms of the GNU General Public License as | |
95 | + * published by the Free Software Foundation, version 2 of the | |
96 | + * License. | |
97 | + */ | |
98 | + | |
fc63ffa9 AM |
99 | +#ifndef __AA_NET_H |
100 | +#define __AA_NET_H | |
2380c486 | 101 | + |
fc63ffa9 | 102 | +#include <net/sock.h> |
9474138d | 103 | + |
fc63ffa9 AM |
104 | +/* struct aa_net - network confinement data |
105 | + * @allowed: basic network families permissions | |
106 | + * @audit_network: which network permissions to force audit | |
107 | + * @quiet_network: which network permissions to quiet rejects | |
108 | + */ | |
109 | +struct aa_net { | |
110 | + u16 allow[AF_MAX]; | |
111 | + u16 audit[AF_MAX]; | |
112 | + u16 quiet[AF_MAX]; | |
113 | +}; | |
ceaf2cfb | 114 | + |
fc63ffa9 AM |
115 | +extern int aa_net_perm(int op, struct aa_profile *profile, u16 family, |
116 | + int type, int protocol, struct sock *sk); | |
117 | +extern int aa_revalidate_sk(int op, struct sock *sk); | |
ceaf2cfb | 118 | + |
fc63ffa9 AM |
119 | +static inline void aa_free_net_rules(struct aa_net *new) |
120 | +{ | |
121 | + /* NOP */ | |
ceaf2cfb AM |
122 | +} |
123 | + | |
fc63ffa9 AM |
124 | +#endif /* __AA_NET_H */ |
125 | diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h | |
126 | index aeda5cf..6776929 100644 | |
127 | --- a/security/apparmor/include/policy.h | |
128 | +++ b/security/apparmor/include/policy.h | |
129 | @@ -27,6 +27,7 @@ | |
130 | #include "capability.h" | |
131 | #include "domain.h" | |
132 | #include "file.h" | |
133 | +#include "net.h" | |
134 | #include "resource.h" | |
135 | ||
136 | extern const char *profile_mode_names[]; | |
137 | @@ -145,6 +146,7 @@ struct aa_namespace { | |
138 | * @size: the memory consumed by this profiles rules | |
139 | * @file: The set of rules governing basic file access and domain transitions | |
140 | * @caps: capabilities for the profile | |
141 | + * @net: network controls for the profile | |
142 | * @rlimits: rlimits for the profile | |
143 | * | |
144 | * The AppArmor profile contains the basic confinement data. Each profile | |
145 | @@ -181,6 +183,7 @@ struct aa_profile { | |
146 | ||
147 | struct aa_file_rules file; | |
148 | struct aa_caps caps; | |
149 | + struct aa_net net; | |
150 | struct aa_rlimit rlimits; | |
151 | }; | |
152 | ||
153 | diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c | |
948a1326 | 154 | index ae3a698..05c018b 100644 |
fc63ffa9 AM |
155 | --- a/security/apparmor/lsm.c |
156 | +++ b/security/apparmor/lsm.c | |
948a1326 | 157 | @@ -32,6 +32,7 @@ |
fc63ffa9 AM |
158 | #include "include/context.h" |
159 | #include "include/file.h" | |
160 | #include "include/ipc.h" | |
161 | +#include "include/net.h" | |
162 | #include "include/path.h" | |
163 | #include "include/policy.h" | |
164 | #include "include/procattr.h" | |
5d26c04f | 165 | @@ -610,5 +611,103 @@ static int apparmor_task_setrlimit(struct task_struct *task, |
fc63ffa9 AM |
166 | return error; |
167 | } | |
168 | ||
169 | +static int apparmor_socket_create(int family, int type, int protocol, int kern) | |
ceaf2cfb | 170 | +{ |
fc63ffa9 AM |
171 | + struct aa_profile *profile; |
172 | + int error = 0; | |
ceaf2cfb | 173 | + |
fc63ffa9 AM |
174 | + if (kern) |
175 | + return 0; | |
ceaf2cfb | 176 | + |
fc63ffa9 AM |
177 | + profile = __aa_current_profile(); |
178 | + if (!unconfined(profile)) | |
179 | + error = aa_net_perm(OP_CREATE, profile, family, type, protocol, | |
180 | + NULL); | |
181 | + return error; | |
182 | +} | |
ceaf2cfb | 183 | + |
fc63ffa9 AM |
184 | +static int apparmor_socket_bind(struct socket *sock, |
185 | + struct sockaddr *address, int addrlen) | |
9474138d | 186 | +{ |
fc63ffa9 | 187 | + struct sock *sk = sock->sk; |
9474138d | 188 | + |
fc63ffa9 AM |
189 | + return aa_revalidate_sk(OP_BIND, sk); |
190 | +} | |
ceaf2cfb | 191 | + |
fc63ffa9 AM |
192 | +static int apparmor_socket_connect(struct socket *sock, |
193 | + struct sockaddr *address, int addrlen) | |
194 | +{ | |
195 | + struct sock *sk = sock->sk; | |
ceaf2cfb | 196 | + |
fc63ffa9 | 197 | + return aa_revalidate_sk(OP_CONNECT, sk); |
9474138d AM |
198 | +} |
199 | + | |
fc63ffa9 | 200 | +static int apparmor_socket_listen(struct socket *sock, int backlog) |
9474138d | 201 | +{ |
fc63ffa9 AM |
202 | + struct sock *sk = sock->sk; |
203 | + | |
204 | + return aa_revalidate_sk(OP_LISTEN, sk); | |
9474138d AM |
205 | +} |
206 | + | |
fc63ffa9 | 207 | +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) |
9474138d | 208 | +{ |
fc63ffa9 | 209 | + struct sock *sk = sock->sk; |
9474138d | 210 | + |
fc63ffa9 AM |
211 | + return aa_revalidate_sk(OP_ACCEPT, sk); |
212 | +} | |
9474138d | 213 | + |
fc63ffa9 AM |
214 | +static int apparmor_socket_sendmsg(struct socket *sock, |
215 | + struct msghdr *msg, int size) | |
76514441 | 216 | +{ |
fc63ffa9 | 217 | + struct sock *sk = sock->sk; |
76514441 | 218 | + |
fc63ffa9 | 219 | + return aa_revalidate_sk(OP_SENDMSG, sk); |
76514441 AM |
220 | +} |
221 | + | |
fc63ffa9 AM |
222 | +static int apparmor_socket_recvmsg(struct socket *sock, |
223 | + struct msghdr *msg, int size, int flags) | |
224 | +{ | |
225 | + struct sock *sk = sock->sk; | |
ceaf2cfb | 226 | + |
fc63ffa9 AM |
227 | + return aa_revalidate_sk(OP_RECVMSG, sk); |
228 | +} | |
ceaf2cfb | 229 | + |
fc63ffa9 AM |
230 | +static int apparmor_socket_getsockname(struct socket *sock) |
231 | +{ | |
232 | + struct sock *sk = sock->sk; | |
ceaf2cfb | 233 | + |
fc63ffa9 | 234 | + return aa_revalidate_sk(OP_GETSOCKNAME, sk); |
9474138d AM |
235 | +} |
236 | + | |
fc63ffa9 | 237 | +static int apparmor_socket_getpeername(struct socket *sock) |
9474138d | 238 | +{ |
fc63ffa9 | 239 | + struct sock *sk = sock->sk; |
9474138d | 240 | + |
fc63ffa9 AM |
241 | + return aa_revalidate_sk(OP_GETPEERNAME, sk); |
242 | +} | |
ceaf2cfb | 243 | + |
fc63ffa9 AM |
244 | +static int apparmor_socket_getsockopt(struct socket *sock, int level, |
245 | + int optname) | |
246 | +{ | |
247 | + struct sock *sk = sock->sk; | |
ceaf2cfb | 248 | + |
fc63ffa9 AM |
249 | + return aa_revalidate_sk(OP_GETSOCKOPT, sk); |
250 | +} | |
ceaf2cfb | 251 | + |
fc63ffa9 AM |
252 | +static int apparmor_socket_setsockopt(struct socket *sock, int level, |
253 | + int optname) | |
254 | +{ | |
255 | + struct sock *sk = sock->sk; | |
2380c486 | 256 | + |
fc63ffa9 AM |
257 | + return aa_revalidate_sk(OP_SETSOCKOPT, sk); |
258 | +} | |
ceaf2cfb | 259 | + |
fc63ffa9 AM |
260 | +static int apparmor_socket_shutdown(struct socket *sock, int how) |
261 | +{ | |
262 | + struct sock *sk = sock->sk; | |
ceaf2cfb | 263 | + |
fc63ffa9 | 264 | + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk); |
ceaf2cfb | 265 | +} |
948a1326 | 266 | + |
5d26c04f AM |
267 | static int apparmor_task_setrlimit(struct task_struct *task, |
268 | unsigned int resource, struct rlimit *new_rlim) | |
269 | @@ -651,6 +750,19 @@ static struct security_operations apparmor_ops = { | |
270 | .getprocattr = apparmor_getprocattr, | |
271 | .setprocattr = apparmor_setprocattr, | |
272 | ||
273 | + .socket_create = apparmor_socket_create, | |
274 | + .socket_bind = apparmor_socket_bind, | |
275 | + .socket_connect = apparmor_socket_connect, | |
276 | + .socket_listen = apparmor_socket_listen, | |
277 | + .socket_accept = apparmor_socket_accept, | |
278 | + .socket_sendmsg = apparmor_socket_sendmsg, | |
279 | + .socket_recvmsg = apparmor_socket_recvmsg, | |
280 | + .socket_getsockname = apparmor_socket_getsockname, | |
281 | + .socket_getpeername = apparmor_socket_getpeername, | |
282 | + .socket_getsockopt = apparmor_socket_getsockopt, | |
283 | + .socket_setsockopt = apparmor_socket_setsockopt, | |
284 | + .socket_shutdown = apparmor_socket_shutdown, | |
285 | + | |
286 | .cred_alloc_blank = apparmor_cred_alloc_blank, | |
287 | .cred_free = apparmor_cred_free, | |
288 | .cred_prepare = apparmor_cred_prepare, | |
fc63ffa9 | 289 | diff --git a/security/apparmor/net.c b/security/apparmor/net.c |
ceaf2cfb | 290 | new file mode 100644 |
fc63ffa9 | 291 | index 0000000..1765901 |
ceaf2cfb | 292 | --- /dev/null |
fc63ffa9 AM |
293 | +++ b/security/apparmor/net.c |
294 | @@ -0,0 +1,170 @@ | |
2380c486 | 295 | +/* |
9474138d AM |
296 | + * AppArmor security module |
297 | + * | |
fc63ffa9 | 298 | + * This file contains AppArmor network mediation |
2380c486 | 299 | + * |
9474138d | 300 | + * Copyright (C) 1998-2008 Novell/SUSE |
ceaf2cfb | 301 | + * Copyright 2009-2010 Canonical Ltd. |
2380c486 | 302 | + * |
9474138d AM |
303 | + * This program is free software; you can redistribute it and/or |
304 | + * modify it under the terms of the GNU General Public License as | |
305 | + * published by the Free Software Foundation, version 2 of the | |
306 | + * License. | |
2380c486 JR |
307 | + */ |
308 | + | |
9474138d AM |
309 | +#include "include/apparmor.h" |
310 | +#include "include/audit.h" | |
311 | +#include "include/context.h" | |
fc63ffa9 | 312 | +#include "include/net.h" |
9474138d | 313 | +#include "include/policy.h" |
2380c486 | 314 | + |
fc63ffa9 | 315 | +#include "af_names.h" |
2380c486 | 316 | + |
fc63ffa9 AM |
317 | +static const char *sock_type_names[] = { |
318 | + "unknown(0)", | |
319 | + "stream", | |
320 | + "dgram", | |
321 | + "raw", | |
322 | + "rdm", | |
323 | + "seqpacket", | |
324 | + "dccp", | |
325 | + "unknown(7)", | |
326 | + "unknown(8)", | |
327 | + "unknown(9)", | |
328 | + "packet", | |
9474138d AM |
329 | +}; |
330 | + | |
fc63ffa9 | 331 | +/* audit callback for net specific fields */ |
76514441 | 332 | +static void audit_cb(struct audit_buffer *ab, void *va) |
9474138d | 333 | +{ |
76514441 | 334 | + struct common_audit_data *sa = va; |
9474138d | 335 | + |
fc63ffa9 AM |
336 | + audit_log_format(ab, " family="); |
337 | + if (address_family_names[sa->u.net.family]) { | |
338 | + audit_log_string(ab, address_family_names[sa->u.net.family]); | |
339 | + } else { | |
340 | + audit_log_format(ab, " \"unknown(%d)\"", sa->u.net.family); | |
341 | + } | |
2380c486 | 342 | + |
fc63ffa9 AM |
343 | + audit_log_format(ab, " sock_type="); |
344 | + if (sock_type_names[sa->aad.net.type]) { | |
345 | + audit_log_string(ab, sock_type_names[sa->aad.net.type]); | |
346 | + } else { | |
347 | + audit_log_format(ab, "\"unknown(%d)\"", sa->aad.net.type); | |
348 | + } | |
2380c486 | 349 | + |
fc63ffa9 | 350 | + audit_log_format(ab, " protocol=%d", sa->aad.net.protocol); |
2380c486 JR |
351 | +} |
352 | + | |
353 | +/** | |
fc63ffa9 AM |
354 | + * audit_net - audit network access |
355 | + * @profile: profile being enforced (NOT NULL) | |
356 | + * @op: operation being checked | |
357 | + * @family: network family | |
358 | + * @type: network type | |
359 | + * @protocol: network protocol | |
360 | + * @sk: socket auditing is being applied to | |
361 | + * @error: error code for failure else 0 | |
ceaf2cfb | 362 | + * |
fc63ffa9 | 363 | + * Returns: %0 or sa->error else other errorcode on failure |
2380c486 | 364 | + */ |
fc63ffa9 AM |
365 | +static int audit_net(struct aa_profile *profile, int op, u16 family, int type, |
366 | + int protocol, struct sock *sk, int error) | |
2380c486 | 367 | +{ |
fc63ffa9 AM |
368 | + int audit_type = AUDIT_APPARMOR_AUTO; |
369 | + struct common_audit_data sa; | |
370 | + if (sk) { | |
371 | + COMMON_AUDIT_DATA_INIT(&sa, NET); | |
372 | + } else { | |
373 | + COMMON_AUDIT_DATA_INIT(&sa, NONE); | |
2380c486 | 374 | + } |
fc63ffa9 | 375 | + /* todo fill in socket addr info */ |
2380c486 | 376 | + |
fc63ffa9 AM |
377 | + sa.aad.op = op, |
378 | + sa.u.net.family = family; | |
379 | + sa.u.net.sk = sk; | |
380 | + sa.aad.net.type = type; | |
381 | + sa.aad.net.protocol = protocol; | |
382 | + sa.aad.error = error; | |
2380c486 | 383 | + |
fc63ffa9 AM |
384 | + if (likely(!sa.aad.error)) { |
385 | + u16 audit_mask = profile->net.audit[sa.u.net.family]; | |
386 | + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && | |
387 | + !(1 << sa.aad.net.type & audit_mask))) | |
ceaf2cfb | 388 | + return 0; |
fc63ffa9 AM |
389 | + audit_type = AUDIT_APPARMOR_AUDIT; |
390 | + } else { | |
391 | + u16 quiet_mask = profile->net.quiet[sa.u.net.family]; | |
392 | + u16 kill_mask = 0; | |
393 | + u16 denied = (1 << sa.aad.net.type) & ~quiet_mask; | |
9474138d | 394 | + |
fc63ffa9 AM |
395 | + if (denied & kill_mask) |
396 | + audit_type = AUDIT_APPARMOR_KILL; | |
9474138d | 397 | + |
fc63ffa9 AM |
398 | + if ((denied & quiet_mask) && |
399 | + AUDIT_MODE(profile) != AUDIT_NOQUIET && | |
400 | + AUDIT_MODE(profile) != AUDIT_ALL) | |
401 | + return COMPLAIN_MODE(profile) ? 0 : sa.aad.error; | |
9474138d AM |
402 | + } |
403 | + | |
fc63ffa9 | 404 | + return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb); |
ceaf2cfb AM |
405 | +} |
406 | + | |
2380c486 | 407 | +/** |
fc63ffa9 AM |
408 | + * aa_net_perm - very course network access check |
409 | + * @op: operation being checked | |
410 | + * @profile: profile being enforced (NOT NULL) | |
411 | + * @family: network family | |
412 | + * @type: network type | |
413 | + * @protocol: network protocol | |
2380c486 | 414 | + * |
fc63ffa9 | 415 | + * Returns: %0 else error if permission denied |
2380c486 | 416 | + */ |
fc63ffa9 AM |
417 | +int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type, |
418 | + int protocol, struct sock *sk) | |
2380c486 | 419 | +{ |
fc63ffa9 AM |
420 | + u16 family_mask; |
421 | + int error; | |
ceaf2cfb | 422 | + |
fc63ffa9 AM |
423 | + if ((family < 0) || (family >= AF_MAX)) |
424 | + return -EINVAL; | |
ceaf2cfb | 425 | + |
fc63ffa9 AM |
426 | + if ((type < 0) || (type >= SOCK_MAX)) |
427 | + return -EINVAL; | |
76514441 | 428 | + |
fc63ffa9 AM |
429 | + /* unix domain and netlink sockets are handled by ipc */ |
430 | + if (family == AF_UNIX || family == AF_NETLINK) | |
431 | + return 0; | |
76514441 | 432 | + |
fc63ffa9 | 433 | + family_mask = profile->net.allow[family]; |
2380c486 | 434 | + |
fc63ffa9 | 435 | + error = (family_mask & (1 << type)) ? 0 : -EACCES; |
ceaf2cfb | 436 | + |
fc63ffa9 | 437 | + return audit_net(profile, op, family, type, protocol, sk, error); |
2380c486 JR |
438 | +} |
439 | + | |
76514441 | 440 | +/** |
fc63ffa9 AM |
441 | + * aa_revalidate_sk - Revalidate access to a sock |
442 | + * @op: operation being checked | |
443 | + * @sk: sock being revalidated (NOT NULL) | |
76514441 | 444 | + * |
fc63ffa9 | 445 | + * Returns: %0 else error if permission denied |
76514441 | 446 | + */ |
fc63ffa9 | 447 | +int aa_revalidate_sk(int op, struct sock *sk) |
2380c486 | 448 | +{ |
fc63ffa9 AM |
449 | + struct aa_profile *profile; |
450 | + int error = 0; | |
2380c486 | 451 | + |
fc63ffa9 AM |
452 | + /* aa_revalidate_sk should not be called from interrupt context |
453 | + * don't mediate these calls as they are not task related | |
454 | + */ | |
455 | + if (in_interrupt()) | |
456 | + return 0; | |
ceaf2cfb | 457 | + |
fc63ffa9 AM |
458 | + profile = __aa_current_profile(); |
459 | + if (!unconfined(profile)) | |
460 | + error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type, | |
461 | + sk->sk_protocol, sk); | |
2380c486 | 462 | + |
fc63ffa9 | 463 | + return error; |
2380c486 | 464 | +} |
fc63ffa9 | 465 | diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c |
948a1326 | 466 | index 4f0eade..4d5ce13 100644 |
fc63ffa9 AM |
467 | --- a/security/apparmor/policy.c |
468 | +++ b/security/apparmor/policy.c | |
469 | @@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile) | |
470 | ||
471 | aa_free_file_rules(&profile->file); | |
472 | aa_free_cap_rules(&profile->caps); | |
473 | + aa_free_net_rules(&profile->net); | |
474 | aa_free_rlimit_rules(&profile->rlimits); | |
475 | ||
476 | aa_free_sid(profile->sid); | |
477 | diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c | |
948a1326 | 478 | index e33aaf7..fa3f1b4 100644 |
fc63ffa9 AM |
479 | --- a/security/apparmor/policy_unpack.c |
480 | +++ b/security/apparmor/policy_unpack.c | |
481 | @@ -190,6 +190,19 @@ fail: | |
482 | return 0; | |
483 | } | |
484 | ||
485 | +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) | |
2380c486 | 486 | +{ |
fc63ffa9 AM |
487 | + if (unpack_nameX(e, AA_U16, name)) { |
488 | + if (!inbounds(e, sizeof(u16))) | |
489 | + return 0; | |
490 | + if (data) | |
491 | + *data = le16_to_cpu(get_unaligned((u16 *) e->pos)); | |
492 | + e->pos += sizeof(u16); | |
493 | + return 1; | |
2380c486 | 494 | + } |
2380c486 JR |
495 | + return 0; |
496 | +} | |
497 | + | |
fc63ffa9 AM |
498 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) |
499 | { | |
500 | if (unpack_nameX(e, AA_U32, name)) { | |
501 | @@ -468,7 +481,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) | |
502 | { | |
503 | struct aa_profile *profile = NULL; | |
504 | const char *name = NULL; | |
505 | - int error = -EPROTO; | |
2380c486 JR |
506 | + size_t size = 0; |
507 | + int i, error = -EPROTO; | |
fc63ffa9 AM |
508 | kernel_cap_t tmpcap; |
509 | u32 tmp; | |
510 | ||
511 | @@ -559,6 +573,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) | |
512 | if (!unpack_rlimits(e, profile)) | |
513 | goto fail; | |
514 | ||
ceaf2cfb | 515 | + size = unpack_array(e, "net_allowed_af"); |
2380c486 | 516 | + if (size) { |
2380c486 JR |
517 | + |
518 | + for (i = 0; i < size; i++) { | |
fc63ffa9 AM |
519 | + /* discard extraneous rules that this kernel will |
520 | + * never request | |
521 | + */ | |
1efb82ae | 522 | + if (i >= AF_MAX) { |
fc63ffa9 AM |
523 | + u16 tmp; |
524 | + if (!unpack_u16(e, &tmp, NULL) || | |
525 | + !unpack_u16(e, &tmp, NULL) || | |
526 | + !unpack_u16(e, &tmp, NULL)) | |
527 | + goto fail; | |
528 | + continue; | |
529 | + } | |
76514441 | 530 | + if (!unpack_u16(e, &profile->net.allow[i], NULL)) |
2380c486 | 531 | + goto fail; |
ceaf2cfb | 532 | + if (!unpack_u16(e, &profile->net.audit[i], NULL)) |
2380c486 | 533 | + goto fail; |
ceaf2cfb | 534 | + if (!unpack_u16(e, &profile->net.quiet[i], NULL)) |
2380c486 JR |
535 | + goto fail; |
536 | + } | |
ceaf2cfb | 537 | + if (!unpack_nameX(e, AA_ARRAYEND, NULL)) |
2380c486 | 538 | + goto fail; |
ceaf2cfb AM |
539 | + /* |
540 | + * allow unix domain and netlink sockets they are handled | |
2380c486 JR |
541 | + * by IPC |
542 | + */ | |
543 | + } | |
76514441 AM |
544 | + profile->net.allow[AF_UNIX] = 0xffff; |
545 | + profile->net.allow[AF_NETLINK] = 0xffff; | |
2380c486 | 546 | + |
fc63ffa9 AM |
547 | /* get file rules */ |
548 | profile->file.dfa = unpack_dfa(e); | |
549 | if (IS_ERR(profile->file.dfa)) { | |
550 | -- | |
948a1326 | 551 | 1.7.0.4 |
fc63ffa9 | 552 | |
948a1326 | 553 | From cdc6b35345e5bcfe92bb2b52ef003f94ceedd40d Mon Sep 17 00:00:00 2001 |
fc63ffa9 AM |
554 | From: John Johansen <john.johansen@canonical.com> |
555 | Date: Thu, 22 Jul 2010 02:32:02 -0700 | |
556 | Subject: [PATCH 2/3] AppArmor: compatibility patch for v5 interface | |
557 | ||
558 | Signed-off-by: John Johansen <john.johansen@canonical.com> | |
559 | --- | |
560 | security/apparmor/Kconfig | 9 + | |
948a1326 | 561 | security/apparmor/Makefile | 1 + |
fc63ffa9 AM |
562 | security/apparmor/apparmorfs-24.c | 287 ++++++++++++++++++++++++++++++++ |
563 | security/apparmor/apparmorfs.c | 18 ++- | |
564 | security/apparmor/include/apparmorfs.h | 6 + | |
948a1326 | 565 | 5 files changed, 319 insertions(+), 2 deletions(-) |
fc63ffa9 AM |
566 | create mode 100644 security/apparmor/apparmorfs-24.c |
567 | ||
568 | diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig | |
569 | index 9b9013b..51ebf96 100644 | |
570 | --- a/security/apparmor/Kconfig | |
571 | +++ b/security/apparmor/Kconfig | |
572 | @@ -29,3 +29,12 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE | |
573 | boot. | |
574 | ||
575 | If you are unsure how to answer this question, answer 1. | |
2380c486 | 576 | + |
fc63ffa9 AM |
577 | +config SECURITY_APPARMOR_COMPAT_24 |
578 | + bool "Enable AppArmor 2.4 compatability" | |
579 | + depends on SECURITY_APPARMOR | |
580 | + default y | |
581 | + help | |
582 | + This option enables compatability with AppArmor 2.4. It is | |
583 | + recommended if compatability with older versions of AppArmor | |
584 | + is desired. | |
585 | diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile | |
948a1326 | 586 | index 7cefef9..0bb604b 100644 |
fc63ffa9 AM |
587 | --- a/security/apparmor/Makefile |
588 | +++ b/security/apparmor/Makefile | |
948a1326 JR |
589 | @@ -5,6 +5,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o |
590 | apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ | |
fc63ffa9 AM |
591 | path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ |
592 | resource.o sid.o file.o net.o | |
fc63ffa9 | 593 | +apparmor-$(CONFIG_SECURITY_APPARMOR_COMPAT_24) += apparmorfs-24.o |
fc63ffa9 | 594 | |
948a1326 JR |
595 | clean-files := capability_names.h rlim_names.h af_names.h |
596 | ||
fc63ffa9 | 597 | diff --git a/security/apparmor/apparmorfs-24.c b/security/apparmor/apparmorfs-24.c |
ceaf2cfb | 598 | new file mode 100644 |
fc63ffa9 | 599 | index 0000000..dc8c744 |
ceaf2cfb | 600 | --- /dev/null |
fc63ffa9 AM |
601 | +++ b/security/apparmor/apparmorfs-24.c |
602 | @@ -0,0 +1,287 @@ | |
2380c486 | 603 | +/* |
9474138d AM |
604 | + * AppArmor security module |
605 | + * | |
fc63ffa9 | 606 | + * This file contains AppArmor /sys/kernel/secrutiy/apparmor interface functions |
2380c486 | 607 | + * |
9474138d | 608 | + * Copyright (C) 1998-2008 Novell/SUSE |
ceaf2cfb | 609 | + * Copyright 2009-2010 Canonical Ltd. |
2380c486 | 610 | + * |
9474138d AM |
611 | + * This program is free software; you can redistribute it and/or |
612 | + * modify it under the terms of the GNU General Public License as | |
613 | + * published by the Free Software Foundation, version 2 of the | |
614 | + * License. | |
fc63ffa9 AM |
615 | + * |
616 | + * | |
617 | + * This file contain functions providing an interface for <= AppArmor 2.4 | |
618 | + * compatibility. It is dependent on CONFIG_SECURITY_APPARMOR_COMPAT_24 | |
619 | + * being set (see Makefile). | |
2380c486 JR |
620 | + */ |
621 | + | |
fc63ffa9 AM |
622 | +#include <linux/security.h> |
623 | +#include <linux/vmalloc.h> | |
624 | +#include <linux/module.h> | |
625 | +#include <linux/seq_file.h> | |
626 | +#include <linux/uaccess.h> | |
627 | +#include <linux/namei.h> | |
628 | + | |
9474138d | 629 | +#include "include/apparmor.h" |
fc63ffa9 | 630 | +#include "include/audit.h" |
76514441 | 631 | +#include "include/context.h" |
9474138d | 632 | +#include "include/policy.h" |
2380c486 | 633 | + |
76514441 | 634 | + |
fc63ffa9 AM |
635 | +/* apparmor/matching */ |
636 | +static ssize_t aa_matching_read(struct file *file, char __user *buf, | |
637 | + size_t size, loff_t *ppos) | |
638 | +{ | |
639 | + const char matching[] = "pattern=aadfa audit perms=crwxamlk/ " | |
640 | + "user::other"; | |
641 | + | |
642 | + return simple_read_from_buffer(buf, size, ppos, matching, | |
643 | + sizeof(matching) - 1); | |
644 | +} | |
645 | + | |
646 | +const struct file_operations aa_fs_matching_fops = { | |
647 | + .read = aa_matching_read, | |
648 | +}; | |
649 | + | |
650 | +/* apparmor/features */ | |
651 | +static ssize_t aa_features_read(struct file *file, char __user *buf, | |
652 | + size_t size, loff_t *ppos) | |
653 | +{ | |
654 | + const char features[] = "file=3.1 capability=2.0 network=1.0 " | |
655 | + "change_hat=1.5 change_profile=1.1 " "aanamespaces=1.1 rlimit=1.1"; | |
656 | + | |
657 | + return simple_read_from_buffer(buf, size, ppos, features, | |
658 | + sizeof(features) - 1); | |
659 | +} | |
660 | + | |
661 | +const struct file_operations aa_fs_features_fops = { | |
662 | + .read = aa_features_read, | |
663 | +}; | |
664 | + | |
ceaf2cfb | 665 | +/** |
fc63ffa9 AM |
666 | + * __next_namespace - find the next namespace to list |
667 | + * @root: root namespace to stop search at (NOT NULL) | |
668 | + * @ns: current ns position (NOT NULL) | |
ceaf2cfb | 669 | + * |
fc63ffa9 AM |
670 | + * Find the next namespace from @ns under @root and handle all locking needed |
671 | + * while switching current namespace. | |
ceaf2cfb | 672 | + * |
fc63ffa9 AM |
673 | + * Returns: next namespace or NULL if at last namespace under @root |
674 | + * NOTE: will not unlock root->lock | |
ceaf2cfb | 675 | + */ |
fc63ffa9 AM |
676 | +static struct aa_namespace *__next_namespace(struct aa_namespace *root, |
677 | + struct aa_namespace *ns) | |
2380c486 | 678 | +{ |
fc63ffa9 | 679 | + struct aa_namespace *parent; |
76514441 | 680 | + |
fc63ffa9 AM |
681 | + /* is next namespace a child */ |
682 | + if (!list_empty(&ns->sub_ns)) { | |
683 | + struct aa_namespace *next; | |
684 | + next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list); | |
685 | + read_lock(&next->lock); | |
686 | + return next; | |
687 | + } | |
2380c486 | 688 | + |
fc63ffa9 AM |
689 | + /* check if the next ns is a sibling, parent, gp, .. */ |
690 | + parent = ns->parent; | |
691 | + while (parent) { | |
692 | + read_unlock(&ns->lock); | |
693 | + list_for_each_entry_continue(ns, &parent->sub_ns, base.list) { | |
694 | + read_lock(&ns->lock); | |
695 | + return ns; | |
696 | + } | |
697 | + if (parent == root) | |
698 | + return NULL; | |
699 | + ns = parent; | |
700 | + parent = parent->parent; | |
2380c486 | 701 | + } |
2380c486 | 702 | + |
fc63ffa9 | 703 | + return NULL; |
2380c486 JR |
704 | +} |
705 | + | |
ceaf2cfb | 706 | +/** |
fc63ffa9 AM |
707 | + * __first_profile - find the first profile in a namespace |
708 | + * @root: namespace that is root of profiles being displayed (NOT NULL) | |
709 | + * @ns: namespace to start in (NOT NULL) | |
ceaf2cfb | 710 | + * |
fc63ffa9 | 711 | + * Returns: unrefcounted profile or NULL if no profile |
ceaf2cfb | 712 | + */ |
fc63ffa9 AM |
713 | +static struct aa_profile *__first_profile(struct aa_namespace *root, |
714 | + struct aa_namespace *ns) | |
2380c486 | 715 | +{ |
fc63ffa9 AM |
716 | + for ( ; ns; ns = __next_namespace(root, ns)) { |
717 | + if (!list_empty(&ns->base.profiles)) | |
718 | + return list_first_entry(&ns->base.profiles, | |
719 | + struct aa_profile, base.list); | |
2380c486 | 720 | + } |
fc63ffa9 | 721 | + return NULL; |
2380c486 JR |
722 | +} |
723 | + | |
ceaf2cfb | 724 | +/** |
fc63ffa9 AM |
725 | + * __next_profile - step to the next profile in a profile tree |
726 | + * @profile: current profile in tree (NOT NULL) | |
727 | + * | |
728 | + * Perform a depth first taversal on the profile tree in a namespace | |
ceaf2cfb | 729 | + * |
fc63ffa9 AM |
730 | + * Returns: next profile or NULL if done |
731 | + * Requires: profile->ns.lock to be held | |
ceaf2cfb | 732 | + */ |
fc63ffa9 | 733 | +static struct aa_profile *__next_profile(struct aa_profile *p) |
2380c486 | 734 | +{ |
fc63ffa9 AM |
735 | + struct aa_profile *parent; |
736 | + struct aa_namespace *ns = p->ns; | |
2380c486 | 737 | + |
fc63ffa9 AM |
738 | + /* is next profile a child */ |
739 | + if (!list_empty(&p->base.profiles)) | |
740 | + return list_first_entry(&p->base.profiles, typeof(*p), | |
741 | + base.list); | |
2380c486 | 742 | + |
fc63ffa9 AM |
743 | + /* is next profile a sibling, parent sibling, gp, subling, .. */ |
744 | + parent = p->parent; | |
745 | + while (parent) { | |
746 | + list_for_each_entry_continue(p, &parent->base.profiles, | |
747 | + base.list) | |
748 | + return p; | |
749 | + p = parent; | |
750 | + parent = parent->parent; | |
ceaf2cfb AM |
751 | + } |
752 | + | |
fc63ffa9 AM |
753 | + /* is next another profile in the namespace */ |
754 | + list_for_each_entry_continue(p, &ns->base.profiles, base.list) | |
755 | + return p; | |
2380c486 | 756 | + |
fc63ffa9 | 757 | + return NULL; |
2380c486 JR |
758 | +} |
759 | + | |
ceaf2cfb | 760 | +/** |
fc63ffa9 AM |
761 | + * next_profile - step to the next profile in where ever it may be |
762 | + * @root: root namespace (NOT NULL) | |
763 | + * @profile: current profile (NOT NULL) | |
ceaf2cfb | 764 | + * |
fc63ffa9 | 765 | + * Returns: next profile or NULL if there isn't one |
ceaf2cfb | 766 | + */ |
fc63ffa9 AM |
767 | +static struct aa_profile *next_profile(struct aa_namespace *root, |
768 | + struct aa_profile *profile) | |
2380c486 | 769 | +{ |
fc63ffa9 AM |
770 | + struct aa_profile *next = __next_profile(profile); |
771 | + if (next) | |
772 | + return next; | |
9474138d | 773 | + |
fc63ffa9 AM |
774 | + /* finished all profiles in namespace move to next namespace */ |
775 | + return __first_profile(root, __next_namespace(root, profile->ns)); | |
9474138d | 776 | +} |
2380c486 | 777 | + |
fc63ffa9 AM |
778 | +/** |
779 | + * p_start - start a depth first traversal of profile tree | |
780 | + * @f: seq_file to fill | |
781 | + * @pos: current position | |
9474138d | 782 | + * |
fc63ffa9 | 783 | + * Returns: first profile under current namespace or NULL if none found |
9474138d | 784 | + * |
fc63ffa9 | 785 | + * acquires first ns->lock |
76514441 | 786 | + */ |
fc63ffa9 AM |
787 | +static void *p_start(struct seq_file *f, loff_t *pos) |
788 | + __acquires(root->lock) | |
2380c486 | 789 | +{ |
fc63ffa9 AM |
790 | + struct aa_profile *profile = NULL; |
791 | + struct aa_namespace *root = aa_current_profile()->ns; | |
792 | + loff_t l = *pos; | |
793 | + f->private = aa_get_namespace(root); | |
9474138d | 794 | + |
9474138d | 795 | + |
fc63ffa9 AM |
796 | + /* find the first profile */ |
797 | + read_lock(&root->lock); | |
798 | + profile = __first_profile(root, root); | |
76514441 | 799 | + |
fc63ffa9 AM |
800 | + /* skip to position */ |
801 | + for (; profile && l > 0; l--) | |
802 | + profile = next_profile(root, profile); | |
803 | + | |
804 | + return profile; | |
76514441 AM |
805 | +} |
806 | + | |
807 | +/** | |
fc63ffa9 AM |
808 | + * p_next - read the next profile entry |
809 | + * @f: seq_file to fill | |
810 | + * @p: profile previously returned | |
811 | + * @pos: current position | |
76514441 | 812 | + * |
fc63ffa9 | 813 | + * Returns: next profile after @p or NULL if none |
76514441 | 814 | + * |
fc63ffa9 | 815 | + * may acquire/release locks in namespace tree as necessary |
76514441 | 816 | + */ |
fc63ffa9 | 817 | +static void *p_next(struct seq_file *f, void *p, loff_t *pos) |
9474138d | 818 | +{ |
fc63ffa9 AM |
819 | + struct aa_profile *profile = p; |
820 | + struct aa_namespace *root = f->private; | |
821 | + (*pos)++; | |
822 | + | |
823 | + return next_profile(root, profile); | |
9474138d AM |
824 | +} |
825 | + | |
826 | +/** | |
fc63ffa9 AM |
827 | + * p_stop - stop depth first traversal |
828 | + * @f: seq_file we are filling | |
829 | + * @p: the last profile writen | |
ceaf2cfb | 830 | + * |
fc63ffa9 | 831 | + * Release all locking done by p_start/p_next on namespace tree |
9474138d | 832 | + */ |
fc63ffa9 AM |
833 | +static void p_stop(struct seq_file *f, void *p) |
834 | + __releases(root->lock) | |
9474138d | 835 | +{ |
fc63ffa9 AM |
836 | + struct aa_profile *profile = p; |
837 | + struct aa_namespace *root = f->private, *ns; | |
2380c486 | 838 | + |
fc63ffa9 AM |
839 | + if (profile) { |
840 | + for (ns = profile->ns; ns && ns != root; ns = ns->parent) | |
841 | + read_unlock(&ns->lock); | |
842 | + } | |
843 | + read_unlock(&root->lock); | |
844 | + aa_put_namespace(root); | |
9474138d AM |
845 | +} |
846 | + | |
ceaf2cfb | 847 | +/** |
fc63ffa9 AM |
848 | + * seq_show_profile - show a profile entry |
849 | + * @f: seq_file to file | |
850 | + * @p: current position (profile) (NOT NULL) | |
851 | + * | |
852 | + * Returns: error on failure | |
ceaf2cfb | 853 | + */ |
fc63ffa9 | 854 | +static int seq_show_profile(struct seq_file *f, void *p) |
9474138d | 855 | +{ |
fc63ffa9 AM |
856 | + struct aa_profile *profile = (struct aa_profile *)p; |
857 | + struct aa_namespace *root = f->private; | |
2380c486 | 858 | + |
fc63ffa9 AM |
859 | + if (profile->ns != root) |
860 | + seq_printf(f, ":%s://", aa_ns_name(root, profile->ns)); | |
861 | + seq_printf(f, "%s (%s)\n", profile->base.hname, | |
862 | + COMPLAIN_MODE(profile) ? "complain" : "enforce"); | |
2380c486 | 863 | + |
fc63ffa9 | 864 | + return 0; |
9474138d | 865 | +} |
9474138d | 866 | + |
fc63ffa9 AM |
867 | +static const struct seq_operations aa_fs_profiles_op = { |
868 | + .start = p_start, | |
869 | + .next = p_next, | |
870 | + .stop = p_stop, | |
871 | + .show = seq_show_profile, | |
872 | +}; | |
9474138d | 873 | + |
fc63ffa9 | 874 | +static int profiles_open(struct inode *inode, struct file *file) |
9474138d | 875 | +{ |
fc63ffa9 | 876 | + return seq_open(file, &aa_fs_profiles_op); |
9474138d AM |
877 | +} |
878 | + | |
fc63ffa9 | 879 | +static int profiles_release(struct inode *inode, struct file *file) |
9474138d | 880 | +{ |
fc63ffa9 | 881 | + return seq_release(inode, file); |
9474138d | 882 | +} |
fc63ffa9 AM |
883 | + |
884 | +const struct file_operations aa_fs_profiles_fops = { | |
885 | + .open = profiles_open, | |
886 | + .read = seq_read, | |
887 | + .llseek = seq_lseek, | |
888 | + .release = profiles_release, | |
889 | +}; | |
890 | diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c | |
948a1326 | 891 | index 0848292..28c52ac 100644 |
fc63ffa9 AM |
892 | --- a/security/apparmor/apparmorfs.c |
893 | +++ b/security/apparmor/apparmorfs.c | |
948a1326 | 894 | @@ -187,7 +187,11 @@ void __init aa_destroy_aafs(void) |
fc63ffa9 AM |
895 | aafs_remove(".remove"); |
896 | aafs_remove(".replace"); | |
897 | aafs_remove(".load"); | |
898 | - | |
899 | +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 | |
900 | + aafs_remove("profiles"); | |
901 | + aafs_remove("matching"); | |
902 | + aafs_remove("features"); | |
903 | +#endif | |
904 | securityfs_remove(aa_fs_dentry); | |
905 | aa_fs_dentry = NULL; | |
906 | } | |
948a1326 | 907 | @@ -218,7 +222,17 @@ int __init aa_create_aafs(void) |
fc63ffa9 AM |
908 | aa_fs_dentry = NULL; |
909 | goto error; | |
910 | } | |
911 | - | |
912 | +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 | |
913 | + error = aafs_create("matching", 0444, &aa_fs_matching_fops); | |
914 | + if (error) | |
915 | + goto error; | |
916 | + error = aafs_create("features", 0444, &aa_fs_features_fops); | |
917 | + if (error) | |
918 | + goto error; | |
919 | +#endif | |
920 | + error = aafs_create("profiles", 0440, &aa_fs_profiles_fops); | |
921 | + if (error) | |
922 | + goto error; | |
923 | error = aafs_create(".load", 0640, &aa_fs_profile_load); | |
924 | if (error) | |
925 | goto error; | |
926 | diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h | |
927 | index cb1e93a..14f955c 100644 | |
928 | --- a/security/apparmor/include/apparmorfs.h | |
929 | +++ b/security/apparmor/include/apparmorfs.h | |
930 | @@ -17,4 +17,10 @@ | |
931 | ||
932 | extern void __init aa_destroy_aafs(void); | |
933 | ||
934 | +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 | |
935 | +extern const struct file_operations aa_fs_matching_fops; | |
936 | +extern const struct file_operations aa_fs_features_fops; | |
937 | +extern const struct file_operations aa_fs_profiles_fops; | |
938 | +#endif | |
939 | + | |
940 | #endif /* __AA_APPARMORFS_H */ | |
76514441 | 941 | -- |
948a1326 JR |
942 | 1.7.0.4 |
943 | ||
944 | From f17b28f64b963c47e76737f7bb7f58ce3a7c5249 Mon Sep 17 00:00:00 2001 | |
945 | From: John Johansen <john.johansen@canonical.com> | |
946 | Date: Tue, 20 Jul 2010 06:57:08 -0700 | |
947 | Subject: [PATCH 3/3] AppArmor: Allow dfa backward compatibility with broken userspace | |
948 | ||
949 | The apparmor_parser when compiling policy could generate invalid dfas | |
950 | that did not have sufficient padding to avoid invalid references, when | |
951 | used by the kernel. The kernels check to verify the next/check table | |
952 | size was broken meaning invalid dfas were being created by userspace | |
953 | and not caught. | |
954 | ||
955 | To remain compatible with old tools that are not fixed, pad the loaded | |
956 | dfas next/check table. The dfa's themselves are valid except for the | |
957 | high padding for potentially invalid transitions (high bounds error), | |
958 | which have a maximimum is 256 entries. So just allocate an extra null filled | |
959 | 256 entries for the next/check tables. This will guarentee all bounds | |
960 | are good and invalid transitions go to the null (0) state. | |
961 | ||
962 | Signed-off-by: John Johansen <john.johansen@canonical.com> | |
963 | --- | |
964 | security/apparmor/match.c | 17 +++++++++++++++++ | |
965 | 1 files changed, 17 insertions(+), 0 deletions(-) | |
966 | ||
967 | diff --git a/security/apparmor/match.c b/security/apparmor/match.c | |
968 | index 06d764c..cf92856 100644 | |
969 | --- a/security/apparmor/match.c | |
970 | +++ b/security/apparmor/match.c | |
971 | @@ -57,8 +57,17 @@ static struct table_header *unpack_table(char *blob, size_t bsize) | |
972 | if (bsize < tsize) | |
973 | goto out; | |
974 | ||
975 | + /* Pad table allocation for next/check by 256 entries to remain | |
976 | + * backwards compatible with old (buggy) tools and remain safe without | |
977 | + * run time checks | |
978 | + */ | |
979 | + if (th.td_id == YYTD_ID_NXT || th.td_id == YYTD_ID_CHK) | |
980 | + tsize += 256 * th.td_flags; | |
981 | + | |
982 | table = kvmalloc(tsize); | |
983 | if (table) { | |
984 | + /* ensure the pad is clear, else there will be errors */ | |
985 | + memset(table, 0, tsize); | |
986 | *table = th; | |
987 | if (th.td_flags == YYTD_DATA8) | |
988 | UNPACK_ARRAY(table->td_data, blob, th.td_lolen, | |
989 | @@ -134,11 +143,19 @@ static int verify_dfa(struct aa_dfa *dfa, int flags) | |
990 | goto out; | |
991 | ||
992 | if (flags & DFA_FLAG_VERIFY_STATES) { | |
993 | + int warning = 0; | |
994 | for (i = 0; i < state_count; i++) { | |
995 | if (DEFAULT_TABLE(dfa)[i] >= state_count) | |
996 | goto out; | |
997 | /* TODO: do check that DEF state recursion terminates */ | |
998 | if (BASE_TABLE(dfa)[i] + 255 >= trans_count) { | |
999 | + if (warning) | |
1000 | + continue; | |
1001 | + printk(KERN_WARNING "AppArmor DFA next/check " | |
1002 | + "upper bounds error fixed, upgrade " | |
1003 | + "user space tools \n"); | |
1004 | + warning = 1; | |
1005 | + } else if (BASE_TABLE(dfa)[i] >= trans_count) { | |
1006 | printk(KERN_ERR "AppArmor DFA next/check upper " | |
1007 | "bounds error\n"); | |
1008 | goto out; | |
1009 | -- | |
1010 | 1.7.0.4 | |
76514441 | 1011 |