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