diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 16:25:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 16:25:04 -0400 |
commit | 3556485f1595e3964ba539e39ea682acbb835cee (patch) | |
tree | 7f5ee254f425b1427ac0059b5f347a307f8538a1 /security/apparmor | |
parent | b8716614a7cc2fc15ea2a518edd04755fb08d922 (diff) | |
parent | 09f61cdbb32a9d812c618d3922db533542736bb0 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates for 3.4 from James Morris:
"The main addition here is the new Yama security module from Kees Cook,
which was discussed at the Linux Security Summit last year. Its
purpose is to collect miscellaneous DAC security enhancements in one
place. This also marks a departure in policy for LSM modules, which
were previously limited to being standalone access control systems.
Chromium OS is using Yama, and I believe there are plans for Ubuntu,
at least.
This patchset also includes maintenance updates for AppArmor, TOMOYO
and others."
Fix trivial conflict in <net/sock.h> due to the jumo_label->static_key
rename.
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (38 commits)
AppArmor: Fix location of const qualifier on generated string tables
TOMOYO: Return error if fails to delete a domain
AppArmor: add const qualifiers to string arrays
AppArmor: Add ability to load extended policy
TOMOYO: Return appropriate value to poll().
AppArmor: Move path failure information into aa_get_name and rename
AppArmor: Update dfa matching routines.
AppArmor: Minor cleanup of d_namespace_path to consolidate error handling
AppArmor: Retrieve the dentry_path for error reporting when path lookup fails
AppArmor: Add const qualifiers to generated string tables
AppArmor: Fix oops in policy unpack auditing
AppArmor: Fix error returned when a path lookup is disconnected
KEYS: testing wrong bit for KEY_FLAG_REVOKED
TOMOYO: Fix mount flags checking order.
security: fix ima kconfig warning
AppArmor: Fix the error case for chroot relative path name lookup
AppArmor: fix mapping of META_READ to audit and quiet flags
AppArmor: Fix underflow in xindex calculation
AppArmor: Fix dropping of allowed operations that are force audited
AppArmor: Add mising end of structure test to caps unpacking
...
Diffstat (limited to 'security/apparmor')
-rw-r--r-- | security/apparmor/Makefile | 27 | ||||
-rw-r--r-- | security/apparmor/apparmorfs.c | 195 | ||||
-rw-r--r-- | security/apparmor/audit.c | 7 | ||||
-rw-r--r-- | security/apparmor/domain.c | 5 | ||||
-rw-r--r-- | security/apparmor/file.c | 21 | ||||
-rw-r--r-- | security/apparmor/include/apparmor.h | 15 | ||||
-rw-r--r-- | security/apparmor/include/apparmorfs.h | 44 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 9 | ||||
-rw-r--r-- | security/apparmor/include/file.h | 2 | ||||
-rw-r--r-- | security/apparmor/include/match.h | 3 | ||||
-rw-r--r-- | security/apparmor/include/path.h | 3 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 15 | ||||
-rw-r--r-- | security/apparmor/include/resource.h | 4 | ||||
-rw-r--r-- | security/apparmor/match.c | 80 | ||||
-rw-r--r-- | security/apparmor/path.c | 56 | ||||
-rw-r--r-- | security/apparmor/policy.c | 3 | ||||
-rw-r--r-- | security/apparmor/policy_unpack.c | 31 | ||||
-rw-r--r-- | security/apparmor/resource.c | 5 |
18 files changed, 419 insertions, 106 deletions
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index 2dafe50a2e25..806bd19af7f2 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", |
17 | quiet_cmd_make-caps = GEN $@ | 17 | quiet_cmd_make-caps = GEN $@ |
18 | cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\ | 18 | cmd_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 "};" >> $@ |
@@ -28,25 +28,38 @@ cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\ | |||
28 | # [RLIMIT_STACK] = "stack", | 28 | # [RLIMIT_STACK] = "stack", |
29 | # | 29 | # |
30 | # and build a second integer table (with the second sed cmd), that maps | 30 | # and build a second integer table (with the second sed cmd), that maps |
31 | # RLIMIT defines to the order defined in asm-generic/resource.h Thi is | 31 | # RLIMIT defines to the order defined in asm-generic/resource.h This is |
32 | # required by policy load to map policy ordering of RLIMITs to internal | 32 | # required by policy load to map policy ordering of RLIMITs to internal |
33 | # ordering for architectures that redefine an RLIMIT. | 33 | # ordering for architectures that redefine an RLIMIT. |
34 | # Transforms lines from | 34 | # Transforms lines from |
35 | # #define RLIMIT_STACK 3 /* max stack size */ | 35 | # #define RLIMIT_STACK 3 /* max stack size */ |
36 | # to | 36 | # to |
37 | # RLIMIT_STACK, | 37 | # RLIMIT_STACK, |
38 | # | ||
39 | # and build the securityfs entries for the mapping. | ||
40 | # Transforms lines from | ||
41 | # #define RLIMIT_FSIZE 1 /* Maximum filesize */ | ||
42 | # #define RLIMIT_STACK 3 /* max stack size */ | ||
43 | # to | ||
44 | # #define AA_FS_RLIMIT_MASK "fsize stack" | ||
38 | quiet_cmd_make-rlim = GEN $@ | 45 | quiet_cmd_make-rlim = GEN $@ |
39 | cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\ | 46 | cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ |
47 | > $@ ;\ | ||
40 | sed $< >> $@ -r -n \ | 48 | sed $< >> $@ -r -n \ |
41 | -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';\ |
42 | echo "};" >> $@ ;\ | 50 | echo "};" >> $@ ;\ |
43 | echo "static const int rlim_map[] = {" >> $@ ;\ | 51 | echo "static const int rlim_map[RLIM_NLIMITS] = {" >> $@ ;\ |
44 | sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\ | 52 | sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\ |
45 | echo "};" >> $@ | 53 | echo "};" >> $@ ; \ |
54 | echo -n '\#define AA_FS_RLIMIT_MASK "' >> $@ ;\ | ||
55 | sed -r -n 's/^\# ?define[ \t]+RLIMIT_([A-Z0-9_]+).*/\L\1/p' $< | \ | ||
56 | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ | ||
46 | 57 | ||
47 | $(obj)/capability.o : $(obj)/capability_names.h | 58 | $(obj)/capability.o : $(obj)/capability_names.h |
48 | $(obj)/resource.o : $(obj)/rlim_names.h | 59 | $(obj)/resource.o : $(obj)/rlim_names.h |
49 | $(obj)/capability_names.h : $(srctree)/include/linux/capability.h | 60 | $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \ |
61 | $(src)/Makefile | ||
50 | $(call cmd,make-caps) | 62 | $(call cmd,make-caps) |
51 | $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h | 63 | $(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \ |
64 | $(src)/Makefile | ||
52 | $(call cmd,make-rlim) | 65 | $(call cmd,make-rlim) |
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index e39df6d43779..16c15ec6f670 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c | |||
@@ -18,12 +18,14 @@ | |||
18 | #include <linux/seq_file.h> | 18 | #include <linux/seq_file.h> |
19 | #include <linux/uaccess.h> | 19 | #include <linux/uaccess.h> |
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/capability.h> | ||
21 | 22 | ||
22 | #include "include/apparmor.h" | 23 | #include "include/apparmor.h" |
23 | #include "include/apparmorfs.h" | 24 | #include "include/apparmorfs.h" |
24 | #include "include/audit.h" | 25 | #include "include/audit.h" |
25 | #include "include/context.h" | 26 | #include "include/context.h" |
26 | #include "include/policy.h" | 27 | #include "include/policy.h" |
28 | #include "include/resource.h" | ||
27 | 29 | ||
28 | /** | 30 | /** |
29 | * aa_simple_write_to_buffer - common routine for getting policy from user | 31 | * aa_simple_write_to_buffer - common routine for getting policy from user |
@@ -142,38 +144,166 @@ static const struct file_operations aa_fs_profile_remove = { | |||
142 | .llseek = default_llseek, | 144 | .llseek = default_llseek, |
143 | }; | 145 | }; |
144 | 146 | ||
145 | /** Base file system setup **/ | 147 | static int aa_fs_seq_show(struct seq_file *seq, void *v) |
148 | { | ||
149 | struct aa_fs_entry *fs_file = seq->private; | ||
150 | |||
151 | if (!fs_file) | ||
152 | return 0; | ||
146 | 153 | ||
147 | static struct dentry *aa_fs_dentry __initdata; | 154 | switch (fs_file->v_type) { |
155 | case AA_FS_TYPE_BOOLEAN: | ||
156 | seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no"); | ||
157 | break; | ||
158 | case AA_FS_TYPE_STRING: | ||
159 | seq_printf(seq, "%s\n", fs_file->v.string); | ||
160 | break; | ||
161 | case AA_FS_TYPE_U64: | ||
162 | seq_printf(seq, "%#08lx\n", fs_file->v.u64); | ||
163 | break; | ||
164 | default: | ||
165 | /* Ignore unpritable entry types. */ | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
148 | 171 | ||
149 | static void __init aafs_remove(const char *name) | 172 | static int aa_fs_seq_open(struct inode *inode, struct file *file) |
150 | { | 173 | { |
151 | struct dentry *dentry; | 174 | return single_open(file, aa_fs_seq_show, inode->i_private); |
175 | } | ||
176 | |||
177 | const struct file_operations aa_fs_seq_file_ops = { | ||
178 | .owner = THIS_MODULE, | ||
179 | .open = aa_fs_seq_open, | ||
180 | .read = seq_read, | ||
181 | .llseek = seq_lseek, | ||
182 | .release = single_release, | ||
183 | }; | ||
184 | |||
185 | /** Base file system setup **/ | ||
186 | |||
187 | static struct aa_fs_entry aa_fs_entry_file[] = { | ||
188 | AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \ | ||
189 | "link lock"), | ||
190 | { } | ||
191 | }; | ||
152 | 192 | ||
153 | dentry = lookup_one_len(name, aa_fs_dentry, strlen(name)); | 193 | static struct aa_fs_entry aa_fs_entry_domain[] = { |
154 | if (!IS_ERR(dentry)) { | 194 | AA_FS_FILE_BOOLEAN("change_hat", 1), |
155 | securityfs_remove(dentry); | 195 | AA_FS_FILE_BOOLEAN("change_hatv", 1), |
156 | dput(dentry); | 196 | AA_FS_FILE_BOOLEAN("change_onexec", 1), |
197 | AA_FS_FILE_BOOLEAN("change_profile", 1), | ||
198 | { } | ||
199 | }; | ||
200 | |||
201 | static struct aa_fs_entry aa_fs_entry_features[] = { | ||
202 | AA_FS_DIR("domain", aa_fs_entry_domain), | ||
203 | AA_FS_DIR("file", aa_fs_entry_file), | ||
204 | AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), | ||
205 | AA_FS_DIR("rlimit", aa_fs_entry_rlimit), | ||
206 | { } | ||
207 | }; | ||
208 | |||
209 | static struct aa_fs_entry aa_fs_entry_apparmor[] = { | ||
210 | AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), | ||
211 | AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), | ||
212 | AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), | ||
213 | AA_FS_DIR("features", aa_fs_entry_features), | ||
214 | { } | ||
215 | }; | ||
216 | |||
217 | static struct aa_fs_entry aa_fs_entry = | ||
218 | AA_FS_DIR("apparmor", aa_fs_entry_apparmor); | ||
219 | |||
220 | /** | ||
221 | * aafs_create_file - create a file entry in the apparmor securityfs | ||
222 | * @fs_file: aa_fs_entry to build an entry for (NOT NULL) | ||
223 | * @parent: the parent dentry in the securityfs | ||
224 | * | ||
225 | * Use aafs_remove_file to remove entries created with this fn. | ||
226 | */ | ||
227 | static int __init aafs_create_file(struct aa_fs_entry *fs_file, | ||
228 | struct dentry *parent) | ||
229 | { | ||
230 | int error = 0; | ||
231 | |||
232 | fs_file->dentry = securityfs_create_file(fs_file->name, | ||
233 | S_IFREG | fs_file->mode, | ||
234 | parent, fs_file, | ||
235 | fs_file->file_ops); | ||
236 | if (IS_ERR(fs_file->dentry)) { | ||
237 | error = PTR_ERR(fs_file->dentry); | ||
238 | fs_file->dentry = NULL; | ||
157 | } | 239 | } |
240 | return error; | ||
158 | } | 241 | } |
159 | 242 | ||
160 | /** | 243 | /** |
161 | * aafs_create - create an entry in the apparmor filesystem | 244 | * aafs_create_dir - recursively create a directory entry in the securityfs |
162 | * @name: name of the entry (NOT NULL) | 245 | * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL) |
163 | * @mask: file permission mask of the file | 246 | * @parent: the parent dentry in the securityfs |
164 | * @fops: file operations for the file (NOT NULL) | ||
165 | * | 247 | * |
166 | * Used aafs_remove to remove entries created with this fn. | 248 | * Use aafs_remove_dir to remove entries created with this fn. |
167 | */ | 249 | */ |
168 | static int __init aafs_create(const char *name, umode_t mask, | 250 | static int __init aafs_create_dir(struct aa_fs_entry *fs_dir, |
169 | const struct file_operations *fops) | 251 | struct dentry *parent) |
170 | { | 252 | { |
171 | struct dentry *dentry; | 253 | int error; |
254 | struct aa_fs_entry *fs_file; | ||
172 | 255 | ||
173 | dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry, | 256 | fs_dir->dentry = securityfs_create_dir(fs_dir->name, parent); |
174 | NULL, fops); | 257 | if (IS_ERR(fs_dir->dentry)) { |
258 | error = PTR_ERR(fs_dir->dentry); | ||
259 | fs_dir->dentry = NULL; | ||
260 | goto failed; | ||
261 | } | ||
175 | 262 | ||
176 | return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; | 263 | for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { |
264 | if (fs_file->v_type == AA_FS_TYPE_DIR) | ||
265 | error = aafs_create_dir(fs_file, fs_dir->dentry); | ||
266 | else | ||
267 | error = aafs_create_file(fs_file, fs_dir->dentry); | ||
268 | if (error) | ||
269 | goto failed; | ||
270 | } | ||
271 | |||
272 | return 0; | ||
273 | |||
274 | failed: | ||
275 | return error; | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * aafs_remove_file - drop a single file entry in the apparmor securityfs | ||
280 | * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL) | ||
281 | */ | ||
282 | static void __init aafs_remove_file(struct aa_fs_entry *fs_file) | ||
283 | { | ||
284 | if (!fs_file->dentry) | ||
285 | return; | ||
286 | |||
287 | securityfs_remove(fs_file->dentry); | ||
288 | fs_file->dentry = NULL; | ||
289 | } | ||
290 | |||
291 | /** | ||
292 | * aafs_remove_dir - recursively drop a directory entry from the securityfs | ||
293 | * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL) | ||
294 | */ | ||
295 | static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir) | ||
296 | { | ||
297 | struct aa_fs_entry *fs_file; | ||
298 | |||
299 | for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { | ||
300 | if (fs_file->v_type == AA_FS_TYPE_DIR) | ||
301 | aafs_remove_dir(fs_file); | ||
302 | else | ||
303 | aafs_remove_file(fs_file); | ||
304 | } | ||
305 | |||
306 | aafs_remove_file(fs_dir); | ||
177 | } | 307 | } |
178 | 308 | ||
179 | /** | 309 | /** |
@@ -183,14 +313,7 @@ static int __init aafs_create(const char *name, umode_t mask, | |||
183 | */ | 313 | */ |
184 | void __init aa_destroy_aafs(void) | 314 | void __init aa_destroy_aafs(void) |
185 | { | 315 | { |
186 | if (aa_fs_dentry) { | 316 | aafs_remove_dir(&aa_fs_entry); |
187 | aafs_remove(".remove"); | ||
188 | aafs_remove(".replace"); | ||
189 | aafs_remove(".load"); | ||
190 | |||
191 | securityfs_remove(aa_fs_dentry); | ||
192 | aa_fs_dentry = NULL; | ||
193 | } | ||
194 | } | 317 | } |
195 | 318 | ||
196 | /** | 319 | /** |
@@ -207,25 +330,13 @@ static int __init aa_create_aafs(void) | |||
207 | if (!apparmor_initialized) | 330 | if (!apparmor_initialized) |
208 | return 0; | 331 | return 0; |
209 | 332 | ||
210 | if (aa_fs_dentry) { | 333 | if (aa_fs_entry.dentry) { |
211 | AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); | 334 | AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); |
212 | return -EEXIST; | 335 | return -EEXIST; |
213 | } | 336 | } |
214 | 337 | ||
215 | aa_fs_dentry = securityfs_create_dir("apparmor", NULL); | 338 | /* Populate fs tree. */ |
216 | if (IS_ERR(aa_fs_dentry)) { | 339 | error = aafs_create_dir(&aa_fs_entry, NULL); |
217 | error = PTR_ERR(aa_fs_dentry); | ||
218 | aa_fs_dentry = NULL; | ||
219 | goto error; | ||
220 | } | ||
221 | |||
222 | error = aafs_create(".load", 0640, &aa_fs_profile_load); | ||
223 | if (error) | ||
224 | goto error; | ||
225 | error = aafs_create(".replace", 0640, &aa_fs_profile_replace); | ||
226 | if (error) | ||
227 | goto error; | ||
228 | error = aafs_create(".remove", 0640, &aa_fs_profile_remove); | ||
229 | if (error) | 340 | if (error) |
230 | goto error; | 341 | goto error; |
231 | 342 | ||
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index f3fafedd798a..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 | ||
22 | const char *op_table[] = { | 22 | const 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 | ||
76 | const char *audit_mode_names[] = { | 76 | const 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 | ||
84 | static char *aa_audit_type[] = { | 84 | static const char *const aa_audit_type[] = { |
85 | "AUDIT", | 85 | "AUDIT", |
86 | "ALLOWED", | 86 | "ALLOWED", |
87 | "DENIED", | 87 | "DENIED", |
@@ -89,6 +89,7 @@ static char *aa_audit_type[] = { | |||
89 | "STATUS", | 89 | "STATUS", |
90 | "ERROR", | 90 | "ERROR", |
91 | "KILLED" | 91 | "KILLED" |
92 | "AUTO" | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | /* | 95 | /* |
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 7312db741219..3022c0f4f0db 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c | |||
@@ -173,8 +173,6 @@ static u32 map_old_perms(u32 old) | |||
173 | if (old & 0x40) /* AA_EXEC_MMAP */ | 173 | if (old & 0x40) /* AA_EXEC_MMAP */ |
174 | new |= AA_EXEC_MMAP; | 174 | new |= AA_EXEC_MMAP; |
175 | 175 | ||
176 | new |= AA_MAY_META_READ; | ||
177 | |||
178 | return new; | 176 | return new; |
179 | } | 177 | } |
180 | 178 | ||
@@ -212,6 +210,7 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state, | |||
212 | perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); | 210 | perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); |
213 | perms.xindex = dfa_other_xindex(dfa, state); | 211 | perms.xindex = dfa_other_xindex(dfa, state); |
214 | } | 212 | } |
213 | perms.allow |= AA_MAY_META_READ; | ||
215 | 214 | ||
216 | /* change_profile wasn't determined by ownership in old mapping */ | 215 | /* change_profile wasn't determined by ownership in old mapping */ |
217 | if (ACCEPT_TABLE(dfa)[state] & 0x80000000) | 216 | if (ACCEPT_TABLE(dfa)[state] & 0x80000000) |
@@ -279,22 +278,16 @@ int aa_path_perm(int op, struct aa_profile *profile, struct path *path, | |||
279 | int error; | 278 | int error; |
280 | 279 | ||
281 | 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); |
282 | error = aa_get_name(path, flags, &buffer, &name); | 281 | error = aa_path_name(path, flags, &buffer, &name, &info); |
283 | if (error) { | 282 | if (error) { |
284 | if (error == -ENOENT && is_deleted(path->dentry)) { | 283 | if (error == -ENOENT && is_deleted(path->dentry)) { |
285 | /* Access to open files that are deleted are | 284 | /* Access to open files that are deleted are |
286 | * give a pass (implicit delegation) | 285 | * give a pass (implicit delegation) |
287 | */ | 286 | */ |
288 | error = 0; | 287 | error = 0; |
288 | info = NULL; | ||
289 | perms.allow = request; | 289 | perms.allow = request; |
290 | } else if (error == -ENOENT) | 290 | } |
291 | info = "Failed name lookup - deleted entry"; | ||
292 | else if (error == -ESTALE) | ||
293 | info = "Failed name lookup - disconnected path"; | ||
294 | else if (error == -ENAMETOOLONG) | ||
295 | info = "Failed name lookup - name too long"; | ||
296 | else | ||
297 | info = "Failed name lookup"; | ||
298 | } else { | 291 | } else { |
299 | aa_str_perms(profile->file.dfa, profile->file.start, name, cond, | 292 | aa_str_perms(profile->file.dfa, profile->file.start, name, cond, |
300 | &perms); | 293 | &perms); |
@@ -365,12 +358,14 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, | |||
365 | lperms = nullperms; | 358 | lperms = nullperms; |
366 | 359 | ||
367 | /* buffer freed below, lname is pointer in buffer */ | 360 | /* buffer freed below, lname is pointer in buffer */ |
368 | error = aa_get_name(&link, profile->path_flags, &buffer, &lname); | 361 | error = aa_path_name(&link, profile->path_flags, &buffer, &lname, |
362 | &info); | ||
369 | if (error) | 363 | if (error) |
370 | goto audit; | 364 | goto audit; |
371 | 365 | ||
372 | /* buffer2 freed below, tname is pointer in buffer2 */ | 366 | /* buffer2 freed below, tname is pointer in buffer2 */ |
373 | error = aa_get_name(&target, profile->path_flags, &buffer2, &tname); | 367 | error = aa_path_name(&target, profile->path_flags, &buffer2, &tname, |
368 | &info); | ||
374 | if (error) | 369 | if (error) |
375 | goto audit; | 370 | goto audit; |
376 | 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 */ |
23 | extern enum audit_mode aa_g_audit; | 36 | extern enum audit_mode aa_g_audit; |
24 | extern bool aa_g_audit_header; | 37 | extern 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 | ||
87 | static inline bool mediated_filesystem(struct inode *inode) | 100 | static inline bool mediated_filesystem(struct inode *inode) |
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index cb1e93a114d7..7ea4769fab3f 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h | |||
@@ -15,6 +15,50 @@ | |||
15 | #ifndef __AA_APPARMORFS_H | 15 | #ifndef __AA_APPARMORFS_H |
16 | #define __AA_APPARMORFS_H | 16 | #define __AA_APPARMORFS_H |
17 | 17 | ||
18 | enum aa_fs_type { | ||
19 | AA_FS_TYPE_BOOLEAN, | ||
20 | AA_FS_TYPE_STRING, | ||
21 | AA_FS_TYPE_U64, | ||
22 | AA_FS_TYPE_FOPS, | ||
23 | AA_FS_TYPE_DIR, | ||
24 | }; | ||
25 | |||
26 | struct aa_fs_entry; | ||
27 | |||
28 | struct aa_fs_entry { | ||
29 | const char *name; | ||
30 | struct dentry *dentry; | ||
31 | umode_t mode; | ||
32 | enum aa_fs_type v_type; | ||
33 | union { | ||
34 | bool boolean; | ||
35 | char *string; | ||
36 | unsigned long u64; | ||
37 | struct aa_fs_entry *files; | ||
38 | } v; | ||
39 | const struct file_operations *file_ops; | ||
40 | }; | ||
41 | |||
42 | extern const struct file_operations aa_fs_seq_file_ops; | ||
43 | |||
44 | #define AA_FS_FILE_BOOLEAN(_name, _value) \ | ||
45 | { .name = (_name), .mode = 0444, \ | ||
46 | .v_type = AA_FS_TYPE_BOOLEAN, .v.boolean = (_value), \ | ||
47 | .file_ops = &aa_fs_seq_file_ops } | ||
48 | #define AA_FS_FILE_STRING(_name, _value) \ | ||
49 | { .name = (_name), .mode = 0444, \ | ||
50 | .v_type = AA_FS_TYPE_STRING, .v.string = (_value), \ | ||
51 | .file_ops = &aa_fs_seq_file_ops } | ||
52 | #define AA_FS_FILE_U64(_name, _value) \ | ||
53 | { .name = (_name), .mode = 0444, \ | ||
54 | .v_type = AA_FS_TYPE_U64, .v.u64 = (_value), \ | ||
55 | .file_ops = &aa_fs_seq_file_ops } | ||
56 | #define AA_FS_FILE_FOPS(_name, _mode, _fops) \ | ||
57 | { .name = (_name), .v_type = AA_FS_TYPE_FOPS, \ | ||
58 | .mode = (_mode), .file_ops = (_fops) } | ||
59 | #define AA_FS_DIR(_name, _value) \ | ||
60 | { .name = (_name), .v_type = AA_FS_TYPE_DIR, .v.files = (_value) } | ||
61 | |||
18 | extern void __init aa_destroy_aafs(void); | 62 | extern void __init aa_destroy_aafs(void); |
19 | 63 | ||
20 | #endif /* __AA_APPARMORFS_H */ | 64 | #endif /* __AA_APPARMORFS_H */ |
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 1951786d32e9..4ba78c203af1 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h | |||
@@ -25,11 +25,9 @@ | |||
25 | 25 | ||
26 | struct aa_profile; | 26 | struct aa_profile; |
27 | 27 | ||
28 | extern const char *audit_mode_names[]; | 28 | extern const char *const audit_mode_names[]; |
29 | #define AUDIT_MAX_INDEX 5 | 29 | #define AUDIT_MAX_INDEX 5 |
30 | 30 | ||
31 | #define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */ | ||
32 | |||
33 | enum audit_mode { | 31 | enum audit_mode { |
34 | AUDIT_NORMAL, /* follow normal auditing of accesses */ | 32 | AUDIT_NORMAL, /* follow normal auditing of accesses */ |
35 | AUDIT_QUIET_DENIED, /* quiet all denied access messages */ | 33 | AUDIT_QUIET_DENIED, /* quiet all denied access messages */ |
@@ -45,10 +43,11 @@ enum audit_type { | |||
45 | AUDIT_APPARMOR_HINT, | 43 | AUDIT_APPARMOR_HINT, |
46 | AUDIT_APPARMOR_STATUS, | 44 | AUDIT_APPARMOR_STATUS, |
47 | AUDIT_APPARMOR_ERROR, | 45 | AUDIT_APPARMOR_ERROR, |
48 | AUDIT_APPARMOR_KILL | 46 | AUDIT_APPARMOR_KILL, |
47 | AUDIT_APPARMOR_AUTO | ||
49 | }; | 48 | }; |
50 | 49 | ||
51 | extern const char *op_table[]; | 50 | extern const char *const op_table[]; |
52 | enum aa_ops { | 51 | enum aa_ops { |
53 | OP_NULL, | 52 | OP_NULL, |
54 | 53 | ||
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index ab8c6d87f758..f98fd4701d80 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h | |||
@@ -117,7 +117,7 @@ static inline u16 dfa_map_xindex(u16 mask) | |||
117 | index |= AA_X_NAME; | 117 | index |= AA_X_NAME; |
118 | } else if (old_index == 3) { | 118 | } else if (old_index == 3) { |
119 | index |= AA_X_NAME | AA_X_CHILD; | 119 | index |= AA_X_NAME | AA_X_CHILD; |
120 | } else { | 120 | } else if (old_index) { |
121 | index |= AA_X_TABLE; | 121 | index |= AA_X_TABLE; |
122 | index |= old_index - 4; | 122 | index |= old_index - 4; |
123 | } | 123 | } |
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); |
117 | unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, | 117 | unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, |
118 | const char *str); | 118 | const char *str); |
119 | unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, | ||
120 | const char c); | ||
121 | |||
119 | void aa_dfa_free_kref(struct kref *kref); | 122 | void 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 | ||
29 | int aa_get_name(struct path *path, int flags, char **buffer, const char **name); | 29 | int 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 | ||
32 | extern const char *profile_mode_names[]; | 32 | extern 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 | */ | ||
136 | struct 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/include/resource.h b/security/apparmor/include/resource.h index 02baec732bb5..d3f4cf027957 100644 --- a/security/apparmor/include/resource.h +++ b/security/apparmor/include/resource.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/resource.h> | 18 | #include <linux/resource.h> |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | 20 | ||
21 | #include "apparmorfs.h" | ||
22 | |||
21 | struct aa_profile; | 23 | struct aa_profile; |
22 | 24 | ||
23 | /* struct aa_rlimit - rlimit settings for the profile | 25 | /* struct aa_rlimit - rlimit settings for the profile |
@@ -32,6 +34,8 @@ struct aa_rlimit { | |||
32 | struct rlimit limits[RLIM_NLIMITS]; | 34 | struct rlimit limits[RLIM_NLIMITS]; |
33 | }; | 35 | }; |
34 | 36 | ||
37 | extern struct aa_fs_entry aa_fs_entry_rlimit[]; | ||
38 | |||
35 | int aa_map_resource(int resource); | 39 | int aa_map_resource(int resource); |
36 | int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, | 40 | int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, |
37 | unsigned int resource, struct rlimit *new_rlim); | 41 | unsigned int resource, struct rlimit *new_rlim); |
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, | |||
349 | unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, | 349 | unsigned 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 | */ | ||
397 | unsigned 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 9d070a7c3ffc..2daeea4f9266 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c | |||
@@ -83,31 +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 { |
88 | res = d_absolute_path(path, buf, buflen); | ||
89 | if (!our_mnt(path->mnt)) | ||
90 | connected = 0; | ||
94 | } | 91 | } |
95 | 92 | ||
96 | res = d_absolute_path(path, buf, buflen); | ||
97 | |||
98 | *name = res; | ||
99 | /* handle error conditions - and still allow a partial path to | 93 | /* handle error conditions - and still allow a partial path to |
100 | * be returned. | 94 | * be returned. |
101 | */ | 95 | */ |
102 | if (IS_ERR(res)) { | 96 | if (!res || IS_ERR(res)) { |
103 | error = PTR_ERR(res); | ||
104 | *name = buf; | ||
105 | goto out; | ||
106 | } | ||
107 | if (!our_mnt(path->mnt)) | ||
108 | 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; | ||
109 | 108 | ||
110 | ok: | ||
111 | /* Handle two cases: | 109 | /* Handle two cases: |
112 | * 1. A deleted dentry && profile is not allowing mediation of deleted | 110 | * 1. A deleted dentry && profile is not allowing mediation of deleted |
113 | * 2. On some filesystems, newly allocated dentries appear to the | 111 | * 2. On some filesystems, newly allocated dentries appear to the |
@@ -138,7 +136,7 @@ ok: | |||
138 | /* disconnected path, don't return pathname starting | 136 | /* disconnected path, don't return pathname starting |
139 | * with '/' | 137 | * with '/' |
140 | */ | 138 | */ |
141 | error = -ESTALE; | 139 | error = -EACCES; |
142 | if (*res == '/') | 140 | if (*res == '/') |
143 | *name = res + 1; | 141 | *name = res + 1; |
144 | } | 142 | } |
@@ -159,7 +157,7 @@ out: | |||
159 | * Returns: %0 else error on failure | 157 | * Returns: %0 else error on failure |
160 | */ | 158 | */ |
161 | static int get_name_to_buffer(struct path *path, int flags, char *buffer, | 159 | static int get_name_to_buffer(struct path *path, int flags, char *buffer, |
162 | int size, char **name) | 160 | int size, char **name, const char **info) |
163 | { | 161 | { |
164 | int adjust = (flags & PATH_IS_DIR) ? 1 : 0; | 162 | int adjust = (flags & PATH_IS_DIR) ? 1 : 0; |
165 | int error = d_namespace_path(path, buffer, size - adjust, name, flags); | 163 | int error = d_namespace_path(path, buffer, size - adjust, name, flags); |
@@ -171,15 +169,27 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, | |||
171 | */ | 169 | */ |
172 | strcpy(&buffer[size - 2], "/"); | 170 | strcpy(&buffer[size - 2], "/"); |
173 | 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 | |||
174 | return error; | 183 | return error; |
175 | } | 184 | } |
176 | 185 | ||
177 | /** | 186 | /** |
178 | * aa_get_name - compute the pathname of a file | 187 | * aa_path_name - compute the pathname of a file |
179 | * @path: path the file (NOT NULL) | 188 | * @path: path the file (NOT NULL) |
180 | * @flags: flags controlling path name generation | 189 | * @flags: flags controlling path name generation |
181 | * @buffer: buffer that aa_get_name() allocated (NOT NULL) | 190 | * @buffer: buffer that aa_get_name() allocated (NOT NULL) |
182 | * @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) | ||
183 | * | 193 | * |
184 | * @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 |
185 | * 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 |
@@ -192,7 +202,8 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, | |||
192 | * | 202 | * |
193 | * Returns: %0 else error code if could retrieve name | 203 | * Returns: %0 else error code if could retrieve name |
194 | */ | 204 | */ |
195 | int aa_get_name(struct path *path, int flags, char **buffer, const char **name) | 205 | int aa_path_name(struct path *path, int flags, char **buffer, const char **name, |
206 | const char **info) | ||
196 | { | 207 | { |
197 | char *buf, *str = NULL; | 208 | char *buf, *str = NULL; |
198 | int size = 256; | 209 | int size = 256; |
@@ -206,7 +217,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name) | |||
206 | if (!buf) | 217 | if (!buf) |
207 | return -ENOMEM; | 218 | return -ENOMEM; |
208 | 219 | ||
209 | error = get_name_to_buffer(path, flags, buf, size, &str); | 220 | error = get_name_to_buffer(path, flags, buf, size, &str, info); |
210 | if (error != -ENAMETOOLONG) | 221 | if (error != -ENAMETOOLONG) |
211 | break; | 222 | break; |
212 | 223 | ||
@@ -214,6 +225,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name) | |||
214 | size <<= 1; | 225 | size <<= 1; |
215 | if (size > aa_g_path_max) | 226 | if (size > aa_g_path_max) |
216 | return -ENAMETOOLONG; | 227 | return -ENAMETOOLONG; |
228 | *info = NULL; | ||
217 | } | 229 | } |
218 | *buffer = buf; | 230 | *buffer = buf; |
219 | *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 */ |
94 | struct aa_namespace *root_ns; | 94 | struct aa_namespace *root_ns; |
95 | 95 | ||
96 | const char *profile_mode_names[] = { | 96 | const 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 741dd13e089b..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 | ||
@@ -554,11 +555,35 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) | |||
554 | goto fail; | 555 | goto fail; |
555 | if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL)) | 556 | if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL)) |
556 | goto fail; | 557 | goto fail; |
558 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) | ||
559 | goto fail; | ||
557 | } | 560 | } |
558 | 561 | ||
559 | if (!unpack_rlimits(e, profile)) | 562 | if (!unpack_rlimits(e, profile)) |
560 | goto fail; | 563 | goto fail; |
561 | 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 | |||
562 | /* get file rules */ | 587 | /* get file rules */ |
563 | profile->file.dfa = unpack_dfa(e); | 588 | profile->file.dfa = unpack_dfa(e); |
564 | if (IS_ERR(profile->file.dfa)) { | 589 | if (IS_ERR(profile->file.dfa)) { |
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index a4136c10b1c6..72c25a4f2cfd 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c | |||
@@ -23,6 +23,11 @@ | |||
23 | */ | 23 | */ |
24 | #include "rlim_names.h" | 24 | #include "rlim_names.h" |
25 | 25 | ||
26 | struct aa_fs_entry aa_fs_entry_rlimit[] = { | ||
27 | AA_FS_FILE_STRING("mask", AA_FS_RLIMIT_MASK), | ||
28 | { } | ||
29 | }; | ||
30 | |||
26 | /* audit callback for resource specific fields */ | 31 | /* audit callback for resource specific fields */ |
27 | static void audit_cb(struct audit_buffer *ab, void *va) | 32 | static void audit_cb(struct audit_buffer *ab, void *va) |
28 | { | 33 | { |