diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 271 |
1 files changed, 134 insertions, 137 deletions
@@ -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 | ||
64 | int core_uses_pid; | 61 | int core_uses_pid; |
65 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | 62 | char 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 | */ |
105 | asmlinkage long sys_uselib(const char __user * library) | 102 | SYSCALL_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 | ||
233 | static int __bprm_mm_init(struct linux_binprm *bprm) | 233 | static 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 | |||
270 | err: | 264 | err: |
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) | |||
872 | no_thread_group: | 866 | no_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 | ||
1034 | EXPORT_SYMBOL(flush_old_exec); | 1027 | EXPORT_SYMBOL(flush_old_exec); |
1035 | 1028 | ||
1029 | /* | ||
1030 | * install the new credentials for this executable | ||
1031 | */ | ||
1032 | void 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 | } | ||
1045 | EXPORT_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 | */ | ||
1052 | void 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 | */ |
1040 | int prepare_binprm(struct linux_binprm *bprm) | 1070 | int 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 | ||
1081 | EXPORT_SYMBOL(prepare_binprm); | 1113 | EXPORT_SYMBOL(prepare_binprm); |
1082 | 1114 | ||
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 | /* | 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); | |||
1270 | void free_bprm(struct linux_binprm *bprm) | 1238 | void 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(¤t->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 | ||
1354 | out: | 1323 | /* execve succeeded */ |
1355 | if (bprm->security) | 1324 | mutex_unlock(¤t->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 | ||
1358 | out_mm: | 1331 | out: |
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 | } |
1367 | out_kfree: | 1340 | |
1341 | out_unlock: | ||
1342 | mutex_unlock(¤t->cred_exec_mutex); | ||
1343 | |||
1344 | out_free: | ||
1368 | free_bprm(bprm); | 1345 | free_bprm(bprm); |
1369 | 1346 | ||
1370 | out_files: | 1347 | out_files: |
@@ -1396,6 +1373,7 @@ EXPORT_SYMBOL(set_binfmt); | |||
1396 | */ | 1373 | */ |
1397 | static int format_corename(char *corename, long signr) | 1374 | static 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 | ||
1711 | int do_coredump(long signr, int exit_code, struct pt_regs * regs) | 1689 | void 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); |
1847 | fail: | 1844 | fail: |
1848 | return retval; | 1845 | return; |
1849 | } | 1846 | } |