aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig6
-rw-r--r--security/Makefile2
-rw-r--r--security/apparmor/Makefile27
-rw-r--r--security/apparmor/apparmorfs.c195
-rw-r--r--security/apparmor/audit.c7
-rw-r--r--security/apparmor/domain.c5
-rw-r--r--security/apparmor/file.c21
-rw-r--r--security/apparmor/include/apparmor.h15
-rw-r--r--security/apparmor/include/apparmorfs.h44
-rw-r--r--security/apparmor/include/audit.h9
-rw-r--r--security/apparmor/include/file.h2
-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/include/resource.h4
-rw-r--r--security/apparmor/match.c80
-rw-r--r--security/apparmor/path.c56
-rw-r--r--security/apparmor/policy.c3
-rw-r--r--security/apparmor/policy_unpack.c31
-rw-r--r--security/apparmor/resource.c5
-rw-r--r--security/capability.c5
-rw-r--r--security/commoncap.c1
-rw-r--r--security/integrity/ima/Kconfig4
-rw-r--r--security/integrity/ima/ima_audit.c2
-rw-r--r--security/integrity/ima/ima_policy.c3
-rw-r--r--security/keys/keyctl.c15
-rw-r--r--security/keys/process_keys.c3
-rw-r--r--security/security.c21
-rw-r--r--security/selinux/hooks.c2
-rw-r--r--security/smack/smack_lsm.c3
-rw-r--r--security/tomoyo/audit.c4
-rw-r--r--security/tomoyo/common.c63
-rw-r--r--security/tomoyo/common.h6
-rw-r--r--security/tomoyo/mount.c38
-rw-r--r--security/tomoyo/securityfs_if.c5
-rw-r--r--security/yama/Kconfig13
-rw-r--r--security/yama/Makefile3
-rw-r--r--security/yama/yama_lsm.c323
38 files changed, 856 insertions, 191 deletions
diff --git a/security/Kconfig b/security/Kconfig
index 51bd5a0b69ae..ccc61f8006b2 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -187,6 +187,7 @@ source security/selinux/Kconfig
187source security/smack/Kconfig 187source security/smack/Kconfig
188source security/tomoyo/Kconfig 188source security/tomoyo/Kconfig
189source security/apparmor/Kconfig 189source security/apparmor/Kconfig
190source security/yama/Kconfig
190 191
191source security/integrity/Kconfig 192source security/integrity/Kconfig
192 193
@@ -196,6 +197,7 @@ choice
196 default DEFAULT_SECURITY_SMACK if SECURITY_SMACK 197 default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
197 default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO 198 default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
198 default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR 199 default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
200 default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
199 default DEFAULT_SECURITY_DAC 201 default DEFAULT_SECURITY_DAC
200 202
201 help 203 help
@@ -214,6 +216,9 @@ choice
214 config DEFAULT_SECURITY_APPARMOR 216 config DEFAULT_SECURITY_APPARMOR
215 bool "AppArmor" if SECURITY_APPARMOR=y 217 bool "AppArmor" if SECURITY_APPARMOR=y
216 218
219 config DEFAULT_SECURITY_YAMA
220 bool "Yama" if SECURITY_YAMA=y
221
217 config DEFAULT_SECURITY_DAC 222 config DEFAULT_SECURITY_DAC
218 bool "Unix Discretionary Access Controls" 223 bool "Unix Discretionary Access Controls"
219 224
@@ -225,6 +230,7 @@ config DEFAULT_SECURITY
225 default "smack" if DEFAULT_SECURITY_SMACK 230 default "smack" if DEFAULT_SECURITY_SMACK
226 default "tomoyo" if DEFAULT_SECURITY_TOMOYO 231 default "tomoyo" if DEFAULT_SECURITY_TOMOYO
227 default "apparmor" if DEFAULT_SECURITY_APPARMOR 232 default "apparmor" if DEFAULT_SECURITY_APPARMOR
233 default "yama" if DEFAULT_SECURITY_YAMA
228 default "" if DEFAULT_SECURITY_DAC 234 default "" if DEFAULT_SECURITY_DAC
229 235
230endmenu 236endmenu
diff --git a/security/Makefile b/security/Makefile
index a5e502f8a05b..c26c81e92571 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX) += selinux
7subdir-$(CONFIG_SECURITY_SMACK) += smack 7subdir-$(CONFIG_SECURITY_SMACK) += smack
8subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo 8subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
9subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor 9subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
10subdir-$(CONFIG_SECURITY_YAMA) += yama
10 11
11# always enable default capabilities 12# always enable default capabilities
12obj-y += commoncap.o 13obj-y += commoncap.o
@@ -21,6 +22,7 @@ obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
21obj-$(CONFIG_AUDIT) += lsm_audit.o 22obj-$(CONFIG_AUDIT) += lsm_audit.o
22obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o 23obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
23obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o 24obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o
25obj-$(CONFIG_SECURITY_YAMA) += yama/built-in.o
24obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o 26obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
25 27
26# Object integrity file lists 28# Object integrity file lists
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",
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 "};" >> $@
@@ -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"
38quiet_cmd_make-rlim = GEN $@ 45quiet_cmd_make-rlim = GEN $@
39cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\ 46cmd_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 **/ 147static 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
147static 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
149static void __init aafs_remove(const char *name) 172static 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
177const 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
187static 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)); 193static 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
201static 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
209static 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
217static 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 */
227static 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 */
168static int __init aafs_create(const char *name, umode_t mask, 250static 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
274failed:
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 */
282static 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 */
295static 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 */
184void __init aa_destroy_aafs(void) 314void __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
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",
@@ -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 */
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/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
18enum 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
26struct aa_fs_entry;
27
28struct 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
42extern 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
18extern void __init aa_destroy_aafs(void); 62extern 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
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
31#define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */
32
33enum audit_mode { 31enum 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
51extern const char *op_table[]; 50extern const char *const op_table[];
52enum aa_ops { 51enum 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);
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/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
21struct aa_profile; 23struct 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
37extern struct aa_fs_entry aa_fs_entry_rlimit[];
38
35int aa_map_resource(int resource); 39int aa_map_resource(int resource);
36int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, 40int 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,
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 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
110ok:
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 */
161static 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,
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 */
195int 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)
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 */
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 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
26struct 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 */
27static void audit_cb(struct audit_buffer *ab, void *va) 32static void audit_cb(struct audit_buffer *ab, void *va)
28{ 33{
diff --git a/security/capability.c b/security/capability.c
index 2f680eb02b59..5bb21b1c448c 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -358,6 +358,10 @@ static int cap_task_create(unsigned long clone_flags)
358 return 0; 358 return 0;
359} 359}
360 360
361static void cap_task_free(struct task_struct *task)
362{
363}
364
361static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) 365static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp)
362{ 366{
363 return 0; 367 return 0;
@@ -954,6 +958,7 @@ void __init security_fixup_ops(struct security_operations *ops)
954 set_to_cap_if_null(ops, file_receive); 958 set_to_cap_if_null(ops, file_receive);
955 set_to_cap_if_null(ops, dentry_open); 959 set_to_cap_if_null(ops, dentry_open);
956 set_to_cap_if_null(ops, task_create); 960 set_to_cap_if_null(ops, task_create);
961 set_to_cap_if_null(ops, task_free);
957 set_to_cap_if_null(ops, cred_alloc_blank); 962 set_to_cap_if_null(ops, cred_alloc_blank);
958 set_to_cap_if_null(ops, cred_free); 963 set_to_cap_if_null(ops, cred_free);
959 set_to_cap_if_null(ops, cred_prepare); 964 set_to_cap_if_null(ops, cred_prepare);
diff --git a/security/commoncap.c b/security/commoncap.c
index 7ce191ea29a0..0cf4b53480a7 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -28,6 +28,7 @@
28#include <linux/prctl.h> 28#include <linux/prctl.h>
29#include <linux/securebits.h> 29#include <linux/securebits.h>
30#include <linux/user_namespace.h> 30#include <linux/user_namespace.h>
31#include <linux/binfmts.h>
31 32
32/* 33/*
33 * If a non-root user executes a setuid-root binary in 34 * If a non-root user executes a setuid-root binary in
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 4f554f20dc97..35664fe6daa1 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -9,8 +9,8 @@ config IMA
9 select CRYPTO_HMAC 9 select CRYPTO_HMAC
10 select CRYPTO_MD5 10 select CRYPTO_MD5
11 select CRYPTO_SHA1 11 select CRYPTO_SHA1
12 select TCG_TPM if !S390 && !UML 12 select TCG_TPM if HAS_IOMEM && !UML
13 select TCG_TIS if TCG_TPM 13 select TCG_TIS if TCG_TPM && X86
14 help 14 help
15 The Trusted Computing Group(TCG) runtime Integrity 15 The Trusted Computing Group(TCG) runtime Integrity
16 Measurement Architecture(IMA) maintains a list of hash 16 Measurement Architecture(IMA) maintains a list of hash
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c
index 2ad942fb1e23..21e96bf188df 100644
--- a/security/integrity/ima/ima_audit.c
+++ b/security/integrity/ima/ima_audit.c
@@ -61,6 +61,6 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
61 audit_log_untrustedstring(ab, inode->i_sb->s_id); 61 audit_log_untrustedstring(ab, inode->i_sb->s_id);
62 audit_log_format(ab, " ino=%lu", inode->i_ino); 62 audit_log_format(ab, " ino=%lu", inode->i_ino);
63 } 63 }
64 audit_log_format(ab, " res=%d", !result ? 0 : 1); 64 audit_log_format(ab, " res=%d", !result);
65 audit_log_end(ab); 65 audit_log_end(ab);
66} 66}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index d45061d02fee..d8edff209bf3 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -62,6 +62,7 @@ static struct ima_measure_rule_entry default_rules[] = {
62 {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, 62 {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
63 {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, 63 {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
64 {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, 64 {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
65 {.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC},
65 {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, 66 {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
66 {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, 67 {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
67 {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, 68 {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
@@ -417,7 +418,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
417 if (!result && (entry->action == UNKNOWN)) 418 if (!result && (entry->action == UNKNOWN))
418 result = -EINVAL; 419 result = -EINVAL;
419 420
420 audit_log_format(ab, "res=%d", !!result); 421 audit_log_format(ab, "res=%d", !result);
421 audit_log_end(ab); 422 audit_log_end(ab);
422 return result; 423 return result;
423} 424}
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 0b3f5d72af1c..6523599e9ac0 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -388,11 +388,24 @@ long keyctl_keyring_clear(key_serial_t ringid)
388 keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 388 keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
389 if (IS_ERR(keyring_ref)) { 389 if (IS_ERR(keyring_ref)) {
390 ret = PTR_ERR(keyring_ref); 390 ret = PTR_ERR(keyring_ref);
391
392 /* Root is permitted to invalidate certain special keyrings */
393 if (capable(CAP_SYS_ADMIN)) {
394 keyring_ref = lookup_user_key(ringid, 0, 0);
395 if (IS_ERR(keyring_ref))
396 goto error;
397 if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR,
398 &key_ref_to_ptr(keyring_ref)->flags))
399 goto clear;
400 goto error_put;
401 }
402
391 goto error; 403 goto error;
392 } 404 }
393 405
406clear:
394 ret = keyring_clear(key_ref_to_ptr(keyring_ref)); 407 ret = keyring_clear(key_ref_to_ptr(keyring_ref));
395 408error_put:
396 key_ref_put(keyring_ref); 409 key_ref_put(keyring_ref);
397error: 410error:
398 return ret; 411 return ret;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 1068cb1939b3..be7ecb2018dd 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -657,7 +657,8 @@ try_again:
657 goto error; 657 goto error;
658 658
659 down_read(&cred->request_key_auth->sem); 659 down_read(&cred->request_key_auth->sem);
660 if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) { 660 if (test_bit(KEY_FLAG_REVOKED,
661 &cred->request_key_auth->flags)) {
661 key_ref = ERR_PTR(-EKEYREVOKED); 662 key_ref = ERR_PTR(-EKEYREVOKED);
662 key = NULL; 663 key = NULL;
663 } else { 664 } else {
diff --git a/security/security.c b/security/security.c
index d7542493454d..bf619ffc9a4d 100644
--- a/security/security.c
+++ b/security/security.c
@@ -19,6 +19,8 @@
19#include <linux/integrity.h> 19#include <linux/integrity.h>
20#include <linux/ima.h> 20#include <linux/ima.h>
21#include <linux/evm.h> 21#include <linux/evm.h>
22#include <linux/fsnotify.h>
23#include <net/flow.h>
22 24
23#define MAX_LSM_EVM_XATTR 2 25#define MAX_LSM_EVM_XATTR 2
24 26
@@ -187,25 +189,11 @@ int security_settime(const struct timespec *ts, const struct timezone *tz)
187 return security_ops->settime(ts, tz); 189 return security_ops->settime(ts, tz);
188} 190}
189 191
190int security_vm_enough_memory(long pages)
191{
192 WARN_ON(current->mm == NULL);
193 return security_ops->vm_enough_memory(current->mm, pages);
194}
195
196int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) 192int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
197{ 193{
198 WARN_ON(mm == NULL);
199 return security_ops->vm_enough_memory(mm, pages); 194 return security_ops->vm_enough_memory(mm, pages);
200} 195}
201 196
202int security_vm_enough_memory_kern(long pages)
203{
204 /* If current->mm is a kernel thread then we will pass NULL,
205 for this specific case that is fine */
206 return security_ops->vm_enough_memory(current->mm, pages);
207}
208
209int security_bprm_set_creds(struct linux_binprm *bprm) 197int security_bprm_set_creds(struct linux_binprm *bprm)
210{ 198{
211 return security_ops->bprm_set_creds(bprm); 199 return security_ops->bprm_set_creds(bprm);
@@ -729,6 +717,11 @@ int security_task_create(unsigned long clone_flags)
729 return security_ops->task_create(clone_flags); 717 return security_ops->task_create(clone_flags);
730} 718}
731 719
720void security_task_free(struct task_struct *task)
721{
722 security_ops->task_free(task);
723}
724
732int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) 725int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
733{ 726{
734 return security_ops->cred_alloc_blank(cred, gfp); 727 return security_ops->cred_alloc_blank(cred, gfp);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6a3683e28426..304929909375 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -81,6 +81,8 @@
81#include <linux/syslog.h> 81#include <linux/syslog.h>
82#include <linux/user_namespace.h> 82#include <linux/user_namespace.h>
83#include <linux/export.h> 83#include <linux/export.h>
84#include <linux/msg.h>
85#include <linux/shm.h>
84 86
85#include "avc.h" 87#include "avc.h"
86#include "objsec.h" 88#include "objsec.h"
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index e8af5b0ba80f..cd667b4089a5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -36,6 +36,9 @@
36#include <linux/magic.h> 36#include <linux/magic.h>
37#include <linux/dcache.h> 37#include <linux/dcache.h>
38#include <linux/personality.h> 38#include <linux/personality.h>
39#include <linux/msg.h>
40#include <linux/shm.h>
41#include <linux/binfmts.h>
39#include "smack.h" 42#include "smack.h"
40 43
41#define task_security(task) (task_cred_xxx((task), security)) 44#define task_security(task) (task_cred_xxx((task), security))
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c
index 5ca47ea3049f..7ef9fa3e37e0 100644
--- a/security/tomoyo/audit.c
+++ b/security/tomoyo/audit.c
@@ -446,11 +446,11 @@ void tomoyo_read_log(struct tomoyo_io_buffer *head)
446 * tomoyo_poll_log - Wait for an audit log. 446 * tomoyo_poll_log - Wait for an audit log.
447 * 447 *
448 * @file: Pointer to "struct file". 448 * @file: Pointer to "struct file".
449 * @wait: Pointer to "poll_table". 449 * @wait: Pointer to "poll_table". Maybe NULL.
450 * 450 *
451 * Returns POLLIN | POLLRDNORM when ready to read an audit log. 451 * Returns POLLIN | POLLRDNORM when ready to read an audit log.
452 */ 452 */
453int tomoyo_poll_log(struct file *file, poll_table *wait) 453unsigned int tomoyo_poll_log(struct file *file, poll_table *wait)
454{ 454{
455 if (tomoyo_log_count) 455 if (tomoyo_log_count)
456 return POLLIN | POLLRDNORM; 456 return POLLIN | POLLRDNORM;
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index c47d3ce6c733..8656b16eef7b 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -1069,7 +1069,7 @@ static int tomoyo_write_task(struct tomoyo_acl_param *param)
1069 * 1069 *
1070 * @domainname: The name of domain. 1070 * @domainname: The name of domain.
1071 * 1071 *
1072 * Returns 0. 1072 * Returns 0 on success, negative value otherwise.
1073 * 1073 *
1074 * Caller holds tomoyo_read_lock(). 1074 * Caller holds tomoyo_read_lock().
1075 */ 1075 */
@@ -1081,7 +1081,7 @@ static int tomoyo_delete_domain(char *domainname)
1081 name.name = domainname; 1081 name.name = domainname;
1082 tomoyo_fill_path_info(&name); 1082 tomoyo_fill_path_info(&name);
1083 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 1083 if (mutex_lock_interruptible(&tomoyo_policy_lock))
1084 return 0; 1084 return -EINTR;
1085 /* Is there an active domain? */ 1085 /* Is there an active domain? */
1086 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 1086 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
1087 /* Never delete tomoyo_kernel_domain */ 1087 /* Never delete tomoyo_kernel_domain */
@@ -1164,15 +1164,16 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
1164 bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); 1164 bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
1165 unsigned int profile; 1165 unsigned int profile;
1166 if (*data == '<') { 1166 if (*data == '<') {
1167 int ret = 0;
1167 domain = NULL; 1168 domain = NULL;
1168 if (is_delete) 1169 if (is_delete)
1169 tomoyo_delete_domain(data); 1170 ret = tomoyo_delete_domain(data);
1170 else if (is_select) 1171 else if (is_select)
1171 domain = tomoyo_find_domain(data); 1172 domain = tomoyo_find_domain(data);
1172 else 1173 else
1173 domain = tomoyo_assign_domain(data, false); 1174 domain = tomoyo_assign_domain(data, false);
1174 head->w.domain = domain; 1175 head->w.domain = domain;
1175 return 0; 1176 return ret;
1176 } 1177 }
1177 if (!domain) 1178 if (!domain)
1178 return -EINVAL; 1179 return -EINVAL;
@@ -2111,7 +2112,7 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
2111 struct tomoyo_domain_info *domain = NULL; 2112 struct tomoyo_domain_info *domain = NULL;
2112 spin_lock(&tomoyo_query_list_lock); 2113 spin_lock(&tomoyo_query_list_lock);
2113 list_for_each_entry(ptr, &tomoyo_query_list, list) { 2114 list_for_each_entry(ptr, &tomoyo_query_list, list) {
2114 if (ptr->serial != serial || ptr->answer) 2115 if (ptr->serial != serial)
2115 continue; 2116 continue;
2116 domain = ptr->domain; 2117 domain = ptr->domain;
2117 break; 2118 break;
@@ -2130,28 +2131,13 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
2130 * 2131 *
2131 * Waits for access requests which violated policy in enforcing mode. 2132 * Waits for access requests which violated policy in enforcing mode.
2132 */ 2133 */
2133static int tomoyo_poll_query(struct file *file, poll_table *wait) 2134static unsigned int tomoyo_poll_query(struct file *file, poll_table *wait)
2134{ 2135{
2135 struct list_head *tmp; 2136 if (!list_empty(&tomoyo_query_list))
2136 bool found = false; 2137 return POLLIN | POLLRDNORM;
2137 u8 i; 2138 poll_wait(file, &tomoyo_query_wait, wait);
2138 for (i = 0; i < 2; i++) { 2139 if (!list_empty(&tomoyo_query_list))
2139 spin_lock(&tomoyo_query_list_lock); 2140 return POLLIN | POLLRDNORM;
2140 list_for_each(tmp, &tomoyo_query_list) {
2141 struct tomoyo_query *ptr =
2142 list_entry(tmp, typeof(*ptr), list);
2143 if (ptr->answer)
2144 continue;
2145 found = true;
2146 break;
2147 }
2148 spin_unlock(&tomoyo_query_list_lock);
2149 if (found)
2150 return POLLIN | POLLRDNORM;
2151 if (i)
2152 break;
2153 poll_wait(file, &tomoyo_query_wait, wait);
2154 }
2155 return 0; 2141 return 0;
2156} 2142}
2157 2143
@@ -2175,8 +2161,6 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
2175 spin_lock(&tomoyo_query_list_lock); 2161 spin_lock(&tomoyo_query_list_lock);
2176 list_for_each(tmp, &tomoyo_query_list) { 2162 list_for_each(tmp, &tomoyo_query_list) {
2177 struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); 2163 struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
2178 if (ptr->answer)
2179 continue;
2180 if (pos++ != head->r.query_index) 2164 if (pos++ != head->r.query_index)
2181 continue; 2165 continue;
2182 len = ptr->query_len; 2166 len = ptr->query_len;
@@ -2194,8 +2178,6 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
2194 spin_lock(&tomoyo_query_list_lock); 2178 spin_lock(&tomoyo_query_list_lock);
2195 list_for_each(tmp, &tomoyo_query_list) { 2179 list_for_each(tmp, &tomoyo_query_list) {
2196 struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); 2180 struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
2197 if (ptr->answer)
2198 continue;
2199 if (pos++ != head->r.query_index) 2181 if (pos++ != head->r.query_index)
2200 continue; 2182 continue;
2201 /* 2183 /*
@@ -2243,8 +2225,10 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
2243 struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); 2225 struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
2244 if (ptr->serial != serial) 2226 if (ptr->serial != serial)
2245 continue; 2227 continue;
2246 if (!ptr->answer) 2228 ptr->answer = answer;
2247 ptr->answer = answer; 2229 /* Remove from tomoyo_query_list. */
2230 if (ptr->answer)
2231 list_del_init(&ptr->list);
2248 break; 2232 break;
2249 } 2233 }
2250 spin_unlock(&tomoyo_query_list_lock); 2234 spin_unlock(&tomoyo_query_list_lock);
@@ -2477,18 +2461,17 @@ int tomoyo_open_control(const u8 type, struct file *file)
2477 * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. 2461 * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
2478 * 2462 *
2479 * @file: Pointer to "struct file". 2463 * @file: Pointer to "struct file".
2480 * @wait: Pointer to "poll_table". 2464 * @wait: Pointer to "poll_table". Maybe NULL.
2481 * 2465 *
2482 * Waits for read readiness. 2466 * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
2483 * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and 2467 * POLLOUT | POLLWRNORM otherwise.
2484 * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd.
2485 */ 2468 */
2486int tomoyo_poll_control(struct file *file, poll_table *wait) 2469unsigned int tomoyo_poll_control(struct file *file, poll_table *wait)
2487{ 2470{
2488 struct tomoyo_io_buffer *head = file->private_data; 2471 struct tomoyo_io_buffer *head = file->private_data;
2489 if (!head->poll) 2472 if (head->poll)
2490 return -ENOSYS; 2473 return head->poll(file, wait) | POLLOUT | POLLWRNORM;
2491 return head->poll(file, wait); 2474 return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
2492} 2475}
2493 2476
2494/** 2477/**
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 9512222d5581..30fd98369700 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -788,7 +788,7 @@ struct tomoyo_acl_param {
788struct tomoyo_io_buffer { 788struct tomoyo_io_buffer {
789 void (*read) (struct tomoyo_io_buffer *); 789 void (*read) (struct tomoyo_io_buffer *);
790 int (*write) (struct tomoyo_io_buffer *); 790 int (*write) (struct tomoyo_io_buffer *);
791 int (*poll) (struct file *file, poll_table *wait); 791 unsigned int (*poll) (struct file *file, poll_table *wait);
792 /* Exclusive lock for this structure. */ 792 /* Exclusive lock for this structure. */
793 struct mutex io_sem; 793 struct mutex io_sem;
794 char __user *read_user_buf; 794 char __user *read_user_buf;
@@ -981,8 +981,8 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path,
981 unsigned long number); 981 unsigned long number);
982int tomoyo_path_perm(const u8 operation, struct path *path, 982int tomoyo_path_perm(const u8 operation, struct path *path,
983 const char *target); 983 const char *target);
984int tomoyo_poll_control(struct file *file, poll_table *wait); 984unsigned int tomoyo_poll_control(struct file *file, poll_table *wait);
985int tomoyo_poll_log(struct file *file, poll_table *wait); 985unsigned int tomoyo_poll_log(struct file *file, poll_table *wait);
986int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, 986int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
987 int addr_len); 987 int addr_len);
988int tomoyo_socket_connect_permission(struct socket *sock, 988int tomoyo_socket_connect_permission(struct socket *sock,
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
index bee09d062057..fe00cdfd0267 100644
--- a/security/tomoyo/mount.c
+++ b/security/tomoyo/mount.c
@@ -199,30 +199,32 @@ int tomoyo_mount_permission(char *dev_name, struct path *path,
199 if (flags & MS_REMOUNT) { 199 if (flags & MS_REMOUNT) {
200 type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; 200 type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT];
201 flags &= ~MS_REMOUNT; 201 flags &= ~MS_REMOUNT;
202 } 202 } else if (flags & MS_BIND) {
203 if (flags & MS_MOVE) {
204 type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
205 flags &= ~MS_MOVE;
206 }
207 if (flags & MS_BIND) {
208 type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; 203 type = tomoyo_mounts[TOMOYO_MOUNT_BIND];
209 flags &= ~MS_BIND; 204 flags &= ~MS_BIND;
210 } 205 } else if (flags & MS_SHARED) {
211 if (flags & MS_UNBINDABLE) { 206 if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
212 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; 207 return -EINVAL;
213 flags &= ~MS_UNBINDABLE; 208 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED];
214 } 209 flags &= ~MS_SHARED;
215 if (flags & MS_PRIVATE) { 210 } else if (flags & MS_PRIVATE) {
211 if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
212 return -EINVAL;
216 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; 213 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE];
217 flags &= ~MS_PRIVATE; 214 flags &= ~MS_PRIVATE;
218 } 215 } else if (flags & MS_SLAVE) {
219 if (flags & MS_SLAVE) { 216 if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
217 return -EINVAL;
220 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; 218 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE];
221 flags &= ~MS_SLAVE; 219 flags &= ~MS_SLAVE;
222 } 220 } else if (flags & MS_UNBINDABLE) {
223 if (flags & MS_SHARED) { 221 if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
224 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; 222 return -EINVAL;
225 flags &= ~MS_SHARED; 223 type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE];
224 flags &= ~MS_UNBINDABLE;
225 } else if (flags & MS_MOVE) {
226 type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
227 flags &= ~MS_MOVE;
226 } 228 }
227 if (!type) 229 if (!type)
228 type = "<NULL>"; 230 type = "<NULL>";
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 482b2a5f48f0..8592f2fc6ebb 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -157,9 +157,10 @@ static int tomoyo_release(struct inode *inode, struct file *file)
157 * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. 157 * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface.
158 * 158 *
159 * @file: Pointer to "struct file". 159 * @file: Pointer to "struct file".
160 * @wait: Pointer to "poll_table". 160 * @wait: Pointer to "poll_table". Maybe NULL.
161 * 161 *
162 * Returns 0 on success, negative value otherwise. 162 * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
163 * POLLOUT | POLLWRNORM otherwise.
163 */ 164 */
164static unsigned int tomoyo_poll(struct file *file, poll_table *wait) 165static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
165{ 166{
diff --git a/security/yama/Kconfig b/security/yama/Kconfig
new file mode 100644
index 000000000000..51d6709d8bbd
--- /dev/null
+++ b/security/yama/Kconfig
@@ -0,0 +1,13 @@
1config SECURITY_YAMA
2 bool "Yama support"
3 depends on SECURITY
4 select SECURITYFS
5 select SECURITY_PATH
6 default n
7 help
8 This selects Yama, which extends DAC support with additional
9 system-wide security settings beyond regular Linux discretionary
10 access controls. Currently available is ptrace scope restriction.
11 Further information can be found in Documentation/security/Yama.txt.
12
13 If you are unsure how to answer this question, answer N.
diff --git a/security/yama/Makefile b/security/yama/Makefile
new file mode 100644
index 000000000000..8b5e06588456
--- /dev/null
+++ b/security/yama/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_SECURITY_YAMA) := yama.o
2
3yama-y := yama_lsm.o
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
new file mode 100644
index 000000000000..573723843a04
--- /dev/null
+++ b/security/yama/yama_lsm.c
@@ -0,0 +1,323 @@
1/*
2 * Yama Linux Security Module
3 *
4 * Author: Kees Cook <keescook@chromium.org>
5 *
6 * Copyright (C) 2010 Canonical, Ltd.
7 * Copyright (C) 2011 The Chromium OS Authors.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2, as
11 * published by the Free Software Foundation.
12 *
13 */
14
15#include <linux/security.h>
16#include <linux/sysctl.h>
17#include <linux/ptrace.h>
18#include <linux/prctl.h>
19#include <linux/ratelimit.h>
20
21static int ptrace_scope = 1;
22
23/* describe a ptrace relationship for potential exception */
24struct ptrace_relation {
25 struct task_struct *tracer;
26 struct task_struct *tracee;
27 struct list_head node;
28};
29
30static LIST_HEAD(ptracer_relations);
31static DEFINE_SPINLOCK(ptracer_relations_lock);
32
33/**
34 * yama_ptracer_add - add/replace an exception for this tracer/tracee pair
35 * @tracer: the task_struct of the process doing the ptrace
36 * @tracee: the task_struct of the process to be ptraced
37 *
38 * Each tracee can have, at most, one tracer registered. Each time this
39 * is called, the prior registered tracer will be replaced for the tracee.
40 *
41 * Returns 0 if relationship was added, -ve on error.
42 */
43static int yama_ptracer_add(struct task_struct *tracer,
44 struct task_struct *tracee)
45{
46 int rc = 0;
47 struct ptrace_relation *added;
48 struct ptrace_relation *entry, *relation = NULL;
49
50 added = kmalloc(sizeof(*added), GFP_KERNEL);
51 if (!added)
52 return -ENOMEM;
53
54 spin_lock_bh(&ptracer_relations_lock);
55 list_for_each_entry(entry, &ptracer_relations, node)
56 if (entry->tracee == tracee) {
57 relation = entry;
58 break;
59 }
60 if (!relation) {
61 relation = added;
62 relation->tracee = tracee;
63 list_add(&relation->node, &ptracer_relations);
64 }
65 relation->tracer = tracer;
66
67 spin_unlock_bh(&ptracer_relations_lock);
68 if (added != relation)
69 kfree(added);
70
71 return rc;
72}
73
74/**
75 * yama_ptracer_del - remove exceptions related to the given tasks
76 * @tracer: remove any relation where tracer task matches
77 * @tracee: remove any relation where tracee task matches
78 */
79static void yama_ptracer_del(struct task_struct *tracer,
80 struct task_struct *tracee)
81{
82 struct ptrace_relation *relation, *safe;
83
84 spin_lock_bh(&ptracer_relations_lock);
85 list_for_each_entry_safe(relation, safe, &ptracer_relations, node)
86 if (relation->tracee == tracee ||
87 (tracer && relation->tracer == tracer)) {
88 list_del(&relation->node);
89 kfree(relation);
90 }
91 spin_unlock_bh(&ptracer_relations_lock);
92}
93
94/**
95 * yama_task_free - check for task_pid to remove from exception list
96 * @task: task being removed
97 */
98static void yama_task_free(struct task_struct *task)
99{
100 yama_ptracer_del(task, task);
101}
102
103/**
104 * yama_task_prctl - check for Yama-specific prctl operations
105 * @option: operation
106 * @arg2: argument
107 * @arg3: argument
108 * @arg4: argument
109 * @arg5: argument
110 *
111 * Return 0 on success, -ve on error. -ENOSYS is returned when Yama
112 * does not handle the given option.
113 */
114static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
115 unsigned long arg4, unsigned long arg5)
116{
117 int rc;
118 struct task_struct *myself = current;
119
120 rc = cap_task_prctl(option, arg2, arg3, arg4, arg5);
121 if (rc != -ENOSYS)
122 return rc;
123
124 switch (option) {
125 case PR_SET_PTRACER:
126 /* Since a thread can call prctl(), find the group leader
127 * before calling _add() or _del() on it, since we want
128 * process-level granularity of control. The tracer group
129 * leader checking is handled later when walking the ancestry
130 * at the time of PTRACE_ATTACH check.
131 */
132 rcu_read_lock();
133 if (!thread_group_leader(myself))
134 myself = rcu_dereference(myself->group_leader);
135 get_task_struct(myself);
136 rcu_read_unlock();
137
138 if (arg2 == 0) {
139 yama_ptracer_del(NULL, myself);
140 rc = 0;
141 } else if (arg2 == PR_SET_PTRACER_ANY) {
142 rc = yama_ptracer_add(NULL, myself);
143 } else {
144 struct task_struct *tracer;
145
146 rcu_read_lock();
147 tracer = find_task_by_vpid(arg2);
148 if (tracer)
149 get_task_struct(tracer);
150 else
151 rc = -EINVAL;
152 rcu_read_unlock();
153
154 if (tracer) {
155 rc = yama_ptracer_add(tracer, myself);
156 put_task_struct(tracer);
157 }
158 }
159
160 put_task_struct(myself);
161 break;
162 }
163
164 return rc;
165}
166
167/**
168 * task_is_descendant - walk up a process family tree looking for a match
169 * @parent: the process to compare against while walking up from child
170 * @child: the process to start from while looking upwards for parent
171 *
172 * Returns 1 if child is a descendant of parent, 0 if not.
173 */
174static int task_is_descendant(struct task_struct *parent,
175 struct task_struct *child)
176{
177 int rc = 0;
178 struct task_struct *walker = child;
179
180 if (!parent || !child)
181 return 0;
182
183 rcu_read_lock();
184 if (!thread_group_leader(parent))
185 parent = rcu_dereference(parent->group_leader);
186 while (walker->pid > 0) {
187 if (!thread_group_leader(walker))
188 walker = rcu_dereference(walker->group_leader);
189 if (walker == parent) {
190 rc = 1;
191 break;
192 }
193 walker = rcu_dereference(walker->real_parent);
194 }
195 rcu_read_unlock();
196
197 return rc;
198}
199
200/**
201 * ptracer_exception_found - tracer registered as exception for this tracee
202 * @tracer: the task_struct of the process attempting ptrace
203 * @tracee: the task_struct of the process to be ptraced
204 *
205 * Returns 1 if tracer has is ptracer exception ancestor for tracee.
206 */
207static int ptracer_exception_found(struct task_struct *tracer,
208 struct task_struct *tracee)
209{
210 int rc = 0;
211 struct ptrace_relation *relation;
212 struct task_struct *parent = NULL;
213 bool found = false;
214
215 spin_lock_bh(&ptracer_relations_lock);
216 rcu_read_lock();
217 if (!thread_group_leader(tracee))
218 tracee = rcu_dereference(tracee->group_leader);
219 list_for_each_entry(relation, &ptracer_relations, node)
220 if (relation->tracee == tracee) {
221 parent = relation->tracer;
222 found = true;
223 break;
224 }
225
226 if (found && (parent == NULL || task_is_descendant(parent, tracer)))
227 rc = 1;
228 rcu_read_unlock();
229 spin_unlock_bh(&ptracer_relations_lock);
230
231 return rc;
232}
233
234/**
235 * yama_ptrace_access_check - validate PTRACE_ATTACH calls
236 * @child: task that current task is attempting to ptrace
237 * @mode: ptrace attach mode
238 *
239 * Returns 0 if following the ptrace is allowed, -ve on error.
240 */
241static int yama_ptrace_access_check(struct task_struct *child,
242 unsigned int mode)
243{
244 int rc;
245
246 /* If standard caps disallows it, so does Yama. We should
247 * only tighten restrictions further.
248 */
249 rc = cap_ptrace_access_check(child, mode);
250 if (rc)
251 return rc;
252
253 /* require ptrace target be a child of ptracer on attach */
254 if (mode == PTRACE_MODE_ATTACH &&
255 ptrace_scope &&
256 !task_is_descendant(current, child) &&
257 !ptracer_exception_found(current, child) &&
258 !capable(CAP_SYS_PTRACE))
259 rc = -EPERM;
260
261 if (rc) {
262 char name[sizeof(current->comm)];
263 printk_ratelimited(KERN_NOTICE "ptrace of non-child"
264 " pid %d was attempted by: %s (pid %d)\n",
265 child->pid,
266 get_task_comm(name, current),
267 current->pid);
268 }
269
270 return rc;
271}
272
273static struct security_operations yama_ops = {
274 .name = "yama",
275
276 .ptrace_access_check = yama_ptrace_access_check,
277 .task_prctl = yama_task_prctl,
278 .task_free = yama_task_free,
279};
280
281#ifdef CONFIG_SYSCTL
282static int zero;
283static int one = 1;
284
285struct ctl_path yama_sysctl_path[] = {
286 { .procname = "kernel", },
287 { .procname = "yama", },
288 { }
289};
290
291static struct ctl_table yama_sysctl_table[] = {
292 {
293 .procname = "ptrace_scope",
294 .data = &ptrace_scope,
295 .maxlen = sizeof(int),
296 .mode = 0644,
297 .proc_handler = proc_dointvec_minmax,
298 .extra1 = &zero,
299 .extra2 = &one,
300 },
301 { }
302};
303#endif /* CONFIG_SYSCTL */
304
305static __init int yama_init(void)
306{
307 if (!security_module_enable(&yama_ops))
308 return 0;
309
310 printk(KERN_INFO "Yama: becoming mindful.\n");
311
312 if (register_security(&yama_ops))
313 panic("Yama: kernel registration failed.\n");
314
315#ifdef CONFIG_SYSCTL
316 if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
317 panic("Yama: sysctl registration failed.\n");
318#endif
319
320 return 0;
321}
322
323security_initcall(yama_init);