aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c271
1 files changed, 134 insertions, 137 deletions
diff --git a/fs/exec.c b/fs/exec.c
index ec5df9a38313..0dd60a01f1b4 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -51,15 +51,12 @@
51#include <linux/audit.h> 51#include <linux/audit.h>
52#include <linux/tracehook.h> 52#include <linux/tracehook.h>
53#include <linux/kmod.h> 53#include <linux/kmod.h>
54#include <linux/fsnotify.h>
54 55
55#include <asm/uaccess.h> 56#include <asm/uaccess.h>
56#include <asm/mmu_context.h> 57#include <asm/mmu_context.h>
57#include <asm/tlb.h> 58#include <asm/tlb.h>
58 59#include "internal.h"
59#ifdef __alpha__
60/* for /sbin/loader handling in search_binary_handler() */
61#include <linux/a.out.h>
62#endif
63 60
64int core_uses_pid; 61int core_uses_pid;
65char core_pattern[CORENAME_MAX_SIZE] = "core"; 62char core_pattern[CORENAME_MAX_SIZE] = "core";
@@ -102,7 +99,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
102 * 99 *
103 * Also note that we take the address to load from from the file itself. 100 * Also note that we take the address to load from from the file itself.
104 */ 101 */
105asmlinkage long sys_uselib(const char __user * library) 102SYSCALL_DEFINE1(uselib, const char __user *, library)
106{ 103{
107 struct file *file; 104 struct file *file;
108 struct nameidata nd; 105 struct nameidata nd;
@@ -126,7 +123,8 @@ asmlinkage long sys_uselib(const char __user * library)
126 if (nd.path.mnt->mnt_flags & MNT_NOEXEC) 123 if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
127 goto exit; 124 goto exit;
128 125
129 error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN); 126 error = inode_permission(nd.path.dentry->d_inode,
127 MAY_READ | MAY_EXEC | MAY_OPEN);
130 if (error) 128 if (error)
131 goto exit; 129 goto exit;
132 130
@@ -135,6 +133,8 @@ asmlinkage long sys_uselib(const char __user * library)
135 if (IS_ERR(file)) 133 if (IS_ERR(file))
136 goto out; 134 goto out;
137 135
136 fsnotify_open(file->f_path.dentry);
137
138 error = -ENOEXEC; 138 error = -ENOEXEC;
139 if(file->f_op) { 139 if(file->f_op) {
140 struct linux_binfmt * fmt; 140 struct linux_binfmt * fmt;
@@ -232,13 +232,13 @@ static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
232 232
233static int __bprm_mm_init(struct linux_binprm *bprm) 233static int __bprm_mm_init(struct linux_binprm *bprm)
234{ 234{
235 int err = -ENOMEM; 235 int err;
236 struct vm_area_struct *vma = NULL; 236 struct vm_area_struct *vma = NULL;
237 struct mm_struct *mm = bprm->mm; 237 struct mm_struct *mm = bprm->mm;
238 238
239 bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); 239 bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
240 if (!vma) 240 if (!vma)
241 goto err; 241 return -ENOMEM;
242 242
243 down_write(&mm->mmap_sem); 243 down_write(&mm->mmap_sem);
244 vma->vm_mm = mm; 244 vma->vm_mm = mm;
@@ -251,28 +251,20 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
251 */ 251 */
252 vma->vm_end = STACK_TOP_MAX; 252 vma->vm_end = STACK_TOP_MAX;
253 vma->vm_start = vma->vm_end - PAGE_SIZE; 253 vma->vm_start = vma->vm_end - PAGE_SIZE;
254
255 vma->vm_flags = VM_STACK_FLAGS; 254 vma->vm_flags = VM_STACK_FLAGS;
256 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 255 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
257 err = insert_vm_struct(mm, vma); 256 err = insert_vm_struct(mm, vma);
258 if (err) { 257 if (err)
259 up_write(&mm->mmap_sem);
260 goto err; 258 goto err;
261 }
262 259
263 mm->stack_vm = mm->total_vm = 1; 260 mm->stack_vm = mm->total_vm = 1;
264 up_write(&mm->mmap_sem); 261 up_write(&mm->mmap_sem);
265
266 bprm->p = vma->vm_end - sizeof(void *); 262 bprm->p = vma->vm_end - sizeof(void *);
267
268 return 0; 263 return 0;
269
270err: 264err:
271 if (vma) { 265 up_write(&mm->mmap_sem);
272 bprm->vma = NULL; 266 bprm->vma = NULL;
273 kmem_cache_free(vm_area_cachep, vma); 267 kmem_cache_free(vm_area_cachep, vma);
274 }
275
276 return err; 268 return err;
277} 269}
278 270
@@ -679,7 +671,7 @@ struct file *open_exec(const char *name)
679 if (nd.path.mnt->mnt_flags & MNT_NOEXEC) 671 if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
680 goto out_path_put; 672 goto out_path_put;
681 673
682 err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); 674 err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN);
683 if (err) 675 if (err)
684 goto out_path_put; 676 goto out_path_put;
685 677
@@ -687,6 +679,8 @@ struct file *open_exec(const char *name)
687 if (IS_ERR(file)) 679 if (IS_ERR(file))
688 return file; 680 return file;
689 681
682 fsnotify_open(file->f_path.dentry);
683
690 err = deny_write_access(file); 684 err = deny_write_access(file);
691 if (err) { 685 if (err) {
692 fput(file); 686 fput(file);
@@ -772,7 +766,6 @@ static int de_thread(struct task_struct *tsk)
772 struct signal_struct *sig = tsk->signal; 766 struct signal_struct *sig = tsk->signal;
773 struct sighand_struct *oldsighand = tsk->sighand; 767 struct sighand_struct *oldsighand = tsk->sighand;
774 spinlock_t *lock = &oldsighand->siglock; 768 spinlock_t *lock = &oldsighand->siglock;
775 struct task_struct *leader = NULL;
776 int count; 769 int count;
777 770
778 if (thread_group_empty(tsk)) 771 if (thread_group_empty(tsk))
@@ -810,7 +803,7 @@ static int de_thread(struct task_struct *tsk)
810 * and to assume its PID: 803 * and to assume its PID:
811 */ 804 */
812 if (!thread_group_leader(tsk)) { 805 if (!thread_group_leader(tsk)) {
813 leader = tsk->group_leader; 806 struct task_struct *leader = tsk->group_leader;
814 807
815 sig->notify_count = -1; /* for exit_notify() */ 808 sig->notify_count = -1; /* for exit_notify() */
816 for (;;) { 809 for (;;) {
@@ -862,8 +855,9 @@ static int de_thread(struct task_struct *tsk)
862 855
863 BUG_ON(leader->exit_state != EXIT_ZOMBIE); 856 BUG_ON(leader->exit_state != EXIT_ZOMBIE);
864 leader->exit_state = EXIT_DEAD; 857 leader->exit_state = EXIT_DEAD;
865
866 write_unlock_irq(&tasklist_lock); 858 write_unlock_irq(&tasklist_lock);
859
860 release_task(leader);
867 } 861 }
868 862
869 sig->group_exit_task = NULL; 863 sig->group_exit_task = NULL;
@@ -872,8 +866,6 @@ static int de_thread(struct task_struct *tsk)
872no_thread_group: 866no_thread_group:
873 exit_itimers(sig); 867 exit_itimers(sig);
874 flush_itimer_signals(); 868 flush_itimer_signals();
875 if (leader)
876 release_task(leader);
877 869
878 if (atomic_read(&oldsighand->count) != 1) { 870 if (atomic_read(&oldsighand->count) != 1) {
879 struct sighand_struct *newsighand; 871 struct sighand_struct *newsighand;
@@ -980,7 +972,7 @@ int flush_old_exec(struct linux_binprm * bprm)
980 /* This is the point of no return */ 972 /* This is the point of no return */
981 current->sas_ss_sp = current->sas_ss_size = 0; 973 current->sas_ss_sp = current->sas_ss_size = 0;
982 974
983 if (current->euid == current->uid && current->egid == current->gid) 975 if (current_euid() == current_uid() && current_egid() == current_gid())
984 set_dumpable(current->mm, 1); 976 set_dumpable(current->mm, 1);
985 else 977 else
986 set_dumpable(current->mm, suid_dumpable); 978 set_dumpable(current->mm, suid_dumpable);
@@ -1007,16 +999,17 @@ int flush_old_exec(struct linux_binprm * bprm)
1007 */ 999 */
1008 current->mm->task_size = TASK_SIZE; 1000 current->mm->task_size = TASK_SIZE;
1009 1001
1010 if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) { 1002 /* install the new credentials */
1011 suid_keys(current); 1003 if (bprm->cred->uid != current_euid() ||
1012 set_dumpable(current->mm, suid_dumpable); 1004 bprm->cred->gid != current_egid()) {
1013 current->pdeath_signal = 0; 1005 current->pdeath_signal = 0;
1014 } else if (file_permission(bprm->file, MAY_READ) || 1006 } else if (file_permission(bprm->file, MAY_READ) ||
1015 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { 1007 bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
1016 suid_keys(current);
1017 set_dumpable(current->mm, suid_dumpable); 1008 set_dumpable(current->mm, suid_dumpable);
1018 } 1009 }
1019 1010
1011 current->personality &= ~bprm->per_clear;
1012
1020 /* An exec changes our domain. We are no longer part of the thread 1013 /* An exec changes our domain. We are no longer part of the thread
1021 group */ 1014 group */
1022 1015
@@ -1033,13 +1026,50 @@ out:
1033 1026
1034EXPORT_SYMBOL(flush_old_exec); 1027EXPORT_SYMBOL(flush_old_exec);
1035 1028
1029/*
1030 * install the new credentials for this executable
1031 */
1032void install_exec_creds(struct linux_binprm *bprm)
1033{
1034 security_bprm_committing_creds(bprm);
1035
1036 commit_creds(bprm->cred);
1037 bprm->cred = NULL;
1038
1039 /* cred_exec_mutex must be held at least to this point to prevent
1040 * ptrace_attach() from altering our determination of the task's
1041 * credentials; any time after this it may be unlocked */
1042
1043 security_bprm_committed_creds(bprm);
1044}
1045EXPORT_SYMBOL(install_exec_creds);
1046
1047/*
1048 * determine how safe it is to execute the proposed program
1049 * - the caller must hold current->cred_exec_mutex to protect against
1050 * PTRACE_ATTACH
1051 */
1052void check_unsafe_exec(struct linux_binprm *bprm)
1053{
1054 struct task_struct *p = current;
1055
1056 bprm->unsafe = tracehook_unsafe_exec(p);
1057
1058 if (atomic_read(&p->fs->count) > 1 ||
1059 atomic_read(&p->files->count) > 1 ||
1060 atomic_read(&p->sighand->count) > 1)
1061 bprm->unsafe |= LSM_UNSAFE_SHARE;
1062}
1063
1036/* 1064/*
1037 * Fill the binprm structure from the inode. 1065 * Fill the binprm structure from the inode.
1038 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes 1066 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
1067 *
1068 * This may be called multiple times for binary chains (scripts for example).
1039 */ 1069 */
1040int prepare_binprm(struct linux_binprm *bprm) 1070int prepare_binprm(struct linux_binprm *bprm)
1041{ 1071{
1042 int mode; 1072 umode_t mode;
1043 struct inode * inode = bprm->file->f_path.dentry->d_inode; 1073 struct inode * inode = bprm->file->f_path.dentry->d_inode;
1044 int retval; 1074 int retval;
1045 1075
@@ -1047,14 +1077,15 @@ int prepare_binprm(struct linux_binprm *bprm)
1047 if (bprm->file->f_op == NULL) 1077 if (bprm->file->f_op == NULL)
1048 return -EACCES; 1078 return -EACCES;
1049 1079
1050 bprm->e_uid = current->euid; 1080 /* clear any previous set[ug]id data from a previous binary */
1051 bprm->e_gid = current->egid; 1081 bprm->cred->euid = current_euid();
1082 bprm->cred->egid = current_egid();
1052 1083
1053 if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { 1084 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
1054 /* Set-uid? */ 1085 /* Set-uid? */
1055 if (mode & S_ISUID) { 1086 if (mode & S_ISUID) {
1056 current->personality &= ~PER_CLEAR_ON_SETID; 1087 bprm->per_clear |= PER_CLEAR_ON_SETID;
1057 bprm->e_uid = inode->i_uid; 1088 bprm->cred->euid = inode->i_uid;
1058 } 1089 }
1059 1090
1060 /* Set-gid? */ 1091 /* Set-gid? */
@@ -1064,52 +1095,23 @@ int prepare_binprm(struct linux_binprm *bprm)
1064 * executable. 1095 * executable.
1065 */ 1096 */
1066 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 1097 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
1067 current->personality &= ~PER_CLEAR_ON_SETID; 1098 bprm->per_clear |= PER_CLEAR_ON_SETID;
1068 bprm->e_gid = inode->i_gid; 1099 bprm->cred->egid = inode->i_gid;
1069 } 1100 }
1070 } 1101 }
1071 1102
1072 /* fill in binprm security blob */ 1103 /* fill in binprm security blob */
1073 retval = security_bprm_set(bprm); 1104 retval = security_bprm_set_creds(bprm);
1074 if (retval) 1105 if (retval)
1075 return retval; 1106 return retval;
1107 bprm->cred_prepared = 1;
1076 1108
1077 memset(bprm->buf,0,BINPRM_BUF_SIZE); 1109 memset(bprm->buf, 0, BINPRM_BUF_SIZE);
1078 return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); 1110 return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
1079} 1111}
1080 1112
1081EXPORT_SYMBOL(prepare_binprm); 1113EXPORT_SYMBOL(prepare_binprm);
1082 1114
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/* 1115/*
1114 * Arguments are '\0' separated strings found at the location bprm->p 1116 * 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 1117 * points to; chop off the first by relocating brpm->p to right after
@@ -1162,41 +1164,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
1162 unsigned int depth = bprm->recursion_depth; 1164 unsigned int depth = bprm->recursion_depth;
1163 int try,retval; 1165 int try,retval;
1164 struct linux_binfmt *fmt; 1166 struct linux_binfmt *fmt;
1165#ifdef __alpha__
1166 /* handle /sbin/loader.. */
1167 {
1168 struct exec * eh = (struct exec *) bprm->buf;
1169
1170 if (!bprm->loader && eh->fh.f_magic == 0x183 &&
1171 (eh->fh.f_flags & 0x3000) == 0x3000)
1172 {
1173 struct file * file;
1174 unsigned long loader;
1175 1167
1176 allow_write_access(bprm->file);
1177 fput(bprm->file);
1178 bprm->file = NULL;
1179
1180 loader = bprm->vma->vm_end - sizeof(void *);
1181
1182 file = open_exec("/sbin/loader");
1183 retval = PTR_ERR(file);
1184 if (IS_ERR(file))
1185 return retval;
1186
1187 /* Remember if the application is TASO. */
1188 bprm->taso = eh->ah.entry < 0x100000000UL;
1189
1190 bprm->file = file;
1191 bprm->loader = loader;
1192 retval = prepare_binprm(bprm);
1193 if (retval<0)
1194 return retval;
1195 /* should call search_binary_handler recursively here,
1196 but it does not matter */
1197 }
1198 }
1199#endif
1200 retval = security_bprm_check(bprm); 1168 retval = security_bprm_check(bprm);
1201 if (retval) 1169 if (retval)
1202 return retval; 1170 return retval;
@@ -1270,6 +1238,8 @@ EXPORT_SYMBOL(search_binary_handler);
1270void free_bprm(struct linux_binprm *bprm) 1238void free_bprm(struct linux_binprm *bprm)
1271{ 1239{
1272 free_arg_pages(bprm); 1240 free_arg_pages(bprm);
1241 if (bprm->cred)
1242 abort_creds(bprm->cred);
1273 kfree(bprm); 1243 kfree(bprm);
1274} 1244}
1275 1245
@@ -1295,10 +1265,20 @@ int do_execve(char * filename,
1295 if (!bprm) 1265 if (!bprm)
1296 goto out_files; 1266 goto out_files;
1297 1267
1268 retval = mutex_lock_interruptible(&current->cred_exec_mutex);
1269 if (retval < 0)
1270 goto out_free;
1271
1272 retval = -ENOMEM;
1273 bprm->cred = prepare_exec_creds();
1274 if (!bprm->cred)
1275 goto out_unlock;
1276 check_unsafe_exec(bprm);
1277
1298 file = open_exec(filename); 1278 file = open_exec(filename);
1299 retval = PTR_ERR(file); 1279 retval = PTR_ERR(file);
1300 if (IS_ERR(file)) 1280 if (IS_ERR(file))
1301 goto out_kfree; 1281 goto out_unlock;
1302 1282
1303 sched_exec(); 1283 sched_exec();
1304 1284
@@ -1312,14 +1292,10 @@ int do_execve(char * filename,
1312 1292
1313 bprm->argc = count(argv, MAX_ARG_STRINGS); 1293 bprm->argc = count(argv, MAX_ARG_STRINGS);
1314 if ((retval = bprm->argc) < 0) 1294 if ((retval = bprm->argc) < 0)
1315 goto out_mm; 1295 goto out;
1316 1296
1317 bprm->envc = count(envp, MAX_ARG_STRINGS); 1297 bprm->envc = count(envp, MAX_ARG_STRINGS);
1318 if ((retval = bprm->envc) < 0) 1298 if ((retval = bprm->envc) < 0)
1319 goto out_mm;
1320
1321 retval = security_bprm_alloc(bprm);
1322 if (retval)
1323 goto out; 1299 goto out;
1324 1300
1325 retval = prepare_binprm(bprm); 1301 retval = prepare_binprm(bprm);
@@ -1341,21 +1317,18 @@ int do_execve(char * filename,
1341 1317
1342 current->flags &= ~PF_KTHREAD; 1318 current->flags &= ~PF_KTHREAD;
1343 retval = search_binary_handler(bprm,regs); 1319 retval = search_binary_handler(bprm,regs);
1344 if (retval >= 0) { 1320 if (retval < 0)
1345 /* execve success */ 1321 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 1322
1354out: 1323 /* execve succeeded */
1355 if (bprm->security) 1324 mutex_unlock(&current->cred_exec_mutex);
1356 security_bprm_free(bprm); 1325 acct_update_integrals(current);
1326 free_bprm(bprm);
1327 if (displaced)
1328 put_files_struct(displaced);
1329 return retval;
1357 1330
1358out_mm: 1331out:
1359 if (bprm->mm) 1332 if (bprm->mm)
1360 mmput (bprm->mm); 1333 mmput (bprm->mm);
1361 1334
@@ -1364,7 +1337,11 @@ out_file:
1364 allow_write_access(bprm->file); 1337 allow_write_access(bprm->file);
1365 fput(bprm->file); 1338 fput(bprm->file);
1366 } 1339 }
1367out_kfree: 1340
1341out_unlock:
1342 mutex_unlock(&current->cred_exec_mutex);
1343
1344out_free:
1368 free_bprm(bprm); 1345 free_bprm(bprm);
1369 1346
1370out_files: 1347out_files:
@@ -1396,6 +1373,7 @@ EXPORT_SYMBOL(set_binfmt);
1396 */ 1373 */
1397static int format_corename(char *corename, long signr) 1374static int format_corename(char *corename, long signr)
1398{ 1375{
1376 const struct cred *cred = current_cred();
1399 const char *pat_ptr = core_pattern; 1377 const char *pat_ptr = core_pattern;
1400 int ispipe = (*pat_ptr == '|'); 1378 int ispipe = (*pat_ptr == '|');
1401 char *out_ptr = corename; 1379 char *out_ptr = corename;
@@ -1432,7 +1410,7 @@ static int format_corename(char *corename, long signr)
1432 /* uid */ 1410 /* uid */
1433 case 'u': 1411 case 'u':
1434 rc = snprintf(out_ptr, out_end - out_ptr, 1412 rc = snprintf(out_ptr, out_end - out_ptr,
1435 "%d", current->uid); 1413 "%d", cred->uid);
1436 if (rc > out_end - out_ptr) 1414 if (rc > out_end - out_ptr)
1437 goto out; 1415 goto out;
1438 out_ptr += rc; 1416 out_ptr += rc;
@@ -1440,7 +1418,7 @@ static int format_corename(char *corename, long signr)
1440 /* gid */ 1418 /* gid */
1441 case 'g': 1419 case 'g':
1442 rc = snprintf(out_ptr, out_end - out_ptr, 1420 rc = snprintf(out_ptr, out_end - out_ptr,
1443 "%d", current->gid); 1421 "%d", cred->gid);
1444 if (rc > out_end - out_ptr) 1422 if (rc > out_end - out_ptr)
1445 goto out; 1423 goto out;
1446 out_ptr += rc; 1424 out_ptr += rc;
@@ -1708,7 +1686,7 @@ int get_dumpable(struct mm_struct *mm)
1708 return (ret >= 2) ? 2 : ret; 1686 return (ret >= 2) ? 2 : ret;
1709} 1687}
1710 1688
1711int do_coredump(long signr, int exit_code, struct pt_regs * regs) 1689void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1712{ 1690{
1713 struct core_state core_state; 1691 struct core_state core_state;
1714 char corename[CORENAME_MAX_SIZE + 1]; 1692 char corename[CORENAME_MAX_SIZE + 1];
@@ -1716,8 +1694,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1716 struct linux_binfmt * binfmt; 1694 struct linux_binfmt * binfmt;
1717 struct inode * inode; 1695 struct inode * inode;
1718 struct file * file; 1696 struct file * file;
1697 const struct cred *old_cred;
1698 struct cred *cred;
1719 int retval = 0; 1699 int retval = 0;
1720 int fsuid = current->fsuid;
1721 int flag = 0; 1700 int flag = 0;
1722 int ispipe = 0; 1701 int ispipe = 0;
1723 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; 1702 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1730,12 +1709,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1730 binfmt = current->binfmt; 1709 binfmt = current->binfmt;
1731 if (!binfmt || !binfmt->core_dump) 1710 if (!binfmt || !binfmt->core_dump)
1732 goto fail; 1711 goto fail;
1712
1713 cred = prepare_creds();
1714 if (!cred) {
1715 retval = -ENOMEM;
1716 goto fail;
1717 }
1718
1733 down_write(&mm->mmap_sem); 1719 down_write(&mm->mmap_sem);
1734 /* 1720 /*
1735 * If another thread got here first, or we are not dumpable, bail out. 1721 * If another thread got here first, or we are not dumpable, bail out.
1736 */ 1722 */
1737 if (mm->core_state || !get_dumpable(mm)) { 1723 if (mm->core_state || !get_dumpable(mm)) {
1738 up_write(&mm->mmap_sem); 1724 up_write(&mm->mmap_sem);
1725 put_cred(cred);
1739 goto fail; 1726 goto fail;
1740 } 1727 }
1741 1728
@@ -1746,12 +1733,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1746 */ 1733 */
1747 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ 1734 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
1748 flag = O_EXCL; /* Stop rewrite attacks */ 1735 flag = O_EXCL; /* Stop rewrite attacks */
1749 current->fsuid = 0; /* Dump root private */ 1736 cred->fsuid = 0; /* Dump root private */
1750 } 1737 }
1751 1738
1752 retval = coredump_wait(exit_code, &core_state); 1739 retval = coredump_wait(exit_code, &core_state);
1753 if (retval < 0) 1740 if (retval < 0) {
1741 put_cred(cred);
1754 goto fail; 1742 goto fail;
1743 }
1744
1745 old_cred = override_creds(cred);
1755 1746
1756 /* 1747 /*
1757 * Clear any false indication of pending signals that might 1748 * Clear any false indication of pending signals that might
@@ -1779,6 +1770,11 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1779 1770
1780 if (ispipe) { 1771 if (ispipe) {
1781 helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); 1772 helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc);
1773 if (!helper_argv) {
1774 printk(KERN_WARNING "%s failed to allocate memory\n",
1775 __func__);
1776 goto fail_unlock;
1777 }
1782 /* Terminate the string before the first option */ 1778 /* Terminate the string before the first option */
1783 delimit = strchr(corename, ' '); 1779 delimit = strchr(corename, ' ');
1784 if (delimit) 1780 if (delimit)
@@ -1823,7 +1819,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 1819 * Dont allow local users get cute and trick others to coredump
1824 * into their pre-created files: 1820 * into their pre-created files:
1825 */ 1821 */
1826 if (inode->i_uid != current->fsuid) 1822 if (inode->i_uid != current_fsuid())
1827 goto close_fail; 1823 goto close_fail;
1828 if (!file->f_op) 1824 if (!file->f_op)
1829 goto close_fail; 1825 goto close_fail;
@@ -1842,8 +1838,9 @@ fail_unlock:
1842 if (helper_argv) 1838 if (helper_argv)
1843 argv_free(helper_argv); 1839 argv_free(helper_argv);
1844 1840
1845 current->fsuid = fsuid; 1841 revert_creds(old_cred);
1842 put_cred(cred);
1846 coredump_finish(mm); 1843 coredump_finish(mm);
1847fail: 1844fail:
1848 return retval; 1845 return;
1849} 1846}