aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor')
-rw-r--r--security/apparmor/Makefile5
-rw-r--r--security/apparmor/audit.c6
-rw-r--r--security/apparmor/domain.c5
-rw-r--r--security/apparmor/file.c18
-rw-r--r--security/apparmor/include/apparmor.h15
-rw-r--r--security/apparmor/include/audit.h4
-rw-r--r--security/apparmor/include/match.h3
-rw-r--r--security/apparmor/include/path.h3
-rw-r--r--security/apparmor/include/policy.h15
-rw-r--r--security/apparmor/match.c80
-rw-r--r--security/apparmor/path.c55
-rw-r--r--security/apparmor/policy.c3
-rw-r--r--security/apparmor/policy_unpack.c29
13 files changed, 189 insertions, 52 deletions
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index 86103ce5b7a7..7e14edd9ec60 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -15,7 +15,7 @@ clean-files := capability_names.h rlim_names.h
15# to 15# to
16# [1] = "dac_override", 16# [1] = "dac_override",
17quiet_cmd_make-caps = GEN $@ 17quiet_cmd_make-caps = GEN $@
18cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\ 18cmd_make-caps = echo "static const char const *capability_names[] = {" > $@ ;\
19 sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \ 19 sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \
20 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\ 20 -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
21 echo "};" >> $@ 21 echo "};" >> $@
@@ -43,7 +43,8 @@ cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\
43# to 43# to
44# #define AA_FS_RLIMIT_MASK "fsize stack" 44# #define AA_FS_RLIMIT_MASK "fsize stack"
45quiet_cmd_make-rlim = GEN $@ 45quiet_cmd_make-rlim = GEN $@
46cmd_make-rlim = echo "static const char *rlim_names[RLIM_NLIMITS] = {" > $@ ;\ 46cmd_make-rlim = echo "static const char const *rlim_names[RLIM_NLIMITS] = {" \
47 > $@ ;\
47 sed $< >> $@ -r -n \ 48 sed $< >> $@ -r -n \
48 -e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\ 49 -e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\
49 echo "};" >> $@ ;\ 50 echo "};" >> $@ ;\
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 61344b56722e..5ff67776a5ad 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -19,7 +19,7 @@
19#include "include/audit.h" 19#include "include/audit.h"
20#include "include/policy.h" 20#include "include/policy.h"
21 21
22const char *op_table[] = { 22const char *const op_table[] = {
23 "null", 23 "null",
24 24
25 "sysctl", 25 "sysctl",
@@ -73,7 +73,7 @@ const char *op_table[] = {
73 "profile_remove" 73 "profile_remove"
74}; 74};
75 75
76const char *audit_mode_names[] = { 76const char *const audit_mode_names[] = {
77 "normal", 77 "normal",
78 "quiet_denied", 78 "quiet_denied",
79 "quiet", 79 "quiet",
@@ -81,7 +81,7 @@ const char *audit_mode_names[] = {
81 "all" 81 "all"
82}; 82};
83 83
84static char *aa_audit_type[] = { 84static const char *const aa_audit_type[] = {
85 "AUDIT", 85 "AUDIT",
86 "ALLOWED", 86 "ALLOWED",
87 "DENIED", 87 "DENIED",
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index c1e18ba5bdc0..7c69599a69e1 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -372,13 +372,12 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
372 state = profile->file.start; 372 state = profile->file.start;
373 373
374 /* buffer freed below, name is pointer into buffer */ 374 /* buffer freed below, name is pointer into buffer */
375 error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer, 375 error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer,
376 &name); 376 &name, &info);
377 if (error) { 377 if (error) {
378 if (profile->flags & 378 if (profile->flags &
379 (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED)) 379 (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED))
380 error = 0; 380 error = 0;
381 info = "Exec failed name resolution";
382 name = bprm->filename; 381 name = bprm->filename;
383 goto audit; 382 goto audit;
384 } 383 }
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index bba875c4d068..3022c0f4f0db 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -278,22 +278,16 @@ int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
278 int error; 278 int error;
279 279
280 flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0); 280 flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
281 error = aa_get_name(path, flags, &buffer, &name); 281 error = aa_path_name(path, flags, &buffer, &name, &info);
282 if (error) { 282 if (error) {
283 if (error == -ENOENT && is_deleted(path->dentry)) { 283 if (error == -ENOENT && is_deleted(path->dentry)) {
284 /* Access to open files that are deleted are 284 /* Access to open files that are deleted are
285 * give a pass (implicit delegation) 285 * give a pass (implicit delegation)
286 */ 286 */
287 error = 0; 287 error = 0;
288 info = NULL;
288 perms.allow = request; 289 perms.allow = request;
289 } else if (error == -ENOENT) 290 }
290 info = "Failed name lookup - deleted entry";
291 else if (error == -ESTALE)
292 info = "Failed name lookup - disconnected path";
293 else if (error == -ENAMETOOLONG)
294 info = "Failed name lookup - name too long";
295 else
296 info = "Failed name lookup";
297 } else { 291 } else {
298 aa_str_perms(profile->file.dfa, profile->file.start, name, cond, 292 aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
299 &perms); 293 &perms);
@@ -364,12 +358,14 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
364 lperms = nullperms; 358 lperms = nullperms;
365 359
366 /* buffer freed below, lname is pointer in buffer */ 360 /* buffer freed below, lname is pointer in buffer */
367 error = aa_get_name(&link, profile->path_flags, &buffer, &lname); 361 error = aa_path_name(&link, profile->path_flags, &buffer, &lname,
362 &info);
368 if (error) 363 if (error)
369 goto audit; 364 goto audit;
370 365
371 /* buffer2 freed below, tname is pointer in buffer2 */ 366 /* buffer2 freed below, tname is pointer in buffer2 */
372 error = aa_get_name(&target, profile->path_flags, &buffer2, &tname); 367 error = aa_path_name(&target, profile->path_flags, &buffer2, &tname,
368 &info);
373 if (error) 369 if (error)
374 goto audit; 370 goto audit;
375 371
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index df3649560818..40aedd9f73ea 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -19,6 +19,19 @@
19 19
20#include "match.h" 20#include "match.h"
21 21
22/*
23 * Class of mediation types in the AppArmor policy db
24 */
25#define AA_CLASS_ENTRY 0
26#define AA_CLASS_UNKNOWN 1
27#define AA_CLASS_FILE 2
28#define AA_CLASS_CAP 3
29#define AA_CLASS_NET 4
30#define AA_CLASS_RLIMITS 5
31#define AA_CLASS_DOMAIN 6
32
33#define AA_CLASS_LAST AA_CLASS_DOMAIN
34
22/* Control parameters settable through module/boot flags */ 35/* Control parameters settable through module/boot flags */
23extern enum audit_mode aa_g_audit; 36extern enum audit_mode aa_g_audit;
24extern bool aa_g_audit_header; 37extern bool aa_g_audit_header;
@@ -81,7 +94,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
81 unsigned int start) 94 unsigned int start)
82{ 95{
83 /* the null transition only needs the string's null terminator byte */ 96 /* the null transition only needs the string's null terminator byte */
84 return aa_dfa_match_len(dfa, start, "", 1); 97 return aa_dfa_next(dfa, start, 0);
85} 98}
86 99
87static inline bool mediated_filesystem(struct inode *inode) 100static inline bool mediated_filesystem(struct inode *inode)
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 9317cd81416c..4ba78c203af1 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -25,7 +25,7 @@
25 25
26struct aa_profile; 26struct aa_profile;
27 27
28extern const char *audit_mode_names[]; 28extern const char *const audit_mode_names[];
29#define AUDIT_MAX_INDEX 5 29#define AUDIT_MAX_INDEX 5
30 30
31enum audit_mode { 31enum audit_mode {
@@ -47,7 +47,7 @@ enum audit_type {
47 AUDIT_APPARMOR_AUTO 47 AUDIT_APPARMOR_AUTO
48}; 48};
49 49
50extern const char *op_table[]; 50extern const char *const op_table[];
51enum aa_ops { 51enum aa_ops {
52 OP_NULL, 52 OP_NULL,
53 53
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
index a4a863997bd5..775843e7f984 100644
--- a/security/apparmor/include/match.h
+++ b/security/apparmor/include/match.h
@@ -116,6 +116,9 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
116 const char *str, int len); 116 const char *str, int len);
117unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 117unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
118 const char *str); 118 const char *str);
119unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
120 const char c);
121
119void aa_dfa_free_kref(struct kref *kref); 122void aa_dfa_free_kref(struct kref *kref);
120 123
121/** 124/**
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
index 27b327a7fae5..286ac75dc88b 100644
--- a/security/apparmor/include/path.h
+++ b/security/apparmor/include/path.h
@@ -26,6 +26,7 @@ enum path_flags {
26 PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ 26 PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
27}; 27};
28 28
29int aa_get_name(struct path *path, int flags, char **buffer, const char **name); 29int aa_path_name(struct path *path, int flags, char **buffer,
30 const char **name, const char **info);
30 31
31#endif /* __AA_PATH_H */ 32#endif /* __AA_PATH_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index aeda5cf56904..bda4569fdd83 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -29,7 +29,7 @@
29#include "file.h" 29#include "file.h"
30#include "resource.h" 30#include "resource.h"
31 31
32extern const char *profile_mode_names[]; 32extern const char *const profile_mode_names[];
33#define APPARMOR_NAMES_MAX_INDEX 3 33#define APPARMOR_NAMES_MAX_INDEX 3
34 34
35#define COMPLAIN_MODE(_profile) \ 35#define COMPLAIN_MODE(_profile) \
@@ -129,6 +129,17 @@ struct aa_namespace {
129 struct list_head sub_ns; 129 struct list_head sub_ns;
130}; 130};
131 131
132/* struct aa_policydb - match engine for a policy
133 * dfa: dfa pattern match
134 * start: set of start states for the different classes of data
135 */
136struct aa_policydb {
137 /* Generic policy DFA specific rule types will be subsections of it */
138 struct aa_dfa *dfa;
139 unsigned int start[AA_CLASS_LAST + 1];
140
141};
142
132/* struct aa_profile - basic confinement data 143/* struct aa_profile - basic confinement data
133 * @base - base components of the profile (name, refcount, lists, lock ...) 144 * @base - base components of the profile (name, refcount, lists, lock ...)
134 * @parent: parent of profile 145 * @parent: parent of profile
@@ -143,6 +154,7 @@ struct aa_namespace {
143 * @flags: flags controlling profile behavior 154 * @flags: flags controlling profile behavior
144 * @path_flags: flags controlling path generation behavior 155 * @path_flags: flags controlling path generation behavior
145 * @size: the memory consumed by this profiles rules 156 * @size: the memory consumed by this profiles rules
157 * @policy: general match rules governing policy
146 * @file: The set of rules governing basic file access and domain transitions 158 * @file: The set of rules governing basic file access and domain transitions
147 * @caps: capabilities for the profile 159 * @caps: capabilities for the profile
148 * @rlimits: rlimits for the profile 160 * @rlimits: rlimits for the profile
@@ -179,6 +191,7 @@ struct aa_profile {
179 u32 path_flags; 191 u32 path_flags;
180 int size; 192 int size;
181 193
194 struct aa_policydb policy;
182 struct aa_file_rules file; 195 struct aa_file_rules file;
183 struct aa_caps caps; 196 struct aa_caps caps;
184 struct aa_rlimit rlimits; 197 struct aa_rlimit rlimits;
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index 94de6b4907c8..90971a8c3789 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -335,12 +335,12 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
335} 335}
336 336
337/** 337/**
338 * aa_dfa_next_state - traverse @dfa to find state @str stops at 338 * aa_dfa_match - traverse @dfa to find state @str stops at
339 * @dfa: the dfa to match @str against (NOT NULL) 339 * @dfa: the dfa to match @str against (NOT NULL)
340 * @start: the state of the dfa to start matching in 340 * @start: the state of the dfa to start matching in
341 * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 341 * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
342 * 342 *
343 * aa_dfa_next_state will match @str against the dfa and return the state it 343 * aa_dfa_match will match @str against the dfa and return the state it
344 * finished matching in. The final state can be used to look up the accepting 344 * finished matching in. The final state can be used to look up the accepting
345 * label, or as the start state of a continuing match. 345 * label, or as the start state of a continuing match.
346 * 346 *
@@ -349,5 +349,79 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
349unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 349unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
350 const char *str) 350 const char *str)
351{ 351{
352 return aa_dfa_match_len(dfa, start, str, strlen(str)); 352 u16 *def = DEFAULT_TABLE(dfa);
353 u32 *base = BASE_TABLE(dfa);
354 u16 *next = NEXT_TABLE(dfa);
355 u16 *check = CHECK_TABLE(dfa);
356 unsigned int state = start, pos;
357
358 if (state == 0)
359 return 0;
360
361 /* current state is <state>, matching character *str */
362 if (dfa->tables[YYTD_ID_EC]) {
363 /* Equivalence class table defined */
364 u8 *equiv = EQUIV_TABLE(dfa);
365 /* default is direct to next state */
366 while (*str) {
367 pos = base[state] + equiv[(u8) *str++];
368 if (check[pos] == state)
369 state = next[pos];
370 else
371 state = def[state];
372 }
373 } else {
374 /* default is direct to next state */
375 while (*str) {
376 pos = base[state] + (u8) *str++;
377 if (check[pos] == state)
378 state = next[pos];
379 else
380 state = def[state];
381 }
382 }
383
384 return state;
385}
386
387/**
388 * aa_dfa_next - step one character to the next state in the dfa
389 * @dfa: the dfa to tranverse (NOT NULL)
390 * @state: the state to start in
391 * @c: the input character to transition on
392 *
393 * aa_dfa_match will step through the dfa by one input character @c
394 *
395 * Returns: state reach after input @c
396 */
397unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
398 const char c)
399{
400 u16 *def = DEFAULT_TABLE(dfa);
401 u32 *base = BASE_TABLE(dfa);
402 u16 *next = NEXT_TABLE(dfa);
403 u16 *check = CHECK_TABLE(dfa);
404 unsigned int pos;
405
406 /* current state is <state>, matching character *str */
407 if (dfa->tables[YYTD_ID_EC]) {
408 /* Equivalence class table defined */
409 u8 *equiv = EQUIV_TABLE(dfa);
410 /* default is direct to next state */
411
412 pos = base[state] + equiv[(u8) c];
413 if (check[pos] == state)
414 state = next[pos];
415 else
416 state = def[state];
417 } else {
418 /* default is direct to next state */
419 pos = base[state] + (u8) c;
420 if (check[pos] == state)
421 state = next[pos];
422 else
423 state = def[state];
424 }
425
426 return state;
353} 427}
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index c31ce837fef4..2daeea4f9266 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -83,30 +83,29 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
83 struct path root; 83 struct path root;
84 get_fs_root(current->fs, &root); 84 get_fs_root(current->fs, &root);
85 res = __d_path(path, &root, buf, buflen); 85 res = __d_path(path, &root, buf, buflen);
86 if (res && !IS_ERR(res)) {
87 /* everything's fine */
88 *name = res;
89 path_put(&root);
90 goto ok;
91 }
92 path_put(&root); 86 path_put(&root);
93 connected = 0; 87 } else {
94 } else
95 res = d_absolute_path(path, buf, buflen); 88 res = d_absolute_path(path, buf, buflen);
89 if (!our_mnt(path->mnt))
90 connected = 0;
91 }
96 92
97 *name = res;
98 /* handle error conditions - and still allow a partial path to 93 /* handle error conditions - and still allow a partial path to
99 * be returned. 94 * be returned.
100 */ 95 */
101 if (IS_ERR(res)) { 96 if (!res || IS_ERR(res)) {
102 error = PTR_ERR(res);
103 *name = buf;
104 goto out;
105 }
106 if (!our_mnt(path->mnt))
107 connected = 0; 97 connected = 0;
98 res = dentry_path_raw(path->dentry, buf, buflen);
99 if (IS_ERR(res)) {
100 error = PTR_ERR(res);
101 *name = buf;
102 goto out;
103 };
104 } else if (!our_mnt(path->mnt))
105 connected = 0;
106
107 *name = res;
108 108
109ok:
110 /* Handle two cases: 109 /* Handle two cases:
111 * 1. A deleted dentry && profile is not allowing mediation of deleted 110 * 1. A deleted dentry && profile is not allowing mediation of deleted
112 * 2. On some filesystems, newly allocated dentries appear to the 111 * 2. On some filesystems, newly allocated dentries appear to the
@@ -137,7 +136,7 @@ ok:
137 /* disconnected path, don't return pathname starting 136 /* disconnected path, don't return pathname starting
138 * with '/' 137 * with '/'
139 */ 138 */
140 error = -ESTALE; 139 error = -EACCES;
141 if (*res == '/') 140 if (*res == '/')
142 *name = res + 1; 141 *name = res + 1;
143 } 142 }
@@ -158,7 +157,7 @@ out:
158 * Returns: %0 else error on failure 157 * Returns: %0 else error on failure
159 */ 158 */
160static int get_name_to_buffer(struct path *path, int flags, char *buffer, 159static int get_name_to_buffer(struct path *path, int flags, char *buffer,
161 int size, char **name) 160 int size, char **name, const char **info)
162{ 161{
163 int adjust = (flags & PATH_IS_DIR) ? 1 : 0; 162 int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
164 int error = d_namespace_path(path, buffer, size - adjust, name, flags); 163 int error = d_namespace_path(path, buffer, size - adjust, name, flags);
@@ -170,15 +169,27 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer,
170 */ 169 */
171 strcpy(&buffer[size - 2], "/"); 170 strcpy(&buffer[size - 2], "/");
172 171
172 if (info && error) {
173 if (error == -ENOENT)
174 *info = "Failed name lookup - deleted entry";
175 else if (error == -ESTALE)
176 *info = "Failed name lookup - disconnected path";
177 else if (error == -ENAMETOOLONG)
178 *info = "Failed name lookup - name too long";
179 else
180 *info = "Failed name lookup";
181 }
182
173 return error; 183 return error;
174} 184}
175 185
176/** 186/**
177 * aa_get_name - compute the pathname of a file 187 * aa_path_name - compute the pathname of a file
178 * @path: path the file (NOT NULL) 188 * @path: path the file (NOT NULL)
179 * @flags: flags controlling path name generation 189 * @flags: flags controlling path name generation
180 * @buffer: buffer that aa_get_name() allocated (NOT NULL) 190 * @buffer: buffer that aa_get_name() allocated (NOT NULL)
181 * @name: Returns - the generated path name if !error (NOT NULL) 191 * @name: Returns - the generated path name if !error (NOT NULL)
192 * @info: Returns - information on why the path lookup failed (MAYBE NULL)
182 * 193 *
183 * @name is a pointer to the beginning of the pathname (which usually differs 194 * @name is a pointer to the beginning of the pathname (which usually differs
184 * from the beginning of the buffer), or NULL. If there is an error @name 195 * from the beginning of the buffer), or NULL. If there is an error @name
@@ -191,7 +202,8 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer,
191 * 202 *
192 * Returns: %0 else error code if could retrieve name 203 * Returns: %0 else error code if could retrieve name
193 */ 204 */
194int aa_get_name(struct path *path, int flags, char **buffer, const char **name) 205int aa_path_name(struct path *path, int flags, char **buffer, const char **name,
206 const char **info)
195{ 207{
196 char *buf, *str = NULL; 208 char *buf, *str = NULL;
197 int size = 256; 209 int size = 256;
@@ -205,7 +217,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
205 if (!buf) 217 if (!buf)
206 return -ENOMEM; 218 return -ENOMEM;
207 219
208 error = get_name_to_buffer(path, flags, buf, size, &str); 220 error = get_name_to_buffer(path, flags, buf, size, &str, info);
209 if (error != -ENAMETOOLONG) 221 if (error != -ENAMETOOLONG)
210 break; 222 break;
211 223
@@ -213,6 +225,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
213 size <<= 1; 225 size <<= 1;
214 if (size > aa_g_path_max) 226 if (size > aa_g_path_max)
215 return -ENAMETOOLONG; 227 return -ENAMETOOLONG;
228 *info = NULL;
216 } 229 }
217 *buffer = buf; 230 *buffer = buf;
218 *name = str; 231 *name = str;
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 4f0eadee78b8..906414383022 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -93,7 +93,7 @@
93/* root profile namespace */ 93/* root profile namespace */
94struct aa_namespace *root_ns; 94struct aa_namespace *root_ns;
95 95
96const char *profile_mode_names[] = { 96const char *const profile_mode_names[] = {
97 "enforce", 97 "enforce",
98 "complain", 98 "complain",
99 "kill", 99 "kill",
@@ -749,6 +749,7 @@ static void free_profile(struct aa_profile *profile)
749 749
750 aa_free_sid(profile->sid); 750 aa_free_sid(profile->sid);
751 aa_put_dfa(profile->xmatch); 751 aa_put_dfa(profile->xmatch);
752 aa_put_dfa(profile->policy.dfa);
752 753
753 aa_put_profile(profile->replacedby); 754 aa_put_profile(profile->replacedby);
754 755
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 5c46acf5aa65..25fd51edc8da 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -84,7 +84,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
84 * @new: profile if it has been allocated (MAYBE NULL) 84 * @new: profile if it has been allocated (MAYBE NULL)
85 * @name: name of the profile being manipulated (MAYBE NULL) 85 * @name: name of the profile being manipulated (MAYBE NULL)
86 * @info: any extra info about the failure (MAYBE NULL) 86 * @info: any extra info about the failure (MAYBE NULL)
87 * @e: buffer position info (NOT NULL) 87 * @e: buffer position info
88 * @error: error code 88 * @error: error code
89 * 89 *
90 * Returns: %0 or error 90 * Returns: %0 or error
@@ -95,7 +95,8 @@ static int audit_iface(struct aa_profile *new, const char *name,
95 struct aa_profile *profile = __aa_current_profile(); 95 struct aa_profile *profile = __aa_current_profile();
96 struct common_audit_data sa; 96 struct common_audit_data sa;
97 COMMON_AUDIT_DATA_INIT(&sa, NONE); 97 COMMON_AUDIT_DATA_INIT(&sa, NONE);
98 sa.aad.iface.pos = e->pos - e->start; 98 if (e)
99 sa.aad.iface.pos = e->pos - e->start;
99 sa.aad.iface.target = new; 100 sa.aad.iface.target = new;
100 sa.aad.name = name; 101 sa.aad.name = name;
101 sa.aad.info = info; 102 sa.aad.info = info;
@@ -468,7 +469,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
468{ 469{
469 struct aa_profile *profile = NULL; 470 struct aa_profile *profile = NULL;
470 const char *name = NULL; 471 const char *name = NULL;
471 int error = -EPROTO; 472 int i, error = -EPROTO;
472 kernel_cap_t tmpcap; 473 kernel_cap_t tmpcap;
473 u32 tmp; 474 u32 tmp;
474 475
@@ -561,6 +562,28 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
561 if (!unpack_rlimits(e, profile)) 562 if (!unpack_rlimits(e, profile))
562 goto fail; 563 goto fail;
563 564
565 if (unpack_nameX(e, AA_STRUCT, "policydb")) {
566 /* generic policy dfa - optional and may be NULL */
567 profile->policy.dfa = unpack_dfa(e);
568 if (IS_ERR(profile->policy.dfa)) {
569 error = PTR_ERR(profile->policy.dfa);
570 profile->policy.dfa = NULL;
571 goto fail;
572 }
573 if (!unpack_u32(e, &profile->policy.start[0], "start"))
574 /* default start state */
575 profile->policy.start[0] = DFA_START;
576 /* setup class index */
577 for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) {
578 profile->policy.start[i] =
579 aa_dfa_next(profile->policy.dfa,
580 profile->policy.start[0],
581 i);
582 }
583 if (!unpack_nameX(e, AA_STRUCTEND, NULL))
584 goto fail;
585 }
586
564 /* get file rules */ 587 /* get file rules */
565 profile->file.dfa = unpack_dfa(e); 588 profile->file.dfa = unpack_dfa(e);
566 if (IS_ERR(profile->file.dfa)) { 589 if (IS_ERR(profile->file.dfa)) {