diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 86 |
1 files changed, 24 insertions, 62 deletions
@@ -52,17 +52,13 @@ | |||
52 | #include <linux/audit.h> | 52 | #include <linux/audit.h> |
53 | #include <linux/tracehook.h> | 53 | #include <linux/tracehook.h> |
54 | #include <linux/kmod.h> | 54 | #include <linux/kmod.h> |
55 | #include <linux/fsnotify.h> | ||
55 | 56 | ||
56 | #include <asm/uaccess.h> | 57 | #include <asm/uaccess.h> |
57 | #include <asm/mmu_context.h> | 58 | #include <asm/mmu_context.h> |
58 | #include <asm/tlb.h> | 59 | #include <asm/tlb.h> |
59 | #include "internal.h" | 60 | #include "internal.h" |
60 | 61 | ||
61 | #ifdef __alpha__ | ||
62 | /* for /sbin/loader handling in search_binary_handler() */ | ||
63 | #include <linux/a.out.h> | ||
64 | #endif | ||
65 | |||
66 | int core_uses_pid; | 62 | int core_uses_pid; |
67 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | 63 | char core_pattern[CORENAME_MAX_SIZE] = "core"; |
68 | int suid_dumpable = 0; | 64 | int suid_dumpable = 0; |
@@ -128,7 +124,8 @@ asmlinkage long sys_uselib(const char __user * library) | |||
128 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | 124 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) |
129 | goto exit; | 125 | goto exit; |
130 | 126 | ||
131 | error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN); | 127 | error = inode_permission(nd.path.dentry->d_inode, |
128 | MAY_READ | MAY_EXEC | MAY_OPEN); | ||
132 | if (error) | 129 | if (error) |
133 | goto exit; | 130 | goto exit; |
134 | 131 | ||
@@ -137,6 +134,8 @@ asmlinkage long sys_uselib(const char __user * library) | |||
137 | if (IS_ERR(file)) | 134 | if (IS_ERR(file)) |
138 | goto out; | 135 | goto out; |
139 | 136 | ||
137 | fsnotify_open(file->f_path.dentry); | ||
138 | |||
140 | error = -ENOEXEC; | 139 | error = -ENOEXEC; |
141 | if(file->f_op) { | 140 | if(file->f_op) { |
142 | struct linux_binfmt * fmt; | 141 | struct linux_binfmt * fmt; |
@@ -234,13 +233,13 @@ static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos, | |||
234 | 233 | ||
235 | static int __bprm_mm_init(struct linux_binprm *bprm) | 234 | static int __bprm_mm_init(struct linux_binprm *bprm) |
236 | { | 235 | { |
237 | int err = -ENOMEM; | 236 | int err; |
238 | struct vm_area_struct *vma = NULL; | 237 | struct vm_area_struct *vma = NULL; |
239 | struct mm_struct *mm = bprm->mm; | 238 | struct mm_struct *mm = bprm->mm; |
240 | 239 | ||
241 | bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); | 240 | bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); |
242 | if (!vma) | 241 | if (!vma) |
243 | goto err; | 242 | return -ENOMEM; |
244 | 243 | ||
245 | down_write(&mm->mmap_sem); | 244 | down_write(&mm->mmap_sem); |
246 | vma->vm_mm = mm; | 245 | vma->vm_mm = mm; |
@@ -253,28 +252,20 @@ static int __bprm_mm_init(struct linux_binprm *bprm) | |||
253 | */ | 252 | */ |
254 | vma->vm_end = STACK_TOP_MAX; | 253 | vma->vm_end = STACK_TOP_MAX; |
255 | vma->vm_start = vma->vm_end - PAGE_SIZE; | 254 | vma->vm_start = vma->vm_end - PAGE_SIZE; |
256 | |||
257 | vma->vm_flags = VM_STACK_FLAGS; | 255 | vma->vm_flags = VM_STACK_FLAGS; |
258 | vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); | 256 | vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); |
259 | err = insert_vm_struct(mm, vma); | 257 | err = insert_vm_struct(mm, vma); |
260 | if (err) { | 258 | if (err) |
261 | up_write(&mm->mmap_sem); | ||
262 | goto err; | 259 | goto err; |
263 | } | ||
264 | 260 | ||
265 | mm->stack_vm = mm->total_vm = 1; | 261 | mm->stack_vm = mm->total_vm = 1; |
266 | up_write(&mm->mmap_sem); | 262 | up_write(&mm->mmap_sem); |
267 | |||
268 | bprm->p = vma->vm_end - sizeof(void *); | 263 | bprm->p = vma->vm_end - sizeof(void *); |
269 | |||
270 | return 0; | 264 | return 0; |
271 | |||
272 | err: | 265 | err: |
273 | if (vma) { | 266 | up_write(&mm->mmap_sem); |
274 | bprm->vma = NULL; | 267 | bprm->vma = NULL; |
275 | kmem_cache_free(vm_area_cachep, vma); | 268 | kmem_cache_free(vm_area_cachep, vma); |
276 | } | ||
277 | |||
278 | return err; | 269 | return err; |
279 | } | 270 | } |
280 | 271 | ||
@@ -681,7 +672,7 @@ struct file *open_exec(const char *name) | |||
681 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | 672 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) |
682 | goto out_path_put; | 673 | goto out_path_put; |
683 | 674 | ||
684 | err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); | 675 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); |
685 | if (err) | 676 | if (err) |
686 | goto out_path_put; | 677 | goto out_path_put; |
687 | 678 | ||
@@ -689,6 +680,8 @@ struct file *open_exec(const char *name) | |||
689 | if (IS_ERR(file)) | 680 | if (IS_ERR(file)) |
690 | return file; | 681 | return file; |
691 | 682 | ||
683 | fsnotify_open(file->f_path.dentry); | ||
684 | |||
692 | err = deny_write_access(file); | 685 | err = deny_write_access(file); |
693 | if (err) { | 686 | if (err) { |
694 | fput(file); | 687 | fput(file); |
@@ -774,7 +767,6 @@ static int de_thread(struct task_struct *tsk) | |||
774 | struct signal_struct *sig = tsk->signal; | 767 | struct signal_struct *sig = tsk->signal; |
775 | struct sighand_struct *oldsighand = tsk->sighand; | 768 | struct sighand_struct *oldsighand = tsk->sighand; |
776 | spinlock_t *lock = &oldsighand->siglock; | 769 | spinlock_t *lock = &oldsighand->siglock; |
777 | struct task_struct *leader = NULL; | ||
778 | int count; | 770 | int count; |
779 | 771 | ||
780 | if (thread_group_empty(tsk)) | 772 | if (thread_group_empty(tsk)) |
@@ -812,7 +804,7 @@ static int de_thread(struct task_struct *tsk) | |||
812 | * and to assume its PID: | 804 | * and to assume its PID: |
813 | */ | 805 | */ |
814 | if (!thread_group_leader(tsk)) { | 806 | if (!thread_group_leader(tsk)) { |
815 | leader = tsk->group_leader; | 807 | struct task_struct *leader = tsk->group_leader; |
816 | 808 | ||
817 | sig->notify_count = -1; /* for exit_notify() */ | 809 | sig->notify_count = -1; /* for exit_notify() */ |
818 | for (;;) { | 810 | for (;;) { |
@@ -864,8 +856,9 @@ static int de_thread(struct task_struct *tsk) | |||
864 | 856 | ||
865 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); | 857 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); |
866 | leader->exit_state = EXIT_DEAD; | 858 | leader->exit_state = EXIT_DEAD; |
867 | |||
868 | write_unlock_irq(&tasklist_lock); | 859 | write_unlock_irq(&tasklist_lock); |
860 | |||
861 | release_task(leader); | ||
869 | } | 862 | } |
870 | 863 | ||
871 | sig->group_exit_task = NULL; | 864 | sig->group_exit_task = NULL; |
@@ -874,8 +867,6 @@ static int de_thread(struct task_struct *tsk) | |||
874 | no_thread_group: | 867 | no_thread_group: |
875 | exit_itimers(sig); | 868 | exit_itimers(sig); |
876 | flush_itimer_signals(); | 869 | flush_itimer_signals(); |
877 | if (leader) | ||
878 | release_task(leader); | ||
879 | 870 | ||
880 | if (atomic_read(&oldsighand->count) != 1) { | 871 | if (atomic_read(&oldsighand->count) != 1) { |
881 | struct sighand_struct *newsighand; | 872 | struct sighand_struct *newsighand; |
@@ -1181,41 +1172,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1181 | unsigned int depth = bprm->recursion_depth; | 1172 | unsigned int depth = bprm->recursion_depth; |
1182 | int try,retval; | 1173 | int try,retval; |
1183 | struct linux_binfmt *fmt; | 1174 | struct linux_binfmt *fmt; |
1184 | #ifdef __alpha__ | ||
1185 | /* handle /sbin/loader.. */ | ||
1186 | { | ||
1187 | struct exec * eh = (struct exec *) bprm->buf; | ||
1188 | |||
1189 | if (!bprm->loader && eh->fh.f_magic == 0x183 && | ||
1190 | (eh->fh.f_flags & 0x3000) == 0x3000) | ||
1191 | { | ||
1192 | struct file * file; | ||
1193 | unsigned long loader; | ||
1194 | 1175 | ||
1195 | allow_write_access(bprm->file); | ||
1196 | fput(bprm->file); | ||
1197 | bprm->file = NULL; | ||
1198 | |||
1199 | loader = bprm->vma->vm_end - sizeof(void *); | ||
1200 | |||
1201 | file = open_exec("/sbin/loader"); | ||
1202 | retval = PTR_ERR(file); | ||
1203 | if (IS_ERR(file)) | ||
1204 | return retval; | ||
1205 | |||
1206 | /* Remember if the application is TASO. */ | ||
1207 | bprm->taso = eh->ah.entry < 0x100000000UL; | ||
1208 | |||
1209 | bprm->file = file; | ||
1210 | bprm->loader = loader; | ||
1211 | retval = prepare_binprm(bprm); | ||
1212 | if (retval<0) | ||
1213 | return retval; | ||
1214 | /* should call search_binary_handler recursively here, | ||
1215 | but it does not matter */ | ||
1216 | } | ||
1217 | } | ||
1218 | #endif | ||
1219 | retval = security_bprm_check(bprm); | 1176 | retval = security_bprm_check(bprm); |
1220 | if (retval) | 1177 | if (retval) |
1221 | return retval; | 1178 | return retval; |
@@ -1737,7 +1694,7 @@ int get_dumpable(struct mm_struct *mm) | |||
1737 | return (ret >= 2) ? 2 : ret; | 1694 | return (ret >= 2) ? 2 : ret; |
1738 | } | 1695 | } |
1739 | 1696 | ||
1740 | int do_coredump(long signr, int exit_code, struct pt_regs * regs) | 1697 | void do_coredump(long signr, int exit_code, struct pt_regs *regs) |
1741 | { | 1698 | { |
1742 | struct core_state core_state; | 1699 | struct core_state core_state; |
1743 | char corename[CORENAME_MAX_SIZE + 1]; | 1700 | char corename[CORENAME_MAX_SIZE + 1]; |
@@ -1821,6 +1778,11 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1821 | 1778 | ||
1822 | if (ispipe) { | 1779 | if (ispipe) { |
1823 | helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); | 1780 | helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); |
1781 | if (!helper_argv) { | ||
1782 | printk(KERN_WARNING "%s failed to allocate memory\n", | ||
1783 | __func__); | ||
1784 | goto fail_unlock; | ||
1785 | } | ||
1824 | /* Terminate the string before the first option */ | 1786 | /* Terminate the string before the first option */ |
1825 | delimit = strchr(corename, ' '); | 1787 | delimit = strchr(corename, ' '); |
1826 | if (delimit) | 1788 | if (delimit) |
@@ -1888,5 +1850,5 @@ fail_unlock: | |||
1888 | put_cred(cred); | 1850 | put_cred(cred); |
1889 | coredump_finish(mm); | 1851 | coredump_finish(mm); |
1890 | fail: | 1852 | fail: |
1891 | return retval; | 1853 | return; |
1892 | } | 1854 | } |