aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorMike Travis <travis@sgi.com>2008-12-31 20:34:16 -0500
committerIngo Molnar <mingo@elte.hu>2009-01-03 12:53:31 -0500
commit7eb19553369c46cc1fa64caf120cbcab1b597f7c (patch)
treeef1a3beae706b9497c845d0a2557ceb4d2754998 /fs/exec.c
parent6092848a2a23b660150a38bc06f59d75838d70c8 (diff)
parent8c384cdee3e04d6194a2c2b192b624754f990835 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-cpumask into merge-rr-cpumask
Conflicts: arch/x86/kernel/io_apic.c kernel/rcuclassic.c kernel/sched.c kernel/time/tick-sched.c Signed-off-by: Mike Travis <travis@sgi.com> [ mingo@elte.hu: backmerged typo fix for io_apic.c ] Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c191
1 files changed, 112 insertions, 79 deletions
diff --git a/fs/exec.c b/fs/exec.c
index ec5df9a38313..02d2e120542d 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() */
@@ -772,7 +773,6 @@ static int de_thread(struct task_struct *tsk)
772 struct signal_struct *sig = tsk->signal; 773 struct signal_struct *sig = tsk->signal;
773 struct sighand_struct *oldsighand = tsk->sighand; 774 struct sighand_struct *oldsighand = tsk->sighand;
774 spinlock_t *lock = &oldsighand->siglock; 775 spinlock_t *lock = &oldsighand->siglock;
775 struct task_struct *leader = NULL;
776 int count; 776 int count;
777 777
778 if (thread_group_empty(tsk)) 778 if (thread_group_empty(tsk))
@@ -810,7 +810,7 @@ static int de_thread(struct task_struct *tsk)
810 * and to assume its PID: 810 * and to assume its PID:
811 */ 811 */
812 if (!thread_group_leader(tsk)) { 812 if (!thread_group_leader(tsk)) {
813 leader = tsk->group_leader; 813 struct task_struct *leader = tsk->group_leader;
814 814
815 sig->notify_count = -1; /* for exit_notify() */ 815 sig->notify_count = -1; /* for exit_notify() */
816 for (;;) { 816 for (;;) {
@@ -862,8 +862,9 @@ static int de_thread(struct task_struct *tsk)
862 862
863 BUG_ON(leader->exit_state != EXIT_ZOMBIE); 863 BUG_ON(leader->exit_state != EXIT_ZOMBIE);
864 leader->exit_state = EXIT_DEAD; 864 leader->exit_state = EXIT_DEAD;
865
866 write_unlock_irq(&tasklist_lock); 865 write_unlock_irq(&tasklist_lock);
866
867 release_task(leader);
867 } 868 }
868 869
869 sig->group_exit_task = NULL; 870 sig->group_exit_task = NULL;
@@ -872,8 +873,6 @@ static int de_thread(struct task_struct *tsk)
872no_thread_group: 873no_thread_group:
873 exit_itimers(sig); 874 exit_itimers(sig);
874 flush_itimer_signals(); 875 flush_itimer_signals();
875 if (leader)
876 release_task(leader);
877 876
878 if (atomic_read(&oldsighand->count) != 1) { 877 if (atomic_read(&oldsighand->count) != 1) {
879 struct sighand_struct *newsighand; 878 struct sighand_struct *newsighand;
@@ -980,7 +979,7 @@ int flush_old_exec(struct linux_binprm * bprm)
980 /* This is the point of no return */ 979 /* This is the point of no return */
981 current->sas_ss_sp = current->sas_ss_size = 0; 980 current->sas_ss_sp = current->sas_ss_size = 0;
982 981
983 if (current->euid == current->uid && current->egid == current->gid) 982 if (current_euid() == current_uid() && current_egid() == current_gid())
984 set_dumpable(current->mm, 1); 983 set_dumpable(current->mm, 1);
985 else 984 else
986 set_dumpable(current->mm, suid_dumpable); 985 set_dumpable(current->mm, suid_dumpable);
@@ -1007,16 +1006,17 @@ int flush_old_exec(struct linux_binprm * bprm)
1007 */ 1006 */
1008 current->mm->task_size = TASK_SIZE; 1007 current->mm->task_size = TASK_SIZE;
1009 1008
1010 if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) { 1009 /* install the new credentials */
1011 suid_keys(current); 1010 if (bprm->cred->uid != current_euid() ||
1012 set_dumpable(current->mm, suid_dumpable); 1011 bprm->cred->gid != current_egid()) {
1013 current->pdeath_signal = 0; 1012 current->pdeath_signal = 0;
1014 } else if (file_permission(bprm->file, MAY_READ) || 1013 } else if (file_permission(bprm->file, MAY_READ) ||
1015 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { 1014 bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
1016 suid_keys(current);
1017 set_dumpable(current->mm, suid_dumpable); 1015 set_dumpable(current->mm, suid_dumpable);
1018 } 1016 }
1019 1017
1018 current->personality &= ~bprm->per_clear;
1019
1020 /* An exec changes our domain. We are no longer part of the thread 1020 /* An exec changes our domain. We are no longer part of the thread
1021 group */ 1021 group */
1022 1022
@@ -1033,13 +1033,50 @@ out:
1033 1033
1034EXPORT_SYMBOL(flush_old_exec); 1034EXPORT_SYMBOL(flush_old_exec);
1035 1035
1036/*
1037 * install the new credentials for this executable
1038 */
1039void install_exec_creds(struct linux_binprm *bprm)
1040{
1041 security_bprm_committing_creds(bprm);
1042
1043 commit_creds(bprm->cred);
1044 bprm->cred = NULL;
1045
1046 /* cred_exec_mutex must be held at least to this point to prevent
1047 * ptrace_attach() from altering our determination of the task's
1048 * credentials; any time after this it may be unlocked */
1049
1050 security_bprm_committed_creds(bprm);
1051}
1052EXPORT_SYMBOL(install_exec_creds);
1053
1054/*
1055 * determine how safe it is to execute the proposed program
1056 * - the caller must hold current->cred_exec_mutex to protect against
1057 * PTRACE_ATTACH
1058 */
1059void check_unsafe_exec(struct linux_binprm *bprm)
1060{
1061 struct task_struct *p = current;
1062
1063 bprm->unsafe = tracehook_unsafe_exec(p);
1064
1065 if (atomic_read(&p->fs->count) > 1 ||
1066 atomic_read(&p->files->count) > 1 ||
1067 atomic_read(&p->sighand->count) > 1)
1068 bprm->unsafe |= LSM_UNSAFE_SHARE;
1069}
1070
1036/* 1071/*
1037 * Fill the binprm structure from the inode. 1072 * Fill the binprm structure from the inode.
1038 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes 1073 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
1074 *
1075 * This may be called multiple times for binary chains (scripts for example).
1039 */ 1076 */
1040int prepare_binprm(struct linux_binprm *bprm) 1077int prepare_binprm(struct linux_binprm *bprm)
1041{ 1078{
1042 int mode; 1079 umode_t mode;
1043 struct inode * inode = bprm->file->f_path.dentry->d_inode; 1080 struct inode * inode = bprm->file->f_path.dentry->d_inode;
1044 int retval; 1081 int retval;
1045 1082
@@ -1047,14 +1084,15 @@ int prepare_binprm(struct linux_binprm *bprm)
1047 if (bprm->file->f_op == NULL) 1084 if (bprm->file->f_op == NULL)
1048 return -EACCES; 1085 return -EACCES;
1049 1086
1050 bprm->e_uid = current->euid; 1087 /* clear any previous set[ug]id data from a previous binary */
1051 bprm->e_gid = current->egid; 1088 bprm->cred->euid = current_euid();
1089 bprm->cred->egid = current_egid();
1052 1090
1053 if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { 1091 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
1054 /* Set-uid? */ 1092 /* Set-uid? */
1055 if (mode & S_ISUID) { 1093 if (mode & S_ISUID) {
1056 current->personality &= ~PER_CLEAR_ON_SETID; 1094 bprm->per_clear |= PER_CLEAR_ON_SETID;
1057 bprm->e_uid = inode->i_uid; 1095 bprm->cred->euid = inode->i_uid;
1058 } 1096 }
1059 1097
1060 /* Set-gid? */ 1098 /* Set-gid? */
@@ -1064,52 +1102,23 @@ int prepare_binprm(struct linux_binprm *bprm)
1064 * executable. 1102 * executable.
1065 */ 1103 */
1066 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 1104 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
1067 current->personality &= ~PER_CLEAR_ON_SETID; 1105 bprm->per_clear |= PER_CLEAR_ON_SETID;
1068 bprm->e_gid = inode->i_gid; 1106 bprm->cred->egid = inode->i_gid;
1069 } 1107 }
1070 } 1108 }
1071 1109
1072 /* fill in binprm security blob */ 1110 /* fill in binprm security blob */
1073 retval = security_bprm_set(bprm); 1111 retval = security_bprm_set_creds(bprm);
1074 if (retval) 1112 if (retval)
1075 return retval; 1113 return retval;
1114 bprm->cred_prepared = 1;
1076 1115
1077 memset(bprm->buf,0,BINPRM_BUF_SIZE); 1116 memset(bprm->buf, 0, BINPRM_BUF_SIZE);
1078 return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); 1117 return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
1079} 1118}
1080 1119
1081EXPORT_SYMBOL(prepare_binprm); 1120EXPORT_SYMBOL(prepare_binprm);
1082 1121
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/* 1122/*
1114 * Arguments are '\0' separated strings found at the location bprm->p 1123 * 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 1124 * points to; chop off the first by relocating brpm->p to right after
@@ -1270,6 +1279,8 @@ EXPORT_SYMBOL(search_binary_handler);
1270void free_bprm(struct linux_binprm *bprm) 1279void free_bprm(struct linux_binprm *bprm)
1271{ 1280{
1272 free_arg_pages(bprm); 1281 free_arg_pages(bprm);
1282 if (bprm->cred)
1283 abort_creds(bprm->cred);
1273 kfree(bprm); 1284 kfree(bprm);
1274} 1285}
1275 1286
@@ -1295,10 +1306,20 @@ int do_execve(char * filename,
1295 if (!bprm) 1306 if (!bprm)
1296 goto out_files; 1307 goto out_files;
1297 1308
1309 retval = mutex_lock_interruptible(&current->cred_exec_mutex);
1310 if (retval < 0)
1311 goto out_free;
1312
1313 retval = -ENOMEM;
1314 bprm->cred = prepare_exec_creds();
1315 if (!bprm->cred)
1316 goto out_unlock;
1317 check_unsafe_exec(bprm);
1318
1298 file = open_exec(filename); 1319 file = open_exec(filename);
1299 retval = PTR_ERR(file); 1320 retval = PTR_ERR(file);
1300 if (IS_ERR(file)) 1321 if (IS_ERR(file))
1301 goto out_kfree; 1322 goto out_unlock;
1302 1323
1303 sched_exec(); 1324 sched_exec();
1304 1325
@@ -1312,14 +1333,10 @@ int do_execve(char * filename,
1312 1333
1313 bprm->argc = count(argv, MAX_ARG_STRINGS); 1334 bprm->argc = count(argv, MAX_ARG_STRINGS);
1314 if ((retval = bprm->argc) < 0) 1335 if ((retval = bprm->argc) < 0)
1315 goto out_mm; 1336 goto out;
1316 1337
1317 bprm->envc = count(envp, MAX_ARG_STRINGS); 1338 bprm->envc = count(envp, MAX_ARG_STRINGS);
1318 if ((retval = bprm->envc) < 0) 1339 if ((retval = bprm->envc) < 0)
1319 goto out_mm;
1320
1321 retval = security_bprm_alloc(bprm);
1322 if (retval)
1323 goto out; 1340 goto out;
1324 1341
1325 retval = prepare_binprm(bprm); 1342 retval = prepare_binprm(bprm);
@@ -1341,21 +1358,18 @@ int do_execve(char * filename,
1341 1358
1342 current->flags &= ~PF_KTHREAD; 1359 current->flags &= ~PF_KTHREAD;
1343 retval = search_binary_handler(bprm,regs); 1360 retval = search_binary_handler(bprm,regs);
1344 if (retval >= 0) { 1361 if (retval < 0)
1345 /* execve success */ 1362 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 1363
1354out: 1364 /* execve succeeded */
1355 if (bprm->security) 1365 mutex_unlock(&current->cred_exec_mutex);
1356 security_bprm_free(bprm); 1366 acct_update_integrals(current);
1367 free_bprm(bprm);
1368 if (displaced)
1369 put_files_struct(displaced);
1370 return retval;
1357 1371
1358out_mm: 1372out:
1359 if (bprm->mm) 1373 if (bprm->mm)
1360 mmput (bprm->mm); 1374 mmput (bprm->mm);
1361 1375
@@ -1364,7 +1378,11 @@ out_file:
1364 allow_write_access(bprm->file); 1378 allow_write_access(bprm->file);
1365 fput(bprm->file); 1379 fput(bprm->file);
1366 } 1380 }
1367out_kfree: 1381
1382out_unlock:
1383 mutex_unlock(&current->cred_exec_mutex);
1384
1385out_free:
1368 free_bprm(bprm); 1386 free_bprm(bprm);
1369 1387
1370out_files: 1388out_files:
@@ -1396,6 +1414,7 @@ EXPORT_SYMBOL(set_binfmt);
1396 */ 1414 */
1397static int format_corename(char *corename, long signr) 1415static int format_corename(char *corename, long signr)
1398{ 1416{
1417 const struct cred *cred = current_cred();
1399 const char *pat_ptr = core_pattern; 1418 const char *pat_ptr = core_pattern;
1400 int ispipe = (*pat_ptr == '|'); 1419 int ispipe = (*pat_ptr == '|');
1401 char *out_ptr = corename; 1420 char *out_ptr = corename;
@@ -1432,7 +1451,7 @@ static int format_corename(char *corename, long signr)
1432 /* uid */ 1451 /* uid */
1433 case 'u': 1452 case 'u':
1434 rc = snprintf(out_ptr, out_end - out_ptr, 1453 rc = snprintf(out_ptr, out_end - out_ptr,
1435 "%d", current->uid); 1454 "%d", cred->uid);
1436 if (rc > out_end - out_ptr) 1455 if (rc > out_end - out_ptr)
1437 goto out; 1456 goto out;
1438 out_ptr += rc; 1457 out_ptr += rc;
@@ -1440,7 +1459,7 @@ static int format_corename(char *corename, long signr)
1440 /* gid */ 1459 /* gid */
1441 case 'g': 1460 case 'g':
1442 rc = snprintf(out_ptr, out_end - out_ptr, 1461 rc = snprintf(out_ptr, out_end - out_ptr,
1443 "%d", current->gid); 1462 "%d", cred->gid);
1444 if (rc > out_end - out_ptr) 1463 if (rc > out_end - out_ptr)
1445 goto out; 1464 goto out;
1446 out_ptr += rc; 1465 out_ptr += rc;
@@ -1716,8 +1735,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1716 struct linux_binfmt * binfmt; 1735 struct linux_binfmt * binfmt;
1717 struct inode * inode; 1736 struct inode * inode;
1718 struct file * file; 1737 struct file * file;
1738 const struct cred *old_cred;
1739 struct cred *cred;
1719 int retval = 0; 1740 int retval = 0;
1720 int fsuid = current->fsuid;
1721 int flag = 0; 1741 int flag = 0;
1722 int ispipe = 0; 1742 int ispipe = 0;
1723 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; 1743 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1730,12 +1750,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1730 binfmt = current->binfmt; 1750 binfmt = current->binfmt;
1731 if (!binfmt || !binfmt->core_dump) 1751 if (!binfmt || !binfmt->core_dump)
1732 goto fail; 1752 goto fail;
1753
1754 cred = prepare_creds();
1755 if (!cred) {
1756 retval = -ENOMEM;
1757 goto fail;
1758 }
1759
1733 down_write(&mm->mmap_sem); 1760 down_write(&mm->mmap_sem);
1734 /* 1761 /*
1735 * If another thread got here first, or we are not dumpable, bail out. 1762 * If another thread got here first, or we are not dumpable, bail out.
1736 */ 1763 */
1737 if (mm->core_state || !get_dumpable(mm)) { 1764 if (mm->core_state || !get_dumpable(mm)) {
1738 up_write(&mm->mmap_sem); 1765 up_write(&mm->mmap_sem);
1766 put_cred(cred);
1739 goto fail; 1767 goto fail;
1740 } 1768 }
1741 1769
@@ -1746,12 +1774,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1746 */ 1774 */
1747 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ 1775 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
1748 flag = O_EXCL; /* Stop rewrite attacks */ 1776 flag = O_EXCL; /* Stop rewrite attacks */
1749 current->fsuid = 0; /* Dump root private */ 1777 cred->fsuid = 0; /* Dump root private */
1750 } 1778 }
1751 1779
1752 retval = coredump_wait(exit_code, &core_state); 1780 retval = coredump_wait(exit_code, &core_state);
1753 if (retval < 0) 1781 if (retval < 0) {
1782 put_cred(cred);
1754 goto fail; 1783 goto fail;
1784 }
1785
1786 old_cred = override_creds(cred);
1755 1787
1756 /* 1788 /*
1757 * Clear any false indication of pending signals that might 1789 * Clear any false indication of pending signals that might
@@ -1823,7 +1855,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 1855 * Dont allow local users get cute and trick others to coredump
1824 * into their pre-created files: 1856 * into their pre-created files:
1825 */ 1857 */
1826 if (inode->i_uid != current->fsuid) 1858 if (inode->i_uid != current_fsuid())
1827 goto close_fail; 1859 goto close_fail;
1828 if (!file->f_op) 1860 if (!file->f_op)
1829 goto close_fail; 1861 goto close_fail;
@@ -1842,7 +1874,8 @@ fail_unlock:
1842 if (helper_argv) 1874 if (helper_argv)
1843 argv_free(helper_argv); 1875 argv_free(helper_argv);
1844 1876
1845 current->fsuid = fsuid; 1877 revert_creds(old_cred);
1878 put_cred(cred);
1846 coredump_finish(mm); 1879 coredump_finish(mm);
1847fail: 1880fail:
1848 return retval; 1881 return retval;