aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c183
1 files changed, 109 insertions, 74 deletions
diff --git a/fs/exec.c b/fs/exec.c
index ec5df9a38313..1f59ea079cbb 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -55,6 +55,7 @@
55#include <asm/uaccess.h> 55#include <asm/uaccess.h>
56#include <asm/mmu_context.h> 56#include <asm/mmu_context.h>
57#include <asm/tlb.h> 57#include <asm/tlb.h>
58#include "internal.h"
58 59
59#ifdef __alpha__ 60#ifdef __alpha__
60/* for /sbin/loader handling in search_binary_handler() */ 61/* for /sbin/loader handling in search_binary_handler() */
@@ -980,7 +981,7 @@ int flush_old_exec(struct linux_binprm * bprm)
980 /* This is the point of no return */ 981 /* This is the point of no return */
981 current->sas_ss_sp = current->sas_ss_size = 0; 982 current->sas_ss_sp = current->sas_ss_size = 0;
982 983
983 if (current->euid == current->uid && current->egid == current->gid) 984 if (current_euid() == current_uid() && current_egid() == current_gid())
984 set_dumpable(current->mm, 1); 985 set_dumpable(current->mm, 1);
985 else 986 else
986 set_dumpable(current->mm, suid_dumpable); 987 set_dumpable(current->mm, suid_dumpable);
@@ -1007,16 +1008,17 @@ int flush_old_exec(struct linux_binprm * bprm)
1007 */ 1008 */
1008 current->mm->task_size = TASK_SIZE; 1009 current->mm->task_size = TASK_SIZE;
1009 1010
1010 if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) { 1011 /* install the new credentials */
1011 suid_keys(current); 1012 if (bprm->cred->uid != current_euid() ||
1012 set_dumpable(current->mm, suid_dumpable); 1013 bprm->cred->gid != current_egid()) {
1013 current->pdeath_signal = 0; 1014 current->pdeath_signal = 0;
1014 } else if (file_permission(bprm->file, MAY_READ) || 1015 } else if (file_permission(bprm->file, MAY_READ) ||
1015 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { 1016 bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
1016 suid_keys(current);
1017 set_dumpable(current->mm, suid_dumpable); 1017 set_dumpable(current->mm, suid_dumpable);
1018 } 1018 }
1019 1019
1020 current->personality &= ~bprm->per_clear;
1021
1020 /* An exec changes our domain. We are no longer part of the thread 1022 /* An exec changes our domain. We are no longer part of the thread
1021 group */ 1023 group */
1022 1024
@@ -1033,13 +1035,50 @@ out:
1033 1035
1034EXPORT_SYMBOL(flush_old_exec); 1036EXPORT_SYMBOL(flush_old_exec);
1035 1037
1038/*
1039 * install the new credentials for this executable
1040 */
1041void install_exec_creds(struct linux_binprm *bprm)
1042{
1043 security_bprm_committing_creds(bprm);
1044
1045 commit_creds(bprm->cred);
1046 bprm->cred = NULL;
1047
1048 /* cred_exec_mutex must be held at least to this point to prevent
1049 * ptrace_attach() from altering our determination of the task's
1050 * credentials; any time after this it may be unlocked */
1051
1052 security_bprm_committed_creds(bprm);
1053}
1054EXPORT_SYMBOL(install_exec_creds);
1055
1056/*
1057 * determine how safe it is to execute the proposed program
1058 * - the caller must hold current->cred_exec_mutex to protect against
1059 * PTRACE_ATTACH
1060 */
1061void check_unsafe_exec(struct linux_binprm *bprm)
1062{
1063 struct task_struct *p = current;
1064
1065 bprm->unsafe = tracehook_unsafe_exec(p);
1066
1067 if (atomic_read(&p->fs->count) > 1 ||
1068 atomic_read(&p->files->count) > 1 ||
1069 atomic_read(&p->sighand->count) > 1)
1070 bprm->unsafe |= LSM_UNSAFE_SHARE;
1071}
1072
1036/* 1073/*
1037 * Fill the binprm structure from the inode. 1074 * Fill the binprm structure from the inode.
1038 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes 1075 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
1076 *
1077 * This may be called multiple times for binary chains (scripts for example).
1039 */ 1078 */
1040int prepare_binprm(struct linux_binprm *bprm) 1079int prepare_binprm(struct linux_binprm *bprm)
1041{ 1080{
1042 int mode; 1081 umode_t mode;
1043 struct inode * inode = bprm->file->f_path.dentry->d_inode; 1082 struct inode * inode = bprm->file->f_path.dentry->d_inode;
1044 int retval; 1083 int retval;
1045 1084
@@ -1047,14 +1086,15 @@ int prepare_binprm(struct linux_binprm *bprm)
1047 if (bprm->file->f_op == NULL) 1086 if (bprm->file->f_op == NULL)
1048 return -EACCES; 1087 return -EACCES;
1049 1088
1050 bprm->e_uid = current->euid; 1089 /* clear any previous set[ug]id data from a previous binary */
1051 bprm->e_gid = current->egid; 1090 bprm->cred->euid = current_euid();
1091 bprm->cred->egid = current_egid();
1052 1092
1053 if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { 1093 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
1054 /* Set-uid? */ 1094 /* Set-uid? */
1055 if (mode & S_ISUID) { 1095 if (mode & S_ISUID) {
1056 current->personality &= ~PER_CLEAR_ON_SETID; 1096 bprm->per_clear |= PER_CLEAR_ON_SETID;
1057 bprm->e_uid = inode->i_uid; 1097 bprm->cred->euid = inode->i_uid;
1058 } 1098 }
1059 1099
1060 /* Set-gid? */ 1100 /* Set-gid? */
@@ -1064,52 +1104,23 @@ int prepare_binprm(struct linux_binprm *bprm)
1064 * executable. 1104 * executable.
1065 */ 1105 */
1066 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 1106 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
1067 current->personality &= ~PER_CLEAR_ON_SETID; 1107 bprm->per_clear |= PER_CLEAR_ON_SETID;
1068 bprm->e_gid = inode->i_gid; 1108 bprm->cred->egid = inode->i_gid;
1069 } 1109 }
1070 } 1110 }
1071 1111
1072 /* fill in binprm security blob */ 1112 /* fill in binprm security blob */
1073 retval = security_bprm_set(bprm); 1113 retval = security_bprm_set_creds(bprm);
1074 if (retval) 1114 if (retval)
1075 return retval; 1115 return retval;
1116 bprm->cred_prepared = 1;
1076 1117
1077 memset(bprm->buf,0,BINPRM_BUF_SIZE); 1118 memset(bprm->buf, 0, BINPRM_BUF_SIZE);
1078 return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); 1119 return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
1079} 1120}
1080 1121
1081EXPORT_SYMBOL(prepare_binprm); 1122EXPORT_SYMBOL(prepare_binprm);
1082 1123
1083static int unsafe_exec(struct task_struct *p)
1084{
1085 int unsafe = tracehook_unsafe_exec(p);
1086
1087 if (atomic_read(&p->fs->count) > 1 ||
1088 atomic_read(&p->files->count) > 1 ||
1089 atomic_read(&p->sighand->count) > 1)
1090 unsafe |= LSM_UNSAFE_SHARE;
1091
1092 return unsafe;
1093}
1094
1095void compute_creds(struct linux_binprm *bprm)
1096{
1097 int unsafe;
1098
1099 if (bprm->e_uid != current->uid) {
1100 suid_keys(current);
1101 current->pdeath_signal = 0;
1102 }
1103 exec_keys(current);
1104
1105 task_lock(current);
1106 unsafe = unsafe_exec(current);
1107 security_bprm_apply_creds(bprm, unsafe);
1108 task_unlock(current);
1109 security_bprm_post_apply_creds(bprm);
1110}
1111EXPORT_SYMBOL(compute_creds);
1112
1113/* 1124/*
1114 * Arguments are '\0' separated strings found at the location bprm->p 1125 * Arguments are '\0' separated strings found at the location bprm->p
1115 * points to; chop off the first by relocating brpm->p to right after 1126 * points to; chop off the first by relocating brpm->p to right after
@@ -1270,6 +1281,8 @@ EXPORT_SYMBOL(search_binary_handler);
1270void free_bprm(struct linux_binprm *bprm) 1281void free_bprm(struct linux_binprm *bprm)
1271{ 1282{
1272 free_arg_pages(bprm); 1283 free_arg_pages(bprm);
1284 if (bprm->cred)
1285 abort_creds(bprm->cred);
1273 kfree(bprm); 1286 kfree(bprm);
1274} 1287}
1275 1288
@@ -1295,10 +1308,20 @@ int do_execve(char * filename,
1295 if (!bprm) 1308 if (!bprm)
1296 goto out_files; 1309 goto out_files;
1297 1310
1311 retval = mutex_lock_interruptible(&current->cred_exec_mutex);
1312 if (retval < 0)
1313 goto out_free;
1314
1315 retval = -ENOMEM;
1316 bprm->cred = prepare_exec_creds();
1317 if (!bprm->cred)
1318 goto out_unlock;
1319 check_unsafe_exec(bprm);
1320
1298 file = open_exec(filename); 1321 file = open_exec(filename);
1299 retval = PTR_ERR(file); 1322 retval = PTR_ERR(file);
1300 if (IS_ERR(file)) 1323 if (IS_ERR(file))
1301 goto out_kfree; 1324 goto out_unlock;
1302 1325
1303 sched_exec(); 1326 sched_exec();
1304 1327
@@ -1312,14 +1335,10 @@ int do_execve(char * filename,
1312 1335
1313 bprm->argc = count(argv, MAX_ARG_STRINGS); 1336 bprm->argc = count(argv, MAX_ARG_STRINGS);
1314 if ((retval = bprm->argc) < 0) 1337 if ((retval = bprm->argc) < 0)
1315 goto out_mm; 1338 goto out;
1316 1339
1317 bprm->envc = count(envp, MAX_ARG_STRINGS); 1340 bprm->envc = count(envp, MAX_ARG_STRINGS);
1318 if ((retval = bprm->envc) < 0) 1341 if ((retval = bprm->envc) < 0)
1319 goto out_mm;
1320
1321 retval = security_bprm_alloc(bprm);
1322 if (retval)
1323 goto out; 1342 goto out;
1324 1343
1325 retval = prepare_binprm(bprm); 1344 retval = prepare_binprm(bprm);
@@ -1341,21 +1360,18 @@ int do_execve(char * filename,
1341 1360
1342 current->flags &= ~PF_KTHREAD; 1361 current->flags &= ~PF_KTHREAD;
1343 retval = search_binary_handler(bprm,regs); 1362 retval = search_binary_handler(bprm,regs);
1344 if (retval >= 0) { 1363 if (retval < 0)
1345 /* execve success */ 1364 goto out;
1346 security_bprm_free(bprm);
1347 acct_update_integrals(current);
1348 free_bprm(bprm);
1349 if (displaced)
1350 put_files_struct(displaced);
1351 return retval;
1352 }
1353 1365
1354out: 1366 /* execve succeeded */
1355 if (bprm->security) 1367 mutex_unlock(&current->cred_exec_mutex);
1356 security_bprm_free(bprm); 1368 acct_update_integrals(current);
1369 free_bprm(bprm);
1370 if (displaced)
1371 put_files_struct(displaced);
1372 return retval;
1357 1373
1358out_mm: 1374out:
1359 if (bprm->mm) 1375 if (bprm->mm)
1360 mmput (bprm->mm); 1376 mmput (bprm->mm);
1361 1377
@@ -1364,7 +1380,11 @@ out_file:
1364 allow_write_access(bprm->file); 1380 allow_write_access(bprm->file);
1365 fput(bprm->file); 1381 fput(bprm->file);
1366 } 1382 }
1367out_kfree: 1383
1384out_unlock:
1385 mutex_unlock(&current->cred_exec_mutex);
1386
1387out_free:
1368 free_bprm(bprm); 1388 free_bprm(bprm);
1369 1389
1370out_files: 1390out_files:
@@ -1396,6 +1416,7 @@ EXPORT_SYMBOL(set_binfmt);
1396 */ 1416 */
1397static int format_corename(char *corename, long signr) 1417static int format_corename(char *corename, long signr)
1398{ 1418{
1419 const struct cred *cred = current_cred();
1399 const char *pat_ptr = core_pattern; 1420 const char *pat_ptr = core_pattern;
1400 int ispipe = (*pat_ptr == '|'); 1421 int ispipe = (*pat_ptr == '|');
1401 char *out_ptr = corename; 1422 char *out_ptr = corename;
@@ -1432,7 +1453,7 @@ static int format_corename(char *corename, long signr)
1432 /* uid */ 1453 /* uid */
1433 case 'u': 1454 case 'u':
1434 rc = snprintf(out_ptr, out_end - out_ptr, 1455 rc = snprintf(out_ptr, out_end - out_ptr,
1435 "%d", current->uid); 1456 "%d", cred->uid);
1436 if (rc > out_end - out_ptr) 1457 if (rc > out_end - out_ptr)
1437 goto out; 1458 goto out;
1438 out_ptr += rc; 1459 out_ptr += rc;
@@ -1440,7 +1461,7 @@ static int format_corename(char *corename, long signr)
1440 /* gid */ 1461 /* gid */
1441 case 'g': 1462 case 'g':
1442 rc = snprintf(out_ptr, out_end - out_ptr, 1463 rc = snprintf(out_ptr, out_end - out_ptr,
1443 "%d", current->gid); 1464 "%d", cred->gid);
1444 if (rc > out_end - out_ptr) 1465 if (rc > out_end - out_ptr)
1445 goto out; 1466 goto out;
1446 out_ptr += rc; 1467 out_ptr += rc;
@@ -1716,8 +1737,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1716 struct linux_binfmt * binfmt; 1737 struct linux_binfmt * binfmt;
1717 struct inode * inode; 1738 struct inode * inode;
1718 struct file * file; 1739 struct file * file;
1740 const struct cred *old_cred;
1741 struct cred *cred;
1719 int retval = 0; 1742 int retval = 0;
1720 int fsuid = current->fsuid;
1721 int flag = 0; 1743 int flag = 0;
1722 int ispipe = 0; 1744 int ispipe = 0;
1723 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; 1745 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1730,12 +1752,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1730 binfmt = current->binfmt; 1752 binfmt = current->binfmt;
1731 if (!binfmt || !binfmt->core_dump) 1753 if (!binfmt || !binfmt->core_dump)
1732 goto fail; 1754 goto fail;
1755
1756 cred = prepare_creds();
1757 if (!cred) {
1758 retval = -ENOMEM;
1759 goto fail;
1760 }
1761
1733 down_write(&mm->mmap_sem); 1762 down_write(&mm->mmap_sem);
1734 /* 1763 /*
1735 * If another thread got here first, or we are not dumpable, bail out. 1764 * If another thread got here first, or we are not dumpable, bail out.
1736 */ 1765 */
1737 if (mm->core_state || !get_dumpable(mm)) { 1766 if (mm->core_state || !get_dumpable(mm)) {
1738 up_write(&mm->mmap_sem); 1767 up_write(&mm->mmap_sem);
1768 put_cred(cred);
1739 goto fail; 1769 goto fail;
1740 } 1770 }
1741 1771
@@ -1746,12 +1776,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1746 */ 1776 */
1747 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ 1777 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
1748 flag = O_EXCL; /* Stop rewrite attacks */ 1778 flag = O_EXCL; /* Stop rewrite attacks */
1749 current->fsuid = 0; /* Dump root private */ 1779 cred->fsuid = 0; /* Dump root private */
1750 } 1780 }
1751 1781
1752 retval = coredump_wait(exit_code, &core_state); 1782 retval = coredump_wait(exit_code, &core_state);
1753 if (retval < 0) 1783 if (retval < 0) {
1784 put_cred(cred);
1754 goto fail; 1785 goto fail;
1786 }
1787
1788 old_cred = override_creds(cred);
1755 1789
1756 /* 1790 /*
1757 * Clear any false indication of pending signals that might 1791 * Clear any false indication of pending signals that might
@@ -1823,7 +1857,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1823 * Dont allow local users get cute and trick others to coredump 1857 * Dont allow local users get cute and trick others to coredump
1824 * into their pre-created files: 1858 * into their pre-created files:
1825 */ 1859 */
1826 if (inode->i_uid != current->fsuid) 1860 if (inode->i_uid != current_fsuid())
1827 goto close_fail; 1861 goto close_fail;
1828 if (!file->f_op) 1862 if (!file->f_op)
1829 goto close_fail; 1863 goto close_fail;
@@ -1842,7 +1876,8 @@ fail_unlock:
1842 if (helper_argv) 1876 if (helper_argv)
1843 argv_free(helper_argv); 1877 argv_free(helper_argv);
1844 1878
1845 current->fsuid = fsuid; 1879 revert_creds(old_cred);
1880 put_cred(cred);
1846 coredump_finish(mm); 1881 coredump_finish(mm);
1847fail: 1882fail:
1848 return retval; 1883 return retval;