diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 52 |
1 files changed, 40 insertions, 12 deletions
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/proc_fs.h> | 45 | #include <linux/proc_fs.h> |
46 | #include <linux/mount.h> | 46 | #include <linux/mount.h> |
47 | #include <linux/security.h> | 47 | #include <linux/security.h> |
48 | #include <linux/ima.h> | ||
48 | #include <linux/syscalls.h> | 49 | #include <linux/syscalls.h> |
49 | #include <linux/tsacct_kern.h> | 50 | #include <linux/tsacct_kern.h> |
50 | #include <linux/cn_proc.h> | 51 | #include <linux/cn_proc.h> |
@@ -52,6 +53,7 @@ | |||
52 | #include <linux/tracehook.h> | 53 | #include <linux/tracehook.h> |
53 | #include <linux/kmod.h> | 54 | #include <linux/kmod.h> |
54 | #include <linux/fsnotify.h> | 55 | #include <linux/fsnotify.h> |
56 | #include <linux/fs_struct.h> | ||
55 | 57 | ||
56 | #include <asm/uaccess.h> | 58 | #include <asm/uaccess.h> |
57 | #include <asm/mmu_context.h> | 59 | #include <asm/mmu_context.h> |
@@ -127,6 +129,9 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) | |||
127 | MAY_READ | MAY_EXEC | MAY_OPEN); | 129 | MAY_READ | MAY_EXEC | MAY_OPEN); |
128 | if (error) | 130 | if (error) |
129 | goto exit; | 131 | goto exit; |
132 | error = ima_path_check(&nd.path, MAY_READ | MAY_EXEC | MAY_OPEN); | ||
133 | if (error) | ||
134 | goto exit; | ||
130 | 135 | ||
131 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); | 136 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); |
132 | error = PTR_ERR(file); | 137 | error = PTR_ERR(file); |
@@ -674,6 +679,9 @@ struct file *open_exec(const char *name) | |||
674 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); | 679 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); |
675 | if (err) | 680 | if (err) |
676 | goto out_path_put; | 681 | goto out_path_put; |
682 | err = ima_path_check(&nd.path, MAY_EXEC | MAY_OPEN); | ||
683 | if (err) | ||
684 | goto out_path_put; | ||
677 | 685 | ||
678 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); | 686 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); |
679 | if (IS_ERR(file)) | 687 | if (IS_ERR(file)) |
@@ -1049,32 +1057,35 @@ EXPORT_SYMBOL(install_exec_creds); | |||
1049 | * - the caller must hold current->cred_exec_mutex to protect against | 1057 | * - the caller must hold current->cred_exec_mutex to protect against |
1050 | * PTRACE_ATTACH | 1058 | * PTRACE_ATTACH |
1051 | */ | 1059 | */ |
1052 | void check_unsafe_exec(struct linux_binprm *bprm, struct files_struct *files) | 1060 | int check_unsafe_exec(struct linux_binprm *bprm) |
1053 | { | 1061 | { |
1054 | struct task_struct *p = current, *t; | 1062 | struct task_struct *p = current, *t; |
1055 | unsigned long flags; | 1063 | unsigned long flags; |
1056 | unsigned n_fs, n_files, n_sighand; | 1064 | unsigned n_fs; |
1065 | int res = 0; | ||
1057 | 1066 | ||
1058 | bprm->unsafe = tracehook_unsafe_exec(p); | 1067 | bprm->unsafe = tracehook_unsafe_exec(p); |
1059 | 1068 | ||
1060 | n_fs = 1; | 1069 | n_fs = 1; |
1061 | n_files = 1; | 1070 | write_lock(&p->fs->lock); |
1062 | n_sighand = 1; | ||
1063 | lock_task_sighand(p, &flags); | 1071 | lock_task_sighand(p, &flags); |
1064 | for (t = next_thread(p); t != p; t = next_thread(t)) { | 1072 | for (t = next_thread(p); t != p; t = next_thread(t)) { |
1065 | if (t->fs == p->fs) | 1073 | if (t->fs == p->fs) |
1066 | n_fs++; | 1074 | n_fs++; |
1067 | if (t->files == files) | ||
1068 | n_files++; | ||
1069 | n_sighand++; | ||
1070 | } | 1075 | } |
1071 | 1076 | ||
1072 | if (atomic_read(&p->fs->count) > n_fs || | 1077 | if (p->fs->users > n_fs) { |
1073 | atomic_read(&p->files->count) > n_files || | ||
1074 | atomic_read(&p->sighand->count) > n_sighand) | ||
1075 | bprm->unsafe |= LSM_UNSAFE_SHARE; | 1078 | bprm->unsafe |= LSM_UNSAFE_SHARE; |
1079 | } else { | ||
1080 | if (p->fs->in_exec) | ||
1081 | res = -EAGAIN; | ||
1082 | p->fs->in_exec = 1; | ||
1083 | } | ||
1076 | 1084 | ||
1077 | unlock_task_sighand(p, &flags); | 1085 | unlock_task_sighand(p, &flags); |
1086 | write_unlock(&p->fs->lock); | ||
1087 | |||
1088 | return res; | ||
1078 | } | 1089 | } |
1079 | 1090 | ||
1080 | /* | 1091 | /* |
@@ -1184,6 +1195,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1184 | retval = security_bprm_check(bprm); | 1195 | retval = security_bprm_check(bprm); |
1185 | if (retval) | 1196 | if (retval) |
1186 | return retval; | 1197 | return retval; |
1198 | retval = ima_bprm_check(bprm); | ||
1199 | if (retval) | ||
1200 | return retval; | ||
1187 | 1201 | ||
1188 | /* kernel module loader fixup */ | 1202 | /* kernel module loader fixup */ |
1189 | /* so we don't try to load run modprobe in kernel space. */ | 1203 | /* so we don't try to load run modprobe in kernel space. */ |
@@ -1284,17 +1298,21 @@ int do_execve(char * filename, | |||
1284 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | 1298 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); |
1285 | if (retval < 0) | 1299 | if (retval < 0) |
1286 | goto out_free; | 1300 | goto out_free; |
1301 | current->in_execve = 1; | ||
1287 | 1302 | ||
1288 | retval = -ENOMEM; | 1303 | retval = -ENOMEM; |
1289 | bprm->cred = prepare_exec_creds(); | 1304 | bprm->cred = prepare_exec_creds(); |
1290 | if (!bprm->cred) | 1305 | if (!bprm->cred) |
1291 | goto out_unlock; | 1306 | goto out_unlock; |
1292 | check_unsafe_exec(bprm, displaced); | 1307 | |
1308 | retval = check_unsafe_exec(bprm); | ||
1309 | if (retval) | ||
1310 | goto out_unlock; | ||
1293 | 1311 | ||
1294 | file = open_exec(filename); | 1312 | file = open_exec(filename); |
1295 | retval = PTR_ERR(file); | 1313 | retval = PTR_ERR(file); |
1296 | if (IS_ERR(file)) | 1314 | if (IS_ERR(file)) |
1297 | goto out_unlock; | 1315 | goto out_unmark; |
1298 | 1316 | ||
1299 | sched_exec(); | 1317 | sched_exec(); |
1300 | 1318 | ||
@@ -1337,6 +1355,10 @@ int do_execve(char * filename, | |||
1337 | goto out; | 1355 | goto out; |
1338 | 1356 | ||
1339 | /* execve succeeded */ | 1357 | /* execve succeeded */ |
1358 | write_lock(¤t->fs->lock); | ||
1359 | current->fs->in_exec = 0; | ||
1360 | write_unlock(¤t->fs->lock); | ||
1361 | current->in_execve = 0; | ||
1340 | mutex_unlock(¤t->cred_exec_mutex); | 1362 | mutex_unlock(¤t->cred_exec_mutex); |
1341 | acct_update_integrals(current); | 1363 | acct_update_integrals(current); |
1342 | free_bprm(bprm); | 1364 | free_bprm(bprm); |
@@ -1354,7 +1376,13 @@ out_file: | |||
1354 | fput(bprm->file); | 1376 | fput(bprm->file); |
1355 | } | 1377 | } |
1356 | 1378 | ||
1379 | out_unmark: | ||
1380 | write_lock(¤t->fs->lock); | ||
1381 | current->fs->in_exec = 0; | ||
1382 | write_unlock(¤t->fs->lock); | ||
1383 | |||
1357 | out_unlock: | 1384 | out_unlock: |
1385 | current->in_execve = 0; | ||
1358 | mutex_unlock(¤t->cred_exec_mutex); | 1386 | mutex_unlock(¤t->cred_exec_mutex); |
1359 | 1387 | ||
1360 | out_free: | 1388 | out_free: |