diff options
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 235 |
1 files changed, 115 insertions, 120 deletions
| @@ -55,11 +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 | 58 | #include "internal.h" | |
| 59 | #ifdef __alpha__ | ||
| 60 | /* for /sbin/loader handling in search_binary_handler() */ | ||
| 61 | #include <linux/a.out.h> | ||
| 62 | #endif | ||
| 63 | 59 | ||
| 64 | int core_uses_pid; | 60 | int core_uses_pid; |
| 65 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | 61 | char core_pattern[CORENAME_MAX_SIZE] = "core"; |
| @@ -126,7 +122,8 @@ asmlinkage long sys_uselib(const char __user * library) | |||
| 126 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | 122 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) |
| 127 | goto exit; | 123 | goto exit; |
| 128 | 124 | ||
| 129 | error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN); | 125 | error = inode_permission(nd.path.dentry->d_inode, |
| 126 | MAY_READ | MAY_EXEC | MAY_OPEN); | ||
| 130 | if (error) | 127 | if (error) |
| 131 | goto exit; | 128 | goto exit; |
| 132 | 129 | ||
| @@ -679,7 +676,7 @@ struct file *open_exec(const char *name) | |||
| 679 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | 676 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) |
| 680 | goto out_path_put; | 677 | goto out_path_put; |
| 681 | 678 | ||
| 682 | err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); | 679 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); |
| 683 | if (err) | 680 | if (err) |
| 684 | goto out_path_put; | 681 | goto out_path_put; |
| 685 | 682 | ||
| @@ -772,7 +769,6 @@ static int de_thread(struct task_struct *tsk) | |||
| 772 | struct signal_struct *sig = tsk->signal; | 769 | struct signal_struct *sig = tsk->signal; |
| 773 | struct sighand_struct *oldsighand = tsk->sighand; | 770 | struct sighand_struct *oldsighand = tsk->sighand; |
| 774 | spinlock_t *lock = &oldsighand->siglock; | 771 | spinlock_t *lock = &oldsighand->siglock; |
| 775 | struct task_struct *leader = NULL; | ||
| 776 | int count; | 772 | int count; |
| 777 | 773 | ||
| 778 | if (thread_group_empty(tsk)) | 774 | if (thread_group_empty(tsk)) |
| @@ -810,7 +806,7 @@ static int de_thread(struct task_struct *tsk) | |||
| 810 | * and to assume its PID: | 806 | * and to assume its PID: |
| 811 | */ | 807 | */ |
| 812 | if (!thread_group_leader(tsk)) { | 808 | if (!thread_group_leader(tsk)) { |
| 813 | leader = tsk->group_leader; | 809 | struct task_struct *leader = tsk->group_leader; |
| 814 | 810 | ||
| 815 | sig->notify_count = -1; /* for exit_notify() */ | 811 | sig->notify_count = -1; /* for exit_notify() */ |
| 816 | for (;;) { | 812 | for (;;) { |
| @@ -862,8 +858,9 @@ static int de_thread(struct task_struct *tsk) | |||
| 862 | 858 | ||
| 863 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); | 859 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); |
| 864 | leader->exit_state = EXIT_DEAD; | 860 | leader->exit_state = EXIT_DEAD; |
| 865 | |||
| 866 | write_unlock_irq(&tasklist_lock); | 861 | write_unlock_irq(&tasklist_lock); |
| 862 | |||
| 863 | release_task(leader); | ||
| 867 | } | 864 | } |
| 868 | 865 | ||
| 869 | sig->group_exit_task = NULL; | 866 | sig->group_exit_task = NULL; |
| @@ -872,8 +869,6 @@ static int de_thread(struct task_struct *tsk) | |||
| 872 | no_thread_group: | 869 | no_thread_group: |
| 873 | exit_itimers(sig); | 870 | exit_itimers(sig); |
| 874 | flush_itimer_signals(); | 871 | flush_itimer_signals(); |
| 875 | if (leader) | ||
| 876 | release_task(leader); | ||
| 877 | 872 | ||
| 878 | if (atomic_read(&oldsighand->count) != 1) { | 873 | if (atomic_read(&oldsighand->count) != 1) { |
| 879 | struct sighand_struct *newsighand; | 874 | struct sighand_struct *newsighand; |
| @@ -980,7 +975,7 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
| 980 | /* This is the point of no return */ | 975 | /* This is the point of no return */ |
| 981 | current->sas_ss_sp = current->sas_ss_size = 0; | 976 | current->sas_ss_sp = current->sas_ss_size = 0; |
| 982 | 977 | ||
| 983 | if (current->euid == current->uid && current->egid == current->gid) | 978 | if (current_euid() == current_uid() && current_egid() == current_gid()) |
| 984 | set_dumpable(current->mm, 1); | 979 | set_dumpable(current->mm, 1); |
| 985 | else | 980 | else |
| 986 | set_dumpable(current->mm, suid_dumpable); | 981 | set_dumpable(current->mm, suid_dumpable); |
| @@ -1007,16 +1002,17 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
| 1007 | */ | 1002 | */ |
| 1008 | current->mm->task_size = TASK_SIZE; | 1003 | current->mm->task_size = TASK_SIZE; |
| 1009 | 1004 | ||
| 1010 | if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) { | 1005 | /* install the new credentials */ |
| 1011 | suid_keys(current); | 1006 | if (bprm->cred->uid != current_euid() || |
| 1012 | set_dumpable(current->mm, suid_dumpable); | 1007 | bprm->cred->gid != current_egid()) { |
| 1013 | current->pdeath_signal = 0; | 1008 | current->pdeath_signal = 0; |
| 1014 | } else if (file_permission(bprm->file, MAY_READ) || | 1009 | } else if (file_permission(bprm->file, MAY_READ) || |
| 1015 | (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { | 1010 | bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) { |
| 1016 | suid_keys(current); | ||
| 1017 | set_dumpable(current->mm, suid_dumpable); | 1011 | set_dumpable(current->mm, suid_dumpable); |
| 1018 | } | 1012 | } |
| 1019 | 1013 | ||
| 1014 | current->personality &= ~bprm->per_clear; | ||
| 1015 | |||
| 1020 | /* An exec changes our domain. We are no longer part of the thread | 1016 | /* An exec changes our domain. We are no longer part of the thread |
| 1021 | group */ | 1017 | group */ |
| 1022 | 1018 | ||
| @@ -1033,13 +1029,50 @@ out: | |||
| 1033 | 1029 | ||
| 1034 | EXPORT_SYMBOL(flush_old_exec); | 1030 | EXPORT_SYMBOL(flush_old_exec); |
| 1035 | 1031 | ||
| 1032 | /* | ||
| 1033 | * install the new credentials for this executable | ||
| 1034 | */ | ||
| 1035 | void install_exec_creds(struct linux_binprm *bprm) | ||
| 1036 | { | ||
| 1037 | security_bprm_committing_creds(bprm); | ||
| 1038 | |||
| 1039 | commit_creds(bprm->cred); | ||
| 1040 | bprm->cred = NULL; | ||
| 1041 | |||
| 1042 | /* cred_exec_mutex must be held at least to this point to prevent | ||
| 1043 | * ptrace_attach() from altering our determination of the task's | ||
| 1044 | * credentials; any time after this it may be unlocked */ | ||
| 1045 | |||
| 1046 | security_bprm_committed_creds(bprm); | ||
| 1047 | } | ||
| 1048 | EXPORT_SYMBOL(install_exec_creds); | ||
| 1049 | |||
| 1050 | /* | ||
| 1051 | * determine how safe it is to execute the proposed program | ||
| 1052 | * - the caller must hold current->cred_exec_mutex to protect against | ||
| 1053 | * PTRACE_ATTACH | ||
| 1054 | */ | ||
| 1055 | void check_unsafe_exec(struct linux_binprm *bprm) | ||
| 1056 | { | ||
| 1057 | struct task_struct *p = current; | ||
| 1058 | |||
| 1059 | bprm->unsafe = tracehook_unsafe_exec(p); | ||
| 1060 | |||
| 1061 | if (atomic_read(&p->fs->count) > 1 || | ||
| 1062 | atomic_read(&p->files->count) > 1 || | ||
| 1063 | atomic_read(&p->sighand->count) > 1) | ||
| 1064 | bprm->unsafe |= LSM_UNSAFE_SHARE; | ||
| 1065 | } | ||
| 1066 | |||
| 1036 | /* | 1067 | /* |
| 1037 | * Fill the binprm structure from the inode. | 1068 | * Fill the binprm structure from the inode. |
| 1038 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes | 1069 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes |
| 1070 | * | ||
| 1071 | * This may be called multiple times for binary chains (scripts for example). | ||
| 1039 | */ | 1072 | */ |
| 1040 | int prepare_binprm(struct linux_binprm *bprm) | 1073 | int prepare_binprm(struct linux_binprm *bprm) |
| 1041 | { | 1074 | { |
| 1042 | int mode; | 1075 | umode_t mode; |
| 1043 | struct inode * inode = bprm->file->f_path.dentry->d_inode; | 1076 | struct inode * inode = bprm->file->f_path.dentry->d_inode; |
| 1044 | int retval; | 1077 | int retval; |
| 1045 | 1078 | ||
| @@ -1047,14 +1080,15 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
| 1047 | if (bprm->file->f_op == NULL) | 1080 | if (bprm->file->f_op == NULL) |
| 1048 | return -EACCES; | 1081 | return -EACCES; |
| 1049 | 1082 | ||
| 1050 | bprm->e_uid = current->euid; | 1083 | /* clear any previous set[ug]id data from a previous binary */ |
| 1051 | bprm->e_gid = current->egid; | 1084 | bprm->cred->euid = current_euid(); |
| 1085 | bprm->cred->egid = current_egid(); | ||
| 1052 | 1086 | ||
| 1053 | if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { | 1087 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { |
| 1054 | /* Set-uid? */ | 1088 | /* Set-uid? */ |
| 1055 | if (mode & S_ISUID) { | 1089 | if (mode & S_ISUID) { |
| 1056 | current->personality &= ~PER_CLEAR_ON_SETID; | 1090 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
| 1057 | bprm->e_uid = inode->i_uid; | 1091 | bprm->cred->euid = inode->i_uid; |
| 1058 | } | 1092 | } |
| 1059 | 1093 | ||
| 1060 | /* Set-gid? */ | 1094 | /* Set-gid? */ |
| @@ -1064,52 +1098,23 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
| 1064 | * executable. | 1098 | * executable. |
| 1065 | */ | 1099 | */ |
| 1066 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | 1100 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
| 1067 | current->personality &= ~PER_CLEAR_ON_SETID; | 1101 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
| 1068 | bprm->e_gid = inode->i_gid; | 1102 | bprm->cred->egid = inode->i_gid; |
| 1069 | } | 1103 | } |
| 1070 | } | 1104 | } |
| 1071 | 1105 | ||
| 1072 | /* fill in binprm security blob */ | 1106 | /* fill in binprm security blob */ |
| 1073 | retval = security_bprm_set(bprm); | 1107 | retval = security_bprm_set_creds(bprm); |
| 1074 | if (retval) | 1108 | if (retval) |
| 1075 | return retval; | 1109 | return retval; |
| 1110 | bprm->cred_prepared = 1; | ||
| 1076 | 1111 | ||
| 1077 | memset(bprm->buf,0,BINPRM_BUF_SIZE); | 1112 | memset(bprm->buf, 0, BINPRM_BUF_SIZE); |
| 1078 | return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); | 1113 | return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); |
| 1079 | } | 1114 | } |
| 1080 | 1115 | ||
| 1081 | EXPORT_SYMBOL(prepare_binprm); | 1116 | EXPORT_SYMBOL(prepare_binprm); |
| 1082 | 1117 | ||
| 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 | /* | 1118 | /* |
| 1114 | * Arguments are '\0' separated strings found at the location bprm->p | 1119 | * 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 | 1120 | * points to; chop off the first by relocating brpm->p to right after |
| @@ -1162,41 +1167,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
| 1162 | unsigned int depth = bprm->recursion_depth; | 1167 | unsigned int depth = bprm->recursion_depth; |
| 1163 | int try,retval; | 1168 | int try,retval; |
| 1164 | struct linux_binfmt *fmt; | 1169 | 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 | 1170 | ||
| 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); | 1171 | retval = security_bprm_check(bprm); |
| 1201 | if (retval) | 1172 | if (retval) |
| 1202 | return retval; | 1173 | return retval; |
| @@ -1270,6 +1241,8 @@ EXPORT_SYMBOL(search_binary_handler); | |||
| 1270 | void free_bprm(struct linux_binprm *bprm) | 1241 | void free_bprm(struct linux_binprm *bprm) |
| 1271 | { | 1242 | { |
| 1272 | free_arg_pages(bprm); | 1243 | free_arg_pages(bprm); |
| 1244 | if (bprm->cred) | ||
| 1245 | abort_creds(bprm->cred); | ||
| 1273 | kfree(bprm); | 1246 | kfree(bprm); |
| 1274 | } | 1247 | } |
| 1275 | 1248 | ||
| @@ -1295,10 +1268,20 @@ int do_execve(char * filename, | |||
| 1295 | if (!bprm) | 1268 | if (!bprm) |
| 1296 | goto out_files; | 1269 | goto out_files; |
| 1297 | 1270 | ||
| 1271 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | ||
| 1272 | if (retval < 0) | ||
| 1273 | goto out_free; | ||
| 1274 | |||
| 1275 | retval = -ENOMEM; | ||
| 1276 | bprm->cred = prepare_exec_creds(); | ||
| 1277 | if (!bprm->cred) | ||
| 1278 | goto out_unlock; | ||
| 1279 | check_unsafe_exec(bprm); | ||
| 1280 | |||
| 1298 | file = open_exec(filename); | 1281 | file = open_exec(filename); |
| 1299 | retval = PTR_ERR(file); | 1282 | retval = PTR_ERR(file); |
| 1300 | if (IS_ERR(file)) | 1283 | if (IS_ERR(file)) |
| 1301 | goto out_kfree; | 1284 | goto out_unlock; |
| 1302 | 1285 | ||
| 1303 | sched_exec(); | 1286 | sched_exec(); |
| 1304 | 1287 | ||
| @@ -1312,14 +1295,10 @@ int do_execve(char * filename, | |||
| 1312 | 1295 | ||
| 1313 | bprm->argc = count(argv, MAX_ARG_STRINGS); | 1296 | bprm->argc = count(argv, MAX_ARG_STRINGS); |
| 1314 | if ((retval = bprm->argc) < 0) | 1297 | if ((retval = bprm->argc) < 0) |
| 1315 | goto out_mm; | 1298 | goto out; |
| 1316 | 1299 | ||
| 1317 | bprm->envc = count(envp, MAX_ARG_STRINGS); | 1300 | bprm->envc = count(envp, MAX_ARG_STRINGS); |
| 1318 | if ((retval = bprm->envc) < 0) | 1301 | if ((retval = bprm->envc) < 0) |
| 1319 | goto out_mm; | ||
| 1320 | |||
| 1321 | retval = security_bprm_alloc(bprm); | ||
| 1322 | if (retval) | ||
| 1323 | goto out; | 1302 | goto out; |
| 1324 | 1303 | ||
| 1325 | retval = prepare_binprm(bprm); | 1304 | retval = prepare_binprm(bprm); |
| @@ -1341,21 +1320,18 @@ int do_execve(char * filename, | |||
| 1341 | 1320 | ||
| 1342 | current->flags &= ~PF_KTHREAD; | 1321 | current->flags &= ~PF_KTHREAD; |
| 1343 | retval = search_binary_handler(bprm,regs); | 1322 | retval = search_binary_handler(bprm,regs); |
| 1344 | if (retval >= 0) { | 1323 | if (retval < 0) |
| 1345 | /* execve success */ | 1324 | 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 | 1325 | ||
| 1354 | out: | 1326 | /* execve succeeded */ |
| 1355 | if (bprm->security) | 1327 | mutex_unlock(¤t->cred_exec_mutex); |
| 1356 | security_bprm_free(bprm); | 1328 | acct_update_integrals(current); |
| 1329 | free_bprm(bprm); | ||
| 1330 | if (displaced) | ||
| 1331 | put_files_struct(displaced); | ||
| 1332 | return retval; | ||
| 1357 | 1333 | ||
| 1358 | out_mm: | 1334 | out: |
| 1359 | if (bprm->mm) | 1335 | if (bprm->mm) |
| 1360 | mmput (bprm->mm); | 1336 | mmput (bprm->mm); |
| 1361 | 1337 | ||
| @@ -1364,7 +1340,11 @@ out_file: | |||
| 1364 | allow_write_access(bprm->file); | 1340 | allow_write_access(bprm->file); |
| 1365 | fput(bprm->file); | 1341 | fput(bprm->file); |
| 1366 | } | 1342 | } |
| 1367 | out_kfree: | 1343 | |
| 1344 | out_unlock: | ||
| 1345 | mutex_unlock(¤t->cred_exec_mutex); | ||
| 1346 | |||
| 1347 | out_free: | ||
| 1368 | free_bprm(bprm); | 1348 | free_bprm(bprm); |
| 1369 | 1349 | ||
| 1370 | out_files: | 1350 | out_files: |
| @@ -1396,6 +1376,7 @@ EXPORT_SYMBOL(set_binfmt); | |||
| 1396 | */ | 1376 | */ |
| 1397 | static int format_corename(char *corename, long signr) | 1377 | static int format_corename(char *corename, long signr) |
| 1398 | { | 1378 | { |
| 1379 | const struct cred *cred = current_cred(); | ||
| 1399 | const char *pat_ptr = core_pattern; | 1380 | const char *pat_ptr = core_pattern; |
| 1400 | int ispipe = (*pat_ptr == '|'); | 1381 | int ispipe = (*pat_ptr == '|'); |
| 1401 | char *out_ptr = corename; | 1382 | char *out_ptr = corename; |
| @@ -1432,7 +1413,7 @@ static int format_corename(char *corename, long signr) | |||
| 1432 | /* uid */ | 1413 | /* uid */ |
| 1433 | case 'u': | 1414 | case 'u': |
| 1434 | rc = snprintf(out_ptr, out_end - out_ptr, | 1415 | rc = snprintf(out_ptr, out_end - out_ptr, |
| 1435 | "%d", current->uid); | 1416 | "%d", cred->uid); |
| 1436 | if (rc > out_end - out_ptr) | 1417 | if (rc > out_end - out_ptr) |
| 1437 | goto out; | 1418 | goto out; |
| 1438 | out_ptr += rc; | 1419 | out_ptr += rc; |
| @@ -1440,7 +1421,7 @@ static int format_corename(char *corename, long signr) | |||
| 1440 | /* gid */ | 1421 | /* gid */ |
| 1441 | case 'g': | 1422 | case 'g': |
| 1442 | rc = snprintf(out_ptr, out_end - out_ptr, | 1423 | rc = snprintf(out_ptr, out_end - out_ptr, |
| 1443 | "%d", current->gid); | 1424 | "%d", cred->gid); |
| 1444 | if (rc > out_end - out_ptr) | 1425 | if (rc > out_end - out_ptr) |
| 1445 | goto out; | 1426 | goto out; |
| 1446 | out_ptr += rc; | 1427 | out_ptr += rc; |
| @@ -1716,8 +1697,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1716 | struct linux_binfmt * binfmt; | 1697 | struct linux_binfmt * binfmt; |
| 1717 | struct inode * inode; | 1698 | struct inode * inode; |
| 1718 | struct file * file; | 1699 | struct file * file; |
| 1700 | const struct cred *old_cred; | ||
| 1701 | struct cred *cred; | ||
| 1719 | int retval = 0; | 1702 | int retval = 0; |
| 1720 | int fsuid = current->fsuid; | ||
| 1721 | int flag = 0; | 1703 | int flag = 0; |
| 1722 | int ispipe = 0; | 1704 | int ispipe = 0; |
| 1723 | unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1705 | unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
| @@ -1730,12 +1712,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1730 | binfmt = current->binfmt; | 1712 | binfmt = current->binfmt; |
| 1731 | if (!binfmt || !binfmt->core_dump) | 1713 | if (!binfmt || !binfmt->core_dump) |
| 1732 | goto fail; | 1714 | goto fail; |
| 1715 | |||
| 1716 | cred = prepare_creds(); | ||
| 1717 | if (!cred) { | ||
| 1718 | retval = -ENOMEM; | ||
| 1719 | goto fail; | ||
| 1720 | } | ||
| 1721 | |||
| 1733 | down_write(&mm->mmap_sem); | 1722 | down_write(&mm->mmap_sem); |
| 1734 | /* | 1723 | /* |
| 1735 | * If another thread got here first, or we are not dumpable, bail out. | 1724 | * If another thread got here first, or we are not dumpable, bail out. |
| 1736 | */ | 1725 | */ |
| 1737 | if (mm->core_state || !get_dumpable(mm)) { | 1726 | if (mm->core_state || !get_dumpable(mm)) { |
| 1738 | up_write(&mm->mmap_sem); | 1727 | up_write(&mm->mmap_sem); |
| 1728 | put_cred(cred); | ||
| 1739 | goto fail; | 1729 | goto fail; |
| 1740 | } | 1730 | } |
| 1741 | 1731 | ||
| @@ -1746,12 +1736,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1746 | */ | 1736 | */ |
| 1747 | if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ | 1737 | if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ |
| 1748 | flag = O_EXCL; /* Stop rewrite attacks */ | 1738 | flag = O_EXCL; /* Stop rewrite attacks */ |
| 1749 | current->fsuid = 0; /* Dump root private */ | 1739 | cred->fsuid = 0; /* Dump root private */ |
| 1750 | } | 1740 | } |
| 1751 | 1741 | ||
| 1752 | retval = coredump_wait(exit_code, &core_state); | 1742 | retval = coredump_wait(exit_code, &core_state); |
| 1753 | if (retval < 0) | 1743 | if (retval < 0) { |
| 1744 | put_cred(cred); | ||
| 1754 | goto fail; | 1745 | goto fail; |
| 1746 | } | ||
| 1747 | |||
| 1748 | old_cred = override_creds(cred); | ||
| 1755 | 1749 | ||
| 1756 | /* | 1750 | /* |
| 1757 | * Clear any false indication of pending signals that might | 1751 | * Clear any false indication of pending signals that might |
| @@ -1823,7 +1817,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 | 1817 | * Dont allow local users get cute and trick others to coredump |
| 1824 | * into their pre-created files: | 1818 | * into their pre-created files: |
| 1825 | */ | 1819 | */ |
| 1826 | if (inode->i_uid != current->fsuid) | 1820 | if (inode->i_uid != current_fsuid()) |
| 1827 | goto close_fail; | 1821 | goto close_fail; |
| 1828 | if (!file->f_op) | 1822 | if (!file->f_op) |
| 1829 | goto close_fail; | 1823 | goto close_fail; |
| @@ -1842,7 +1836,8 @@ fail_unlock: | |||
| 1842 | if (helper_argv) | 1836 | if (helper_argv) |
| 1843 | argv_free(helper_argv); | 1837 | argv_free(helper_argv); |
| 1844 | 1838 | ||
| 1845 | current->fsuid = fsuid; | 1839 | revert_creds(old_cred); |
| 1840 | put_cred(cred); | ||
| 1846 | coredump_finish(mm); | 1841 | coredump_finish(mm); |
| 1847 | fail: | 1842 | fail: |
| 1848 | return retval; | 1843 | return retval; |
