diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 206 |
1 files changed, 124 insertions, 82 deletions
@@ -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() */ |
@@ -126,7 +127,8 @@ asmlinkage long sys_uselib(const char __user * library) | |||
126 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | 127 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) |
127 | goto exit; | 128 | goto exit; |
128 | 129 | ||
129 | error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN); | 130 | error = inode_permission(nd.path.dentry->d_inode, |
131 | MAY_READ | MAY_EXEC | MAY_OPEN); | ||
130 | if (error) | 132 | if (error) |
131 | goto exit; | 133 | goto exit; |
132 | 134 | ||
@@ -679,7 +681,7 @@ struct file *open_exec(const char *name) | |||
679 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | 681 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) |
680 | goto out_path_put; | 682 | goto out_path_put; |
681 | 683 | ||
682 | err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); | 684 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); |
683 | if (err) | 685 | if (err) |
684 | goto out_path_put; | 686 | goto out_path_put; |
685 | 687 | ||
@@ -772,7 +774,6 @@ static int de_thread(struct task_struct *tsk) | |||
772 | struct signal_struct *sig = tsk->signal; | 774 | struct signal_struct *sig = tsk->signal; |
773 | struct sighand_struct *oldsighand = tsk->sighand; | 775 | struct sighand_struct *oldsighand = tsk->sighand; |
774 | spinlock_t *lock = &oldsighand->siglock; | 776 | spinlock_t *lock = &oldsighand->siglock; |
775 | struct task_struct *leader = NULL; | ||
776 | int count; | 777 | int count; |
777 | 778 | ||
778 | if (thread_group_empty(tsk)) | 779 | if (thread_group_empty(tsk)) |
@@ -810,7 +811,7 @@ static int de_thread(struct task_struct *tsk) | |||
810 | * and to assume its PID: | 811 | * and to assume its PID: |
811 | */ | 812 | */ |
812 | if (!thread_group_leader(tsk)) { | 813 | if (!thread_group_leader(tsk)) { |
813 | leader = tsk->group_leader; | 814 | struct task_struct *leader = tsk->group_leader; |
814 | 815 | ||
815 | sig->notify_count = -1; /* for exit_notify() */ | 816 | sig->notify_count = -1; /* for exit_notify() */ |
816 | for (;;) { | 817 | for (;;) { |
@@ -862,8 +863,9 @@ static int de_thread(struct task_struct *tsk) | |||
862 | 863 | ||
863 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); | 864 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); |
864 | leader->exit_state = EXIT_DEAD; | 865 | leader->exit_state = EXIT_DEAD; |
865 | |||
866 | write_unlock_irq(&tasklist_lock); | 866 | write_unlock_irq(&tasklist_lock); |
867 | |||
868 | release_task(leader); | ||
867 | } | 869 | } |
868 | 870 | ||
869 | sig->group_exit_task = NULL; | 871 | sig->group_exit_task = NULL; |
@@ -872,8 +874,6 @@ static int de_thread(struct task_struct *tsk) | |||
872 | no_thread_group: | 874 | no_thread_group: |
873 | exit_itimers(sig); | 875 | exit_itimers(sig); |
874 | flush_itimer_signals(); | 876 | flush_itimer_signals(); |
875 | if (leader) | ||
876 | release_task(leader); | ||
877 | 877 | ||
878 | if (atomic_read(&oldsighand->count) != 1) { | 878 | if (atomic_read(&oldsighand->count) != 1) { |
879 | struct sighand_struct *newsighand; | 879 | struct sighand_struct *newsighand; |
@@ -980,7 +980,7 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
980 | /* This is the point of no return */ | 980 | /* This is the point of no return */ |
981 | current->sas_ss_sp = current->sas_ss_size = 0; | 981 | current->sas_ss_sp = current->sas_ss_size = 0; |
982 | 982 | ||
983 | if (current->euid == current->uid && current->egid == current->gid) | 983 | if (current_euid() == current_uid() && current_egid() == current_gid()) |
984 | set_dumpable(current->mm, 1); | 984 | set_dumpable(current->mm, 1); |
985 | else | 985 | else |
986 | set_dumpable(current->mm, suid_dumpable); | 986 | set_dumpable(current->mm, suid_dumpable); |
@@ -1007,16 +1007,17 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
1007 | */ | 1007 | */ |
1008 | current->mm->task_size = TASK_SIZE; | 1008 | current->mm->task_size = TASK_SIZE; |
1009 | 1009 | ||
1010 | if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) { | 1010 | /* install the new credentials */ |
1011 | suid_keys(current); | 1011 | if (bprm->cred->uid != current_euid() || |
1012 | set_dumpable(current->mm, suid_dumpable); | 1012 | bprm->cred->gid != current_egid()) { |
1013 | current->pdeath_signal = 0; | 1013 | current->pdeath_signal = 0; |
1014 | } else if (file_permission(bprm->file, MAY_READ) || | 1014 | } else if (file_permission(bprm->file, MAY_READ) || |
1015 | (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { | 1015 | bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) { |
1016 | suid_keys(current); | ||
1017 | set_dumpable(current->mm, suid_dumpable); | 1016 | set_dumpable(current->mm, suid_dumpable); |
1018 | } | 1017 | } |
1019 | 1018 | ||
1019 | current->personality &= ~bprm->per_clear; | ||
1020 | |||
1020 | /* An exec changes our domain. We are no longer part of the thread | 1021 | /* An exec changes our domain. We are no longer part of the thread |
1021 | group */ | 1022 | group */ |
1022 | 1023 | ||
@@ -1033,13 +1034,50 @@ out: | |||
1033 | 1034 | ||
1034 | EXPORT_SYMBOL(flush_old_exec); | 1035 | EXPORT_SYMBOL(flush_old_exec); |
1035 | 1036 | ||
1037 | /* | ||
1038 | * install the new credentials for this executable | ||
1039 | */ | ||
1040 | void install_exec_creds(struct linux_binprm *bprm) | ||
1041 | { | ||
1042 | security_bprm_committing_creds(bprm); | ||
1043 | |||
1044 | commit_creds(bprm->cred); | ||
1045 | bprm->cred = NULL; | ||
1046 | |||
1047 | /* cred_exec_mutex must be held at least to this point to prevent | ||
1048 | * ptrace_attach() from altering our determination of the task's | ||
1049 | * credentials; any time after this it may be unlocked */ | ||
1050 | |||
1051 | security_bprm_committed_creds(bprm); | ||
1052 | } | ||
1053 | EXPORT_SYMBOL(install_exec_creds); | ||
1054 | |||
1055 | /* | ||
1056 | * determine how safe it is to execute the proposed program | ||
1057 | * - the caller must hold current->cred_exec_mutex to protect against | ||
1058 | * PTRACE_ATTACH | ||
1059 | */ | ||
1060 | void check_unsafe_exec(struct linux_binprm *bprm) | ||
1061 | { | ||
1062 | struct task_struct *p = current; | ||
1063 | |||
1064 | bprm->unsafe = tracehook_unsafe_exec(p); | ||
1065 | |||
1066 | if (atomic_read(&p->fs->count) > 1 || | ||
1067 | atomic_read(&p->files->count) > 1 || | ||
1068 | atomic_read(&p->sighand->count) > 1) | ||
1069 | bprm->unsafe |= LSM_UNSAFE_SHARE; | ||
1070 | } | ||
1071 | |||
1036 | /* | 1072 | /* |
1037 | * Fill the binprm structure from the inode. | 1073 | * Fill the binprm structure from the inode. |
1038 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes | 1074 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes |
1075 | * | ||
1076 | * This may be called multiple times for binary chains (scripts for example). | ||
1039 | */ | 1077 | */ |
1040 | int prepare_binprm(struct linux_binprm *bprm) | 1078 | int prepare_binprm(struct linux_binprm *bprm) |
1041 | { | 1079 | { |
1042 | int mode; | 1080 | umode_t mode; |
1043 | struct inode * inode = bprm->file->f_path.dentry->d_inode; | 1081 | struct inode * inode = bprm->file->f_path.dentry->d_inode; |
1044 | int retval; | 1082 | int retval; |
1045 | 1083 | ||
@@ -1047,14 +1085,15 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1047 | if (bprm->file->f_op == NULL) | 1085 | if (bprm->file->f_op == NULL) |
1048 | return -EACCES; | 1086 | return -EACCES; |
1049 | 1087 | ||
1050 | bprm->e_uid = current->euid; | 1088 | /* clear any previous set[ug]id data from a previous binary */ |
1051 | bprm->e_gid = current->egid; | 1089 | bprm->cred->euid = current_euid(); |
1090 | bprm->cred->egid = current_egid(); | ||
1052 | 1091 | ||
1053 | if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { | 1092 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { |
1054 | /* Set-uid? */ | 1093 | /* Set-uid? */ |
1055 | if (mode & S_ISUID) { | 1094 | if (mode & S_ISUID) { |
1056 | current->personality &= ~PER_CLEAR_ON_SETID; | 1095 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1057 | bprm->e_uid = inode->i_uid; | 1096 | bprm->cred->euid = inode->i_uid; |
1058 | } | 1097 | } |
1059 | 1098 | ||
1060 | /* Set-gid? */ | 1099 | /* Set-gid? */ |
@@ -1064,52 +1103,23 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1064 | * executable. | 1103 | * executable. |
1065 | */ | 1104 | */ |
1066 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | 1105 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
1067 | current->personality &= ~PER_CLEAR_ON_SETID; | 1106 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1068 | bprm->e_gid = inode->i_gid; | 1107 | bprm->cred->egid = inode->i_gid; |
1069 | } | 1108 | } |
1070 | } | 1109 | } |
1071 | 1110 | ||
1072 | /* fill in binprm security blob */ | 1111 | /* fill in binprm security blob */ |
1073 | retval = security_bprm_set(bprm); | 1112 | retval = security_bprm_set_creds(bprm); |
1074 | if (retval) | 1113 | if (retval) |
1075 | return retval; | 1114 | return retval; |
1115 | bprm->cred_prepared = 1; | ||
1076 | 1116 | ||
1077 | memset(bprm->buf,0,BINPRM_BUF_SIZE); | 1117 | memset(bprm->buf, 0, BINPRM_BUF_SIZE); |
1078 | return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); | 1118 | return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); |
1079 | } | 1119 | } |
1080 | 1120 | ||
1081 | EXPORT_SYMBOL(prepare_binprm); | 1121 | EXPORT_SYMBOL(prepare_binprm); |
1082 | 1122 | ||
1083 | static 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 | |||
1095 | void 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 | } | ||
1111 | EXPORT_SYMBOL(compute_creds); | ||
1112 | |||
1113 | /* | 1123 | /* |
1114 | * Arguments are '\0' separated strings found at the location bprm->p | 1124 | * 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 | 1125 | * points to; chop off the first by relocating brpm->p to right after |
@@ -1159,6 +1169,7 @@ EXPORT_SYMBOL(remove_arg_zero); | |||
1159 | */ | 1169 | */ |
1160 | int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | 1170 | int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) |
1161 | { | 1171 | { |
1172 | unsigned int depth = bprm->recursion_depth; | ||
1162 | int try,retval; | 1173 | int try,retval; |
1163 | struct linux_binfmt *fmt; | 1174 | struct linux_binfmt *fmt; |
1164 | #ifdef __alpha__ | 1175 | #ifdef __alpha__ |
@@ -1219,8 +1230,15 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1219 | continue; | 1230 | continue; |
1220 | read_unlock(&binfmt_lock); | 1231 | read_unlock(&binfmt_lock); |
1221 | retval = fn(bprm, regs); | 1232 | retval = fn(bprm, regs); |
1233 | /* | ||
1234 | * Restore the depth counter to its starting value | ||
1235 | * in this call, so we don't have to rely on every | ||
1236 | * load_binary function to restore it on return. | ||
1237 | */ | ||
1238 | bprm->recursion_depth = depth; | ||
1222 | if (retval >= 0) { | 1239 | if (retval >= 0) { |
1223 | tracehook_report_exec(fmt, bprm, regs); | 1240 | if (depth == 0) |
1241 | tracehook_report_exec(fmt, bprm, regs); | ||
1224 | put_binfmt(fmt); | 1242 | put_binfmt(fmt); |
1225 | allow_write_access(bprm->file); | 1243 | allow_write_access(bprm->file); |
1226 | if (bprm->file) | 1244 | if (bprm->file) |
@@ -1262,6 +1280,8 @@ EXPORT_SYMBOL(search_binary_handler); | |||
1262 | void free_bprm(struct linux_binprm *bprm) | 1280 | void free_bprm(struct linux_binprm *bprm) |
1263 | { | 1281 | { |
1264 | free_arg_pages(bprm); | 1282 | free_arg_pages(bprm); |
1283 | if (bprm->cred) | ||
1284 | abort_creds(bprm->cred); | ||
1265 | kfree(bprm); | 1285 | kfree(bprm); |
1266 | } | 1286 | } |
1267 | 1287 | ||
@@ -1287,10 +1307,20 @@ int do_execve(char * filename, | |||
1287 | if (!bprm) | 1307 | if (!bprm) |
1288 | goto out_files; | 1308 | goto out_files; |
1289 | 1309 | ||
1310 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | ||
1311 | if (retval < 0) | ||
1312 | goto out_free; | ||
1313 | |||
1314 | retval = -ENOMEM; | ||
1315 | bprm->cred = prepare_exec_creds(); | ||
1316 | if (!bprm->cred) | ||
1317 | goto out_unlock; | ||
1318 | check_unsafe_exec(bprm); | ||
1319 | |||
1290 | file = open_exec(filename); | 1320 | file = open_exec(filename); |
1291 | retval = PTR_ERR(file); | 1321 | retval = PTR_ERR(file); |
1292 | if (IS_ERR(file)) | 1322 | if (IS_ERR(file)) |
1293 | goto out_kfree; | 1323 | goto out_unlock; |
1294 | 1324 | ||
1295 | sched_exec(); | 1325 | sched_exec(); |
1296 | 1326 | ||
@@ -1304,14 +1334,10 @@ int do_execve(char * filename, | |||
1304 | 1334 | ||
1305 | bprm->argc = count(argv, MAX_ARG_STRINGS); | 1335 | bprm->argc = count(argv, MAX_ARG_STRINGS); |
1306 | if ((retval = bprm->argc) < 0) | 1336 | if ((retval = bprm->argc) < 0) |
1307 | goto out_mm; | 1337 | goto out; |
1308 | 1338 | ||
1309 | bprm->envc = count(envp, MAX_ARG_STRINGS); | 1339 | bprm->envc = count(envp, MAX_ARG_STRINGS); |
1310 | if ((retval = bprm->envc) < 0) | 1340 | if ((retval = bprm->envc) < 0) |
1311 | goto out_mm; | ||
1312 | |||
1313 | retval = security_bprm_alloc(bprm); | ||
1314 | if (retval) | ||
1315 | goto out; | 1341 | goto out; |
1316 | 1342 | ||
1317 | retval = prepare_binprm(bprm); | 1343 | retval = prepare_binprm(bprm); |
@@ -1333,21 +1359,18 @@ int do_execve(char * filename, | |||
1333 | 1359 | ||
1334 | current->flags &= ~PF_KTHREAD; | 1360 | current->flags &= ~PF_KTHREAD; |
1335 | retval = search_binary_handler(bprm,regs); | 1361 | retval = search_binary_handler(bprm,regs); |
1336 | if (retval >= 0) { | 1362 | if (retval < 0) |
1337 | /* execve success */ | 1363 | goto out; |
1338 | security_bprm_free(bprm); | ||
1339 | acct_update_integrals(current); | ||
1340 | free_bprm(bprm); | ||
1341 | if (displaced) | ||
1342 | put_files_struct(displaced); | ||
1343 | return retval; | ||
1344 | } | ||
1345 | 1364 | ||
1346 | out: | 1365 | /* execve succeeded */ |
1347 | if (bprm->security) | 1366 | mutex_unlock(¤t->cred_exec_mutex); |
1348 | security_bprm_free(bprm); | 1367 | acct_update_integrals(current); |
1368 | free_bprm(bprm); | ||
1369 | if (displaced) | ||
1370 | put_files_struct(displaced); | ||
1371 | return retval; | ||
1349 | 1372 | ||
1350 | out_mm: | 1373 | out: |
1351 | if (bprm->mm) | 1374 | if (bprm->mm) |
1352 | mmput (bprm->mm); | 1375 | mmput (bprm->mm); |
1353 | 1376 | ||
@@ -1356,7 +1379,11 @@ out_file: | |||
1356 | allow_write_access(bprm->file); | 1379 | allow_write_access(bprm->file); |
1357 | fput(bprm->file); | 1380 | fput(bprm->file); |
1358 | } | 1381 | } |
1359 | out_kfree: | 1382 | |
1383 | out_unlock: | ||
1384 | mutex_unlock(¤t->cred_exec_mutex); | ||
1385 | |||
1386 | out_free: | ||
1360 | free_bprm(bprm); | 1387 | free_bprm(bprm); |
1361 | 1388 | ||
1362 | out_files: | 1389 | out_files: |
@@ -1388,6 +1415,7 @@ EXPORT_SYMBOL(set_binfmt); | |||
1388 | */ | 1415 | */ |
1389 | static int format_corename(char *corename, long signr) | 1416 | static int format_corename(char *corename, long signr) |
1390 | { | 1417 | { |
1418 | const struct cred *cred = current_cred(); | ||
1391 | const char *pat_ptr = core_pattern; | 1419 | const char *pat_ptr = core_pattern; |
1392 | int ispipe = (*pat_ptr == '|'); | 1420 | int ispipe = (*pat_ptr == '|'); |
1393 | char *out_ptr = corename; | 1421 | char *out_ptr = corename; |
@@ -1424,7 +1452,7 @@ static int format_corename(char *corename, long signr) | |||
1424 | /* uid */ | 1452 | /* uid */ |
1425 | case 'u': | 1453 | case 'u': |
1426 | rc = snprintf(out_ptr, out_end - out_ptr, | 1454 | rc = snprintf(out_ptr, out_end - out_ptr, |
1427 | "%d", current->uid); | 1455 | "%d", cred->uid); |
1428 | if (rc > out_end - out_ptr) | 1456 | if (rc > out_end - out_ptr) |
1429 | goto out; | 1457 | goto out; |
1430 | out_ptr += rc; | 1458 | out_ptr += rc; |
@@ -1432,7 +1460,7 @@ static int format_corename(char *corename, long signr) | |||
1432 | /* gid */ | 1460 | /* gid */ |
1433 | case 'g': | 1461 | case 'g': |
1434 | rc = snprintf(out_ptr, out_end - out_ptr, | 1462 | rc = snprintf(out_ptr, out_end - out_ptr, |
1435 | "%d", current->gid); | 1463 | "%d", cred->gid); |
1436 | if (rc > out_end - out_ptr) | 1464 | if (rc > out_end - out_ptr) |
1437 | goto out; | 1465 | goto out; |
1438 | out_ptr += rc; | 1466 | out_ptr += rc; |
@@ -1708,8 +1736,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1708 | struct linux_binfmt * binfmt; | 1736 | struct linux_binfmt * binfmt; |
1709 | struct inode * inode; | 1737 | struct inode * inode; |
1710 | struct file * file; | 1738 | struct file * file; |
1739 | const struct cred *old_cred; | ||
1740 | struct cred *cred; | ||
1711 | int retval = 0; | 1741 | int retval = 0; |
1712 | int fsuid = current->fsuid; | ||
1713 | int flag = 0; | 1742 | int flag = 0; |
1714 | int ispipe = 0; | 1743 | int ispipe = 0; |
1715 | unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1744 | unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
@@ -1722,12 +1751,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1722 | binfmt = current->binfmt; | 1751 | binfmt = current->binfmt; |
1723 | if (!binfmt || !binfmt->core_dump) | 1752 | if (!binfmt || !binfmt->core_dump) |
1724 | goto fail; | 1753 | goto fail; |
1754 | |||
1755 | cred = prepare_creds(); | ||
1756 | if (!cred) { | ||
1757 | retval = -ENOMEM; | ||
1758 | goto fail; | ||
1759 | } | ||
1760 | |||
1725 | down_write(&mm->mmap_sem); | 1761 | down_write(&mm->mmap_sem); |
1726 | /* | 1762 | /* |
1727 | * If another thread got here first, or we are not dumpable, bail out. | 1763 | * If another thread got here first, or we are not dumpable, bail out. |
1728 | */ | 1764 | */ |
1729 | if (mm->core_state || !get_dumpable(mm)) { | 1765 | if (mm->core_state || !get_dumpable(mm)) { |
1730 | up_write(&mm->mmap_sem); | 1766 | up_write(&mm->mmap_sem); |
1767 | put_cred(cred); | ||
1731 | goto fail; | 1768 | goto fail; |
1732 | } | 1769 | } |
1733 | 1770 | ||
@@ -1738,12 +1775,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1738 | */ | 1775 | */ |
1739 | if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ | 1776 | if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ |
1740 | flag = O_EXCL; /* Stop rewrite attacks */ | 1777 | flag = O_EXCL; /* Stop rewrite attacks */ |
1741 | current->fsuid = 0; /* Dump root private */ | 1778 | cred->fsuid = 0; /* Dump root private */ |
1742 | } | 1779 | } |
1743 | 1780 | ||
1744 | retval = coredump_wait(exit_code, &core_state); | 1781 | retval = coredump_wait(exit_code, &core_state); |
1745 | if (retval < 0) | 1782 | if (retval < 0) { |
1783 | put_cred(cred); | ||
1746 | goto fail; | 1784 | goto fail; |
1785 | } | ||
1786 | |||
1787 | old_cred = override_creds(cred); | ||
1747 | 1788 | ||
1748 | /* | 1789 | /* |
1749 | * Clear any false indication of pending signals that might | 1790 | * Clear any false indication of pending signals that might |
@@ -1815,7 +1856,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1815 | * Dont allow local users get cute and trick others to coredump | 1856 | * Dont allow local users get cute and trick others to coredump |
1816 | * into their pre-created files: | 1857 | * into their pre-created files: |
1817 | */ | 1858 | */ |
1818 | if (inode->i_uid != current->fsuid) | 1859 | if (inode->i_uid != current_fsuid()) |
1819 | goto close_fail; | 1860 | goto close_fail; |
1820 | if (!file->f_op) | 1861 | if (!file->f_op) |
1821 | goto close_fail; | 1862 | goto close_fail; |
@@ -1834,7 +1875,8 @@ fail_unlock: | |||
1834 | if (helper_argv) | 1875 | if (helper_argv) |
1835 | argv_free(helper_argv); | 1876 | argv_free(helper_argv); |
1836 | 1877 | ||
1837 | current->fsuid = fsuid; | 1878 | revert_creds(old_cred); |
1879 | put_cred(cred); | ||
1838 | coredump_finish(mm); | 1880 | coredump_finish(mm); |
1839 | fail: | 1881 | fail: |
1840 | return retval; | 1882 | return retval; |