diff options
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 201 |
1 files changed, 111 insertions, 90 deletions
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| 34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 35 | #include <linux/pagemap.h> | 35 | #include <linux/pagemap.h> |
| 36 | #include <linux/perf_counter.h> | ||
| 36 | #include <linux/highmem.h> | 37 | #include <linux/highmem.h> |
| 37 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
| 38 | #include <linux/key.h> | 39 | #include <linux/key.h> |
| @@ -45,6 +46,7 @@ | |||
| 45 | #include <linux/proc_fs.h> | 46 | #include <linux/proc_fs.h> |
| 46 | #include <linux/mount.h> | 47 | #include <linux/mount.h> |
| 47 | #include <linux/security.h> | 48 | #include <linux/security.h> |
| 49 | #include <linux/ima.h> | ||
| 48 | #include <linux/syscalls.h> | 50 | #include <linux/syscalls.h> |
| 49 | #include <linux/tsacct_kern.h> | 51 | #include <linux/tsacct_kern.h> |
| 50 | #include <linux/cn_proc.h> | 52 | #include <linux/cn_proc.h> |
| @@ -52,6 +54,7 @@ | |||
| 52 | #include <linux/tracehook.h> | 54 | #include <linux/tracehook.h> |
| 53 | #include <linux/kmod.h> | 55 | #include <linux/kmod.h> |
| 54 | #include <linux/fsnotify.h> | 56 | #include <linux/fsnotify.h> |
| 57 | #include <linux/fs_struct.h> | ||
| 55 | 58 | ||
| 56 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
| 57 | #include <asm/mmu_context.h> | 60 | #include <asm/mmu_context.h> |
| @@ -67,17 +70,18 @@ int suid_dumpable = 0; | |||
| 67 | static LIST_HEAD(formats); | 70 | static LIST_HEAD(formats); |
| 68 | static DEFINE_RWLOCK(binfmt_lock); | 71 | static DEFINE_RWLOCK(binfmt_lock); |
| 69 | 72 | ||
| 70 | int register_binfmt(struct linux_binfmt * fmt) | 73 | int __register_binfmt(struct linux_binfmt * fmt, int insert) |
| 71 | { | 74 | { |
| 72 | if (!fmt) | 75 | if (!fmt) |
| 73 | return -EINVAL; | 76 | return -EINVAL; |
| 74 | write_lock(&binfmt_lock); | 77 | write_lock(&binfmt_lock); |
| 75 | list_add(&fmt->lh, &formats); | 78 | insert ? list_add(&fmt->lh, &formats) : |
| 79 | list_add_tail(&fmt->lh, &formats); | ||
| 76 | write_unlock(&binfmt_lock); | 80 | write_unlock(&binfmt_lock); |
| 77 | return 0; | 81 | return 0; |
| 78 | } | 82 | } |
| 79 | 83 | ||
| 80 | EXPORT_SYMBOL(register_binfmt); | 84 | EXPORT_SYMBOL(__register_binfmt); |
| 81 | 85 | ||
| 82 | void unregister_binfmt(struct linux_binfmt * fmt) | 86 | void unregister_binfmt(struct linux_binfmt * fmt) |
| 83 | { | 87 | { |
| @@ -102,37 +106,28 @@ static inline void put_binfmt(struct linux_binfmt * fmt) | |||
| 102 | SYSCALL_DEFINE1(uselib, const char __user *, library) | 106 | SYSCALL_DEFINE1(uselib, const char __user *, library) |
| 103 | { | 107 | { |
| 104 | struct file *file; | 108 | struct file *file; |
| 105 | struct nameidata nd; | ||
| 106 | char *tmp = getname(library); | 109 | char *tmp = getname(library); |
| 107 | int error = PTR_ERR(tmp); | 110 | int error = PTR_ERR(tmp); |
| 108 | 111 | ||
| 109 | if (!IS_ERR(tmp)) { | 112 | if (IS_ERR(tmp)) |
| 110 | error = path_lookup_open(AT_FDCWD, tmp, | 113 | goto out; |
| 111 | LOOKUP_FOLLOW, &nd, | 114 | |
| 112 | FMODE_READ|FMODE_EXEC); | 115 | file = do_filp_open(AT_FDCWD, tmp, |
| 113 | putname(tmp); | 116 | O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0, |
| 114 | } | 117 | MAY_READ | MAY_EXEC | MAY_OPEN); |
| 115 | if (error) | 118 | putname(tmp); |
| 119 | error = PTR_ERR(file); | ||
| 120 | if (IS_ERR(file)) | ||
| 116 | goto out; | 121 | goto out; |
| 117 | 122 | ||
| 118 | error = -EINVAL; | 123 | error = -EINVAL; |
| 119 | if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) | 124 | if (!S_ISREG(file->f_path.dentry->d_inode->i_mode)) |
| 120 | goto exit; | 125 | goto exit; |
| 121 | 126 | ||
| 122 | error = -EACCES; | 127 | error = -EACCES; |
| 123 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | 128 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) |
| 124 | goto exit; | 129 | goto exit; |
| 125 | 130 | ||
| 126 | error = inode_permission(nd.path.dentry->d_inode, | ||
| 127 | MAY_READ | MAY_EXEC | MAY_OPEN); | ||
| 128 | if (error) | ||
| 129 | goto exit; | ||
| 130 | |||
| 131 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); | ||
| 132 | error = PTR_ERR(file); | ||
| 133 | if (IS_ERR(file)) | ||
| 134 | goto out; | ||
| 135 | |||
| 136 | fsnotify_open(file->f_path.dentry); | 131 | fsnotify_open(file->f_path.dentry); |
| 137 | 132 | ||
| 138 | error = -ENOEXEC; | 133 | error = -ENOEXEC; |
| @@ -154,13 +149,10 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) | |||
| 154 | } | 149 | } |
| 155 | read_unlock(&binfmt_lock); | 150 | read_unlock(&binfmt_lock); |
| 156 | } | 151 | } |
| 152 | exit: | ||
| 157 | fput(file); | 153 | fput(file); |
| 158 | out: | 154 | out: |
| 159 | return error; | 155 | return error; |
| 160 | exit: | ||
| 161 | release_open_intent(&nd); | ||
| 162 | path_put(&nd.path); | ||
| 163 | goto out; | ||
| 164 | } | 156 | } |
| 165 | 157 | ||
| 166 | #ifdef CONFIG_MMU | 158 | #ifdef CONFIG_MMU |
| @@ -655,50 +647,39 @@ EXPORT_SYMBOL(setup_arg_pages); | |||
| 655 | 647 | ||
| 656 | struct file *open_exec(const char *name) | 648 | struct file *open_exec(const char *name) |
| 657 | { | 649 | { |
| 658 | struct nameidata nd; | ||
| 659 | struct file *file; | 650 | struct file *file; |
| 660 | int err; | 651 | int err; |
| 661 | 652 | ||
| 662 | err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, | 653 | file = do_filp_open(AT_FDCWD, name, |
| 663 | FMODE_READ|FMODE_EXEC); | 654 | O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0, |
| 664 | if (err) | 655 | MAY_EXEC | MAY_OPEN); |
| 656 | if (IS_ERR(file)) | ||
| 665 | goto out; | 657 | goto out; |
| 666 | 658 | ||
| 667 | err = -EACCES; | 659 | err = -EACCES; |
| 668 | if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) | 660 | if (!S_ISREG(file->f_path.dentry->d_inode->i_mode)) |
| 669 | goto out_path_put; | 661 | goto exit; |
| 670 | |||
| 671 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | ||
| 672 | goto out_path_put; | ||
| 673 | |||
| 674 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); | ||
| 675 | if (err) | ||
| 676 | goto out_path_put; | ||
| 677 | 662 | ||
| 678 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); | 663 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) |
| 679 | if (IS_ERR(file)) | 664 | goto exit; |
| 680 | return file; | ||
| 681 | 665 | ||
| 682 | fsnotify_open(file->f_path.dentry); | 666 | fsnotify_open(file->f_path.dentry); |
| 683 | 667 | ||
| 684 | err = deny_write_access(file); | 668 | err = deny_write_access(file); |
| 685 | if (err) { | 669 | if (err) |
| 686 | fput(file); | 670 | goto exit; |
| 687 | goto out; | ||
| 688 | } | ||
| 689 | 671 | ||
| 672 | out: | ||
| 690 | return file; | 673 | return file; |
| 691 | 674 | ||
| 692 | out_path_put: | 675 | exit: |
| 693 | release_open_intent(&nd); | 676 | fput(file); |
| 694 | path_put(&nd.path); | ||
| 695 | out: | ||
| 696 | return ERR_PTR(err); | 677 | return ERR_PTR(err); |
| 697 | } | 678 | } |
| 698 | EXPORT_SYMBOL(open_exec); | 679 | EXPORT_SYMBOL(open_exec); |
| 699 | 680 | ||
| 700 | int kernel_read(struct file *file, unsigned long offset, | 681 | int kernel_read(struct file *file, loff_t offset, |
| 701 | char *addr, unsigned long count) | 682 | char *addr, unsigned long count) |
| 702 | { | 683 | { |
| 703 | mm_segment_t old_fs; | 684 | mm_segment_t old_fs; |
| 704 | loff_t pos = offset; | 685 | loff_t pos = offset; |
| @@ -942,6 +923,7 @@ void set_task_comm(struct task_struct *tsk, char *buf) | |||
| 942 | task_lock(tsk); | 923 | task_lock(tsk); |
| 943 | strlcpy(tsk->comm, buf, sizeof(tsk->comm)); | 924 | strlcpy(tsk->comm, buf, sizeof(tsk->comm)); |
| 944 | task_unlock(tsk); | 925 | task_unlock(tsk); |
| 926 | perf_counter_comm(tsk); | ||
| 945 | } | 927 | } |
| 946 | 928 | ||
| 947 | int flush_old_exec(struct linux_binprm * bprm) | 929 | int flush_old_exec(struct linux_binprm * bprm) |
| @@ -1010,6 +992,13 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
| 1010 | 992 | ||
| 1011 | current->personality &= ~bprm->per_clear; | 993 | current->personality &= ~bprm->per_clear; |
| 1012 | 994 | ||
| 995 | /* | ||
| 996 | * Flush performance counters when crossing a | ||
| 997 | * security domain: | ||
| 998 | */ | ||
| 999 | if (!get_dumpable(current->mm)) | ||
| 1000 | perf_counter_exit_task(current); | ||
| 1001 | |||
| 1013 | /* An exec changes our domain. We are no longer part of the thread | 1002 | /* An exec changes our domain. We are no longer part of the thread |
| 1014 | group */ | 1003 | group */ |
| 1015 | 1004 | ||
| @@ -1027,6 +1016,35 @@ out: | |||
| 1027 | EXPORT_SYMBOL(flush_old_exec); | 1016 | EXPORT_SYMBOL(flush_old_exec); |
| 1028 | 1017 | ||
| 1029 | /* | 1018 | /* |
| 1019 | * Prepare credentials and lock ->cred_guard_mutex. | ||
| 1020 | * install_exec_creds() commits the new creds and drops the lock. | ||
| 1021 | * Or, if exec fails before, free_bprm() should release ->cred and | ||
| 1022 | * and unlock. | ||
| 1023 | */ | ||
| 1024 | int prepare_bprm_creds(struct linux_binprm *bprm) | ||
| 1025 | { | ||
| 1026 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) | ||
| 1027 | return -ERESTARTNOINTR; | ||
| 1028 | |||
| 1029 | bprm->cred = prepare_exec_creds(); | ||
| 1030 | if (likely(bprm->cred)) | ||
| 1031 | return 0; | ||
| 1032 | |||
| 1033 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1034 | return -ENOMEM; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | void free_bprm(struct linux_binprm *bprm) | ||
| 1038 | { | ||
| 1039 | free_arg_pages(bprm); | ||
| 1040 | if (bprm->cred) { | ||
| 1041 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1042 | abort_creds(bprm->cred); | ||
| 1043 | } | ||
| 1044 | kfree(bprm); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | /* | ||
| 1030 | * install the new credentials for this executable | 1048 | * install the new credentials for this executable |
| 1031 | */ | 1049 | */ |
| 1032 | void install_exec_creds(struct linux_binprm *bprm) | 1050 | void install_exec_creds(struct linux_binprm *bprm) |
| @@ -1035,46 +1053,50 @@ void install_exec_creds(struct linux_binprm *bprm) | |||
| 1035 | 1053 | ||
| 1036 | commit_creds(bprm->cred); | 1054 | commit_creds(bprm->cred); |
| 1037 | bprm->cred = NULL; | 1055 | bprm->cred = NULL; |
| 1038 | 1056 | /* | |
| 1039 | /* cred_exec_mutex must be held at least to this point to prevent | 1057 | * cred_guard_mutex must be held at least to this point to prevent |
| 1040 | * ptrace_attach() from altering our determination of the task's | 1058 | * ptrace_attach() from altering our determination of the task's |
| 1041 | * credentials; any time after this it may be unlocked */ | 1059 | * credentials; any time after this it may be unlocked. |
| 1042 | 1060 | */ | |
| 1043 | security_bprm_committed_creds(bprm); | 1061 | security_bprm_committed_creds(bprm); |
| 1062 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1044 | } | 1063 | } |
| 1045 | EXPORT_SYMBOL(install_exec_creds); | 1064 | EXPORT_SYMBOL(install_exec_creds); |
| 1046 | 1065 | ||
| 1047 | /* | 1066 | /* |
| 1048 | * determine how safe it is to execute the proposed program | 1067 | * determine how safe it is to execute the proposed program |
| 1049 | * - the caller must hold current->cred_exec_mutex to protect against | 1068 | * - the caller must hold current->cred_guard_mutex to protect against |
| 1050 | * PTRACE_ATTACH | 1069 | * PTRACE_ATTACH |
| 1051 | */ | 1070 | */ |
| 1052 | void check_unsafe_exec(struct linux_binprm *bprm, struct files_struct *files) | 1071 | int check_unsafe_exec(struct linux_binprm *bprm) |
| 1053 | { | 1072 | { |
| 1054 | struct task_struct *p = current, *t; | 1073 | struct task_struct *p = current, *t; |
| 1055 | unsigned long flags; | 1074 | unsigned n_fs; |
| 1056 | unsigned n_fs, n_files, n_sighand; | 1075 | int res = 0; |
| 1057 | 1076 | ||
| 1058 | bprm->unsafe = tracehook_unsafe_exec(p); | 1077 | bprm->unsafe = tracehook_unsafe_exec(p); |
| 1059 | 1078 | ||
| 1060 | n_fs = 1; | 1079 | n_fs = 1; |
| 1061 | n_files = 1; | 1080 | write_lock(&p->fs->lock); |
| 1062 | n_sighand = 1; | 1081 | rcu_read_lock(); |
| 1063 | lock_task_sighand(p, &flags); | ||
| 1064 | for (t = next_thread(p); t != p; t = next_thread(t)) { | 1082 | for (t = next_thread(p); t != p; t = next_thread(t)) { |
| 1065 | if (t->fs == p->fs) | 1083 | if (t->fs == p->fs) |
| 1066 | n_fs++; | 1084 | n_fs++; |
| 1067 | if (t->files == files) | ||
| 1068 | n_files++; | ||
| 1069 | n_sighand++; | ||
| 1070 | } | 1085 | } |
| 1086 | rcu_read_unlock(); | ||
| 1071 | 1087 | ||
| 1072 | if (atomic_read(&p->fs->count) > n_fs || | 1088 | 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; | 1089 | bprm->unsafe |= LSM_UNSAFE_SHARE; |
| 1090 | } else { | ||
| 1091 | res = -EAGAIN; | ||
| 1092 | if (!p->fs->in_exec) { | ||
| 1093 | p->fs->in_exec = 1; | ||
| 1094 | res = 1; | ||
| 1095 | } | ||
| 1096 | } | ||
| 1097 | write_unlock(&p->fs->lock); | ||
| 1076 | 1098 | ||
| 1077 | unlock_task_sighand(p, &flags); | 1099 | return res; |
| 1078 | } | 1100 | } |
| 1079 | 1101 | ||
| 1080 | /* | 1102 | /* |
| @@ -1184,6 +1206,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
| 1184 | retval = security_bprm_check(bprm); | 1206 | retval = security_bprm_check(bprm); |
| 1185 | if (retval) | 1207 | if (retval) |
| 1186 | return retval; | 1208 | return retval; |
| 1209 | retval = ima_bprm_check(bprm); | ||
| 1210 | if (retval) | ||
| 1211 | return retval; | ||
| 1187 | 1212 | ||
| 1188 | /* kernel module loader fixup */ | 1213 | /* kernel module loader fixup */ |
| 1189 | /* so we don't try to load run modprobe in kernel space. */ | 1214 | /* so we don't try to load run modprobe in kernel space. */ |
| @@ -1251,14 +1276,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
| 1251 | 1276 | ||
| 1252 | EXPORT_SYMBOL(search_binary_handler); | 1277 | EXPORT_SYMBOL(search_binary_handler); |
| 1253 | 1278 | ||
| 1254 | void free_bprm(struct linux_binprm *bprm) | ||
| 1255 | { | ||
| 1256 | free_arg_pages(bprm); | ||
| 1257 | if (bprm->cred) | ||
| 1258 | abort_creds(bprm->cred); | ||
| 1259 | kfree(bprm); | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | /* | 1279 | /* |
| 1263 | * sys_execve() executes a new program. | 1280 | * sys_execve() executes a new program. |
| 1264 | */ | 1281 | */ |
| @@ -1270,6 +1287,7 @@ int do_execve(char * filename, | |||
| 1270 | struct linux_binprm *bprm; | 1287 | struct linux_binprm *bprm; |
| 1271 | struct file *file; | 1288 | struct file *file; |
| 1272 | struct files_struct *displaced; | 1289 | struct files_struct *displaced; |
| 1290 | bool clear_in_exec; | ||
| 1273 | int retval; | 1291 | int retval; |
| 1274 | 1292 | ||
| 1275 | retval = unshare_files(&displaced); | 1293 | retval = unshare_files(&displaced); |
| @@ -1281,20 +1299,20 @@ int do_execve(char * filename, | |||
| 1281 | if (!bprm) | 1299 | if (!bprm) |
| 1282 | goto out_files; | 1300 | goto out_files; |
| 1283 | 1301 | ||
| 1284 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | 1302 | retval = prepare_bprm_creds(bprm); |
| 1285 | if (retval < 0) | 1303 | if (retval) |
| 1286 | goto out_free; | 1304 | goto out_free; |
| 1287 | 1305 | ||
| 1288 | retval = -ENOMEM; | 1306 | retval = check_unsafe_exec(bprm); |
| 1289 | bprm->cred = prepare_exec_creds(); | 1307 | if (retval < 0) |
| 1290 | if (!bprm->cred) | 1308 | goto out_free; |
| 1291 | goto out_unlock; | 1309 | clear_in_exec = retval; |
| 1292 | check_unsafe_exec(bprm, displaced); | 1310 | current->in_execve = 1; |
| 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,7 +1355,8 @@ int do_execve(char * filename, | |||
| 1337 | goto out; | 1355 | goto out; |
| 1338 | 1356 | ||
| 1339 | /* execve succeeded */ | 1357 | /* execve succeeded */ |
| 1340 | mutex_unlock(¤t->cred_exec_mutex); | 1358 | current->fs->in_exec = 0; |
| 1359 | current->in_execve = 0; | ||
| 1341 | acct_update_integrals(current); | 1360 | acct_update_integrals(current); |
| 1342 | free_bprm(bprm); | 1361 | free_bprm(bprm); |
| 1343 | if (displaced) | 1362 | if (displaced) |
| @@ -1354,8 +1373,10 @@ out_file: | |||
| 1354 | fput(bprm->file); | 1373 | fput(bprm->file); |
| 1355 | } | 1374 | } |
| 1356 | 1375 | ||
| 1357 | out_unlock: | 1376 | out_unmark: |
| 1358 | mutex_unlock(¤t->cred_exec_mutex); | 1377 | if (clear_in_exec) |
| 1378 | current->fs->in_exec = 0; | ||
| 1379 | current->in_execve = 0; | ||
| 1359 | 1380 | ||
| 1360 | out_free: | 1381 | out_free: |
| 1361 | free_bprm(bprm); | 1382 | free_bprm(bprm); |
