diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 78 |
1 files changed, 50 insertions, 28 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> |
@@ -677,8 +678,8 @@ exit: | |||
677 | } | 678 | } |
678 | EXPORT_SYMBOL(open_exec); | 679 | EXPORT_SYMBOL(open_exec); |
679 | 680 | ||
680 | int kernel_read(struct file *file, unsigned long offset, | 681 | int kernel_read(struct file *file, loff_t offset, |
681 | char *addr, unsigned long count) | 682 | char *addr, unsigned long count) |
682 | { | 683 | { |
683 | mm_segment_t old_fs; | 684 | mm_segment_t old_fs; |
684 | loff_t pos = offset; | 685 | loff_t pos = offset; |
@@ -922,6 +923,7 @@ void set_task_comm(struct task_struct *tsk, char *buf) | |||
922 | task_lock(tsk); | 923 | task_lock(tsk); |
923 | strlcpy(tsk->comm, buf, sizeof(tsk->comm)); | 924 | strlcpy(tsk->comm, buf, sizeof(tsk->comm)); |
924 | task_unlock(tsk); | 925 | task_unlock(tsk); |
926 | perf_counter_comm(tsk); | ||
925 | } | 927 | } |
926 | 928 | ||
927 | int flush_old_exec(struct linux_binprm * bprm) | 929 | int flush_old_exec(struct linux_binprm * bprm) |
@@ -990,6 +992,13 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
990 | 992 | ||
991 | current->personality &= ~bprm->per_clear; | 993 | current->personality &= ~bprm->per_clear; |
992 | 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 | |||
993 | /* 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 |
994 | group */ | 1003 | group */ |
995 | 1004 | ||
@@ -1007,6 +1016,35 @@ out: | |||
1007 | EXPORT_SYMBOL(flush_old_exec); | 1016 | EXPORT_SYMBOL(flush_old_exec); |
1008 | 1017 | ||
1009 | /* | 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 | /* | ||
1010 | * install the new credentials for this executable | 1048 | * install the new credentials for this executable |
1011 | */ | 1049 | */ |
1012 | void install_exec_creds(struct linux_binprm *bprm) | 1050 | void install_exec_creds(struct linux_binprm *bprm) |
@@ -1015,18 +1053,19 @@ void install_exec_creds(struct linux_binprm *bprm) | |||
1015 | 1053 | ||
1016 | commit_creds(bprm->cred); | 1054 | commit_creds(bprm->cred); |
1017 | bprm->cred = NULL; | 1055 | bprm->cred = NULL; |
1018 | 1056 | /* | |
1019 | /* 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 |
1020 | * ptrace_attach() from altering our determination of the task's | 1058 | * ptrace_attach() from altering our determination of the task's |
1021 | * credentials; any time after this it may be unlocked */ | 1059 | * credentials; any time after this it may be unlocked. |
1022 | 1060 | */ | |
1023 | security_bprm_committed_creds(bprm); | 1061 | security_bprm_committed_creds(bprm); |
1062 | mutex_unlock(¤t->cred_guard_mutex); | ||
1024 | } | 1063 | } |
1025 | EXPORT_SYMBOL(install_exec_creds); | 1064 | EXPORT_SYMBOL(install_exec_creds); |
1026 | 1065 | ||
1027 | /* | 1066 | /* |
1028 | * determine how safe it is to execute the proposed program | 1067 | * determine how safe it is to execute the proposed program |
1029 | * - the caller must hold current->cred_exec_mutex to protect against | 1068 | * - the caller must hold current->cred_guard_mutex to protect against |
1030 | * PTRACE_ATTACH | 1069 | * PTRACE_ATTACH |
1031 | */ | 1070 | */ |
1032 | int check_unsafe_exec(struct linux_binprm *bprm) | 1071 | int check_unsafe_exec(struct linux_binprm *bprm) |
@@ -1237,14 +1276,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1237 | 1276 | ||
1238 | EXPORT_SYMBOL(search_binary_handler); | 1277 | EXPORT_SYMBOL(search_binary_handler); |
1239 | 1278 | ||
1240 | void free_bprm(struct linux_binprm *bprm) | ||
1241 | { | ||
1242 | free_arg_pages(bprm); | ||
1243 | if (bprm->cred) | ||
1244 | abort_creds(bprm->cred); | ||
1245 | kfree(bprm); | ||
1246 | } | ||
1247 | |||
1248 | /* | 1279 | /* |
1249 | * sys_execve() executes a new program. | 1280 | * sys_execve() executes a new program. |
1250 | */ | 1281 | */ |
@@ -1268,20 +1299,15 @@ int do_execve(char * filename, | |||
1268 | if (!bprm) | 1299 | if (!bprm) |
1269 | goto out_files; | 1300 | goto out_files; |
1270 | 1301 | ||
1271 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | 1302 | retval = prepare_bprm_creds(bprm); |
1272 | if (retval < 0) | 1303 | if (retval) |
1273 | goto out_free; | 1304 | goto out_free; |
1274 | current->in_execve = 1; | ||
1275 | |||
1276 | retval = -ENOMEM; | ||
1277 | bprm->cred = prepare_exec_creds(); | ||
1278 | if (!bprm->cred) | ||
1279 | goto out_unlock; | ||
1280 | 1305 | ||
1281 | retval = check_unsafe_exec(bprm); | 1306 | retval = check_unsafe_exec(bprm); |
1282 | if (retval < 0) | 1307 | if (retval < 0) |
1283 | goto out_unlock; | 1308 | goto out_free; |
1284 | clear_in_exec = retval; | 1309 | clear_in_exec = retval; |
1310 | current->in_execve = 1; | ||
1285 | 1311 | ||
1286 | file = open_exec(filename); | 1312 | file = open_exec(filename); |
1287 | retval = PTR_ERR(file); | 1313 | retval = PTR_ERR(file); |
@@ -1331,7 +1357,6 @@ int do_execve(char * filename, | |||
1331 | /* execve succeeded */ | 1357 | /* execve succeeded */ |
1332 | current->fs->in_exec = 0; | 1358 | current->fs->in_exec = 0; |
1333 | current->in_execve = 0; | 1359 | current->in_execve = 0; |
1334 | mutex_unlock(¤t->cred_exec_mutex); | ||
1335 | acct_update_integrals(current); | 1360 | acct_update_integrals(current); |
1336 | free_bprm(bprm); | 1361 | free_bprm(bprm); |
1337 | if (displaced) | 1362 | if (displaced) |
@@ -1351,10 +1376,7 @@ out_file: | |||
1351 | out_unmark: | 1376 | out_unmark: |
1352 | if (clear_in_exec) | 1377 | if (clear_in_exec) |
1353 | current->fs->in_exec = 0; | 1378 | current->fs->in_exec = 0; |
1354 | |||
1355 | out_unlock: | ||
1356 | current->in_execve = 0; | 1379 | current->in_execve = 0; |
1357 | mutex_unlock(¤t->cred_exec_mutex); | ||
1358 | 1380 | ||
1359 | out_free: | 1381 | out_free: |
1360 | free_bprm(bprm); | 1382 | free_bprm(bprm); |