| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * linux/fs/exec.c | |||
| 3 | * | |||
| 4 | * Copyright (C) 1991, 1992 Linus Torvalds | |||
| 5 | */ | |||
| 6 | ||||
| 7 | /* | |||
| 8 | * #!-checking implemented by tytso. | |||
| 9 | */ | |||
| 10 | /* | |||
| 11 | * Demand-loading implemented 01.12.91 - no need to read anything but | |||
| 12 | * the header into memory. The inode of the executable is put into | |||
| 13 | * "current->executable", and page faults do the actual loading. Clean. | |||
| 14 | * | |||
| 15 | * Once more I can proudly say that linux stood up to being changed: it | |||
| 16 | * was less than 2 hours work to get demand-loading completely implemented. | |||
| 17 | * | |||
| 18 | * Demand loading changed July 1993 by Eric Youngdale. Use mmap instead, | |||
| 19 | * current->executable is only used by the procfs. This allows a dispatch | |||
| 20 | * table to check for several different types of binary formats. We keep | |||
| 21 | * trying until we recognize the file or we run out of supported binary | |||
| 22 | * formats. | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include <linux/config.h> | |||
| 26 | #include <linux/slab.h> | |||
| 27 | #include <linux/file.h> | |||
| 28 | #include <linux/mman.h> | |||
| 29 | #include <linux/a.out.h> | |||
| 30 | #include <linux/stat.h> | |||
| 31 | #include <linux/fcntl.h> | |||
| 32 | #include <linux/smp_lock.h> | |||
| 33 | #include <linux/init.h> | |||
| 34 | #include <linux/pagemap.h> | |||
| 35 | #include <linux/highmem.h> | |||
| 36 | #include <linux/spinlock.h> | |||
| 37 | #include <linux/key.h> | |||
| 38 | #include <linux/personality.h> | |||
| 39 | #include <linux/binfmts.h> | |||
| 40 | #include <linux/swap.h> | |||
| 41 | #include <linux/utsname.h> | |||
| 42 | #include <linux/module.h> | |||
| 43 | #include <linux/namei.h> | |||
| 44 | #include <linux/proc_fs.h> | |||
| 45 | #include <linux/ptrace.h> | |||
| 46 | #include <linux/mount.h> | |||
| 47 | #include <linux/security.h> | |||
| 48 | #include <linux/syscalls.h> | |||
| 49 | #include <linux/rmap.h> | |||
| 50 | #include <linux/acct.h> | |||
| 51 | #include <linux/cn_proc.h> | |||
| 52 | ||||
| 53 | #include <asm/uaccess.h> | |||
| 54 | #include <asm/mmu_context.h> | |||
| 55 | ||||
| 56 | #ifdef CONFIG_KMOD | |||
| 57 | #include <linux/kmod.h> | |||
| 58 | #endif | |||
| 59 | ||||
| 60 | int core_uses_pid; | |||
| 61 | char core_pattern[65] = "core"; | |||
| 62 | int suid_dumpable = 0; | |||
| 63 | ||||
| 64 | EXPORT_SYMBOL(suid_dumpable); | |||
| 65 | /* The maximal length of core_pattern is also specified in sysctl.c */ | |||
| 66 | ||||
| 67 | static struct linux_binfmt *formats; | |||
| 68 | static DEFINE_RWLOCK(binfmt_lock); | |||
| 69 | ||||
| 30 | 0 | 70 | int register_binfmt(struct linux_binfmt * fmt) | |
| 71 | { | |||
| 72 | struct linux_binfmt ** tmp = &formats; | |||
| 73 | ||||
| 0 | 30 | - | 74 | if (!fmt) |
| 0 | - | 75 | return -EINVAL; | |
| 0 | 30 | - | 76 | if (fmt->next) |
| 0 | - | 77 | return -EBUSY; | |
| 78 | write_lock(&binfmt_lock); | |||
| 78 | do | |||
| 0 | 30 | - | 78 | do-while (0) |
| 0 | 30 | - | 78 | do-while (0) |
| 60 | 30 | 79 | while (*tmp) { | |
| 0 | 60 | - | 80 | if (fmt == *tmp) { |
| 81 | write_unlock(&binfmt_lock); | |||
| 81 | do | |||
| 0 | 0 | - | 81 | do-while (0) |
| 0 | 0 | - | 81 | do-while (0) |
| 0 | - | 82 | return -EBUSY; | |
| 83 | } | |||
| 84 | tmp = &(*tmp)->next; | |||
| 85 | } | |||
| 86 | fmt->next = formats; | |||
| 87 | formats = fmt; | |||
| 88 | write_unlock(&binfmt_lock); | |||
| 88 | do | |||
| 0 | 30 | - | 88 | do-while (0) |
| 0 | 30 | - | 88 | do-while (0) |
| 30 | 89 | return 0; | ||
| 90 | } | |||
| 91 | ||||
| 92 | EXPORT_SYMBOL(register_binfmt); | |||
| 93 | ||||
| 0 | 0 | - | 94 | int unregister_binfmt(struct linux_binfmt * fmt) |
| 95 | { | |||
| 96 | struct linux_binfmt ** tmp = &formats; | |||
| 97 | ||||
| 98 | write_lock(&binfmt_lock); | |||
| 98 | do | |||
| 0 | 0 | - | 98 | do-while (0) |
| 0 | 0 | - | 98 | do-while (0) |
| 0 | 0 | - | 99 | while (*tmp) { |
| 0 | 0 | - | 100 | if (fmt == *tmp) { |
| 101 | *tmp = fmt->next; | |||
| 102 | write_unlock(&binfmt_lock); | |||
| 102 | do | |||
| 0 | 0 | - | 102 | do-while (0) |
| 0 | 0 | - | 102 | do-while (0) |
| 0 | - | 103 | return 0; | |
| 104 | } | |||
| 105 | tmp = &(*tmp)->next; | |||
| 106 | } | |||
| 107 | write_unlock(&binfmt_lock); | |||
| 107 | do | |||
| 0 | 0 | - | 107 | do-while (0) |
| 0 | 0 | - | 107 | do-while (0) |
| 0 | - | 108 | return -EINVAL; | |
| 109 | } | |||
| 110 | ||||
| 111 | EXPORT_SYMBOL(unregister_binfmt); | |||
| 112 | ||||
| 140570 | 140570 | 113 | static inline void put_binfmt(struct linux_binfmt * fmt) | |
| 114 | { | |||
| 115 | module_put(fmt->module); | |||
| 116 | } | |||
| 117 | ||||
| 118 | /* | |||
| 119 | * Note that a shared library must be both readable and executable due to | |||
| 120 | * security reasons. | |||
| 121 | * | |||
| 122 | * Also note that we take the address to load from from the file itself. | |||
| 123 | */ | |||
| 0 | 0 | - | 124 | asmlinkage long sys_uselib(const char __user * library) |
| 125 | { | |||
| 126 | struct file * file; | |||
| 127 | struct nameidata nd; | |||
| 128 | int error; | |||
| 129 | ||||
| 130 | error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ); | |||
| 0 | 0 | - | 131 | if (error) |
| 0 | - | 132 | goto out; | |
| 133 | ||||
| 134 | error = -EINVAL; | |||
| 0 | 0 | - | 135 | if (!S_ISREG(nd.dentry->d_inode->i_mode)) |
| 0 | - | 136 | goto exit; | |
| 137 | ||||
| 138 | error = vfs_permission(&nd, MAY_READ | MAY_EXEC); | |||
| 0 | 0 | - | 139 | if (error) |
| 0 | - | 140 | goto exit; | |
| 141 | ||||
| 142 | file = nameidata_to_filp(&nd, O_RDONLY); | |||
| 143 | error = PTR_ERR(file); | |||
| 0 | 0 | - | 144 | if (IS_ERR(file)) |
| 0 | - | 145 | goto out; | |
| 146 | ||||
| 147 | error = -ENOEXEC; | |||
| 0 | 0 | - | 148 | if(file->f_op) { |
| 149 | struct linux_binfmt * fmt; | |||
| 150 | ||||
| 151 | read_lock(&binfmt_lock); | |||
| 151 | do | |||
| 0 | 0 | - | 151 | do-while (0) |
| 0 | 0 | - | 151 | do-while (0) |
| 0 | 0 | - | 152 | for (fmt = formats ; fmt ; fmt = fmt->next) { |
| 0 | 0 | - | 153 | if (!fmt->load_shlib) |
| 0 | - | 154 | continue; | |
| 0 | 0 | - | 155 | if (!try_module_get(fmt->module)) |
| 0 | - | 156 | continue; | |
| 157 | read_unlock(&binfmt_lock); | |||
| 157 | do | |||
| 0 | 0 | - | 157 | do-while (0) |
| 0 | 0 | - | 157 | do-while (0) |
| 158 | error = fmt->load_shlib(file); | |||
| 159 | read_lock(&binfmt_lock); | |||
| 159 | do | |||
| 0 | 0 | - | 159 | do-while (0) |
| 0 | 0 | - | 159 | do-while (0) |
| 160 | put_binfmt(fmt); | |||
| 0 | 0 | - | 161 | if (error != -ENOEXEC) |
| 0 | - | 162 | break; | |
| 163 | } | |||
| 164 | read_unlock(&binfmt_lock); | |||
| 164 | do | |||
| 0 | 0 | - | 164 | do-while (0) |
| 0 | 0 | - | 164 | do-while (0) |
| 165 | } | |||
| 166 | fput(file); | |||
| 167 | out: | |||
| 0 | - | 168 | return error; | |
| 169 | exit: | |||
| 170 | release_open_intent(&nd); | |||
| 171 | path_release(&nd); | |||
| 0 | - | 172 | goto out; | |
| 173 | } | |||
| 174 | ||||
| 175 | /* | |||
| 176 | * count() counts the number of strings in array ARGV. | |||
| 177 | */ | |||
| 129958 | 0 | 178 | static int count(char __user * __user * argv, int max) | |
| 179 | { | |||
| 180 | int i = 0; | |||
| 181 | ||||
| 129952 | 6 | 182 | if (argv != NULL) { | |
| 5337E3 | 0 | - | 183 | for (;;) { |
| 184 | char __user * p; | |||
| 185 | ||||
| 0 | 5337E3 | - | 186 | if (get_user(p, argv)) |
| 0 | - | 187 | return -EFAULT; | |
| 129952 | 5207E3 | 188 | if (!p) | |
| 129952 | 189 | break; | ||
| 190 | argv++; | |||
| 0 | 5207E3 | - | 191 | if(++i > max) |
| 0 | - | 192 | return -E2BIG; | |
| 193 | cond_resched(); | |||
| 194 | } | |||
| 195 | } | |||
| 129958 | 196 | return i; | ||
| 197 | } | |||
| 198 | ||||
| 199 | /* | |||
| 200 | * 'copy_strings()' copies argument/environment strings from user | |||
| 201 | * memory to free pages in kernel mem. These are in a format ready | |||
| 202 | * to be put directly into the top of new user memory. | |||
| 203 | */ | |||
| 200919 | 0 | 204 | static int copy_strings(int argc, char __user * __user * argv, | |
| 205 | struct linux_binprm *bprm) | |||
| 206 | { | |||
| 207 | struct page *kmapped_page = NULL; | |||
| 208 | char *kaddr = NULL; | |||
| 209 | int ret; | |||
| 210 | ||||
| 5278E3 | 200918 | 211 | while (argc-- > 0) { | |
| 212 | char __user *str; | |||
| 213 | int len; | |||
| 214 | unsigned long pos; | |||
| 215 | ||||
| 216 | if (get_user(str, argv+argc) || | |||
| 0 | 5278E3 | - | 217 | !(len = strnlen_user(str, bprm->p))) { |
| 0 | - | 217 | (T) || !(_) | |
| 0 | - | 217 | (F) || !(F) | |
| 5278E3 | 217 | (F) || !(T) | ||
| 218 | ret = -EFAULT; | |||
| 0 | - | 219 | goto out; | |
| 220 | } | |||
| 221 | ||||
| 1 | 5278E3 | 222 | if (bprm->p < len) { | |
| 223 | ret = -E2BIG; | |||
| 1 | 224 | goto out; | ||
| 225 | } | |||
| 226 | ||||
| 227 | bprm->p -= len; | |||
| 228 | /* XXX: add architecture specific overflow check here. */ | |||
| 229 | pos = bprm->p; | |||
| 230 | ||||
| 5308E3 | 5278E3 | 231 | while (len > 0) { | |
| 232 | int i, new, err; | |||
| 233 | int offset, bytes_to_copy; | |||
| 234 | struct page *page; | |||
| 235 | ||||
| 236 | offset = pos % PAGE_SIZE; | |||
| 237 | i = pos/PAGE_SIZE; | |||
| 238 | page = bprm->page[i]; | |||
| 239 | new = 0; | |||
| 94945 | 5213E3 | 240 | if (!page) { | |
| 241 | page = alloc_page(GFP_HIGHUSER); | |||
| 242 | bprm->page[i] = page; | |||
| 0 | 94945 | - | 243 | if (!page) { |
| 244 | ret = -ENOMEM; | |||
| 0 | - | 245 | goto out; | |
| 246 | } | |||
| 247 | new = 1; | |||
| 248 | } | |||
| 249 | ||||
| 287718 | 5020E3 | 250 | if (page != kmapped_page) { | |
| 86974 | 200744 | 251 | if (kmapped_page) | |
| 252 | kunmap(kmapped_page); | |||
| 0 | 86974 | - | 252 | do-while (0) |
| 253 | kmapped_page = page; | |||
| 254 | kaddr = kmap(kmapped_page); | |||
| 255 | } | |||
| 94876 | 5213E3 | 256 | if (new && offset) | |
| 94876 | 256 | T && T | ||
| 69 | 256 | T && F | ||
| 5213E3 | 256 | F && _ | ||
| 257 | memset(kaddr, 0, offset); | |||
| 258 | bytes_to_copy = PAGE_SIZE - offset; | |||
| 5278E3 | 29383 | 259 | if (bytes_to_copy > len) { | |
| 260 | bytes_to_copy = len; | |||
| 65562 | 5213E3 | 261 | if (new) | |
| 262 | memset(kaddr+offset+len, 0, | |||
| 263 | PAGE_SIZE-offset-len); | |||
| 264 | } | |||
| 265 | err = copy_from_user(kaddr+offset, str, bytes_to_copy); | |||
| 0 | 5308E3 | - | 266 | if (err) { |
| 267 | ret = -EFAULT; | |||
| 0 | - | 268 | goto out; | |
| 269 | } | |||
| 270 | ||||
| 271 | pos += bytes_to_copy; | |||
| 272 | str += bytes_to_copy; | |||
| 273 | len -= bytes_to_copy; | |||
| 274 | } | |||
| 275 | } | |||
| 276 | ret = 0; | |||
| 277 | out: | |||
| 200744 | 175 | 278 | if (kmapped_page) | |
| 279 | kunmap(kmapped_page); | |||
| 0 | 200744 | - | 279 | do-while (0) |
| 200919 | 280 | return ret; | ||
| 281 | } | |||
| 282 | ||||
| 283 | /* | |||
| 284 | * Like copy_strings, but get argv and its values from kernel memory. | |||
| 285 | */ | |||
| 70961 | 0 | 286 | int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm) | |
| 287 | { | |||
| 288 | int r; | |||
| 289 | mm_segment_t oldfs = get_fs(); | |||
| 290 | set_fs(KERNEL_DS); | |||
| 291 | r = copy_strings(argc, (char __user * __user *)argv, bprm); | |||
| 292 | set_fs(oldfs); | |||
| 70961 | 293 | return r; | ||
| 294 | } | |||
| 295 | ||||
| 296 | EXPORT_SYMBOL(copy_strings_kernel); | |||
| 297 | ||||
| 298 | #ifdef CONFIG_MMU | |||
| 299 | /* | |||
| 300 | * This routine is used to map in a page into an address space: needed by | |||
| 301 | * execve() for the initial stack and environment pages. | |||
| 302 | * | |||
| 303 | * vma->vm_mm->mmap_sem is held for writing. | |||
| 304 | */ | |||
| 95330 | 0 | 305 | void install_arg_page(struct vm_area_struct *vma, | |
| 306 | struct page *page, unsigned long address) | |||
| 307 | { | |||
| 308 | struct mm_struct *mm = vma->vm_mm; | |||
| 309 | pte_t * pte; | |||
| 310 | spinlock_t *ptl; | |||
| 311 | ||||
| 0 | 95330 | - | 312 | if (unlikely(anon_vma_prepare(vma))) |
| 0 | - | 313 | goto out; | |
| 314 | ||||
| 315 | flush_dcache_page(page); | |||
| 0 | 95330 | - | 315 | do-while (0) |
| 316 | pte = get_locked_pte(mm, address, &ptl); | |||
| 0 | 95330 | - | 317 | if (!pte) |
| 0 | - | 318 | goto out; | |
| 0 | 95330 | - | 319 | if (!pte_none(*pte)) { |
| 320 | pte_unmap_unlock(pte, ptl); | |||
| 320 | do | |||
| 320 | do | |||
| 0 | 0 | - | 320 | do-while (0) |
| 0 | 0 | - | 320 | do-while (0) |
| 0 | 0 | - | 320 | do-while (0) |
| 0 | - | 321 | goto out; | |
| 322 | } | |||
| 323 | inc_mm_counter(mm, anon_rss); | |||
| 324 | lru_cache_add_active(page); | |||
| 325 | set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte( | |||
| 326 | page, vma->vm_page_prot)))); | |||
| 327 | page_add_new_anon_rmap(page, vma, address); | |||
| 328 | pte_unmap_unlock(pte, ptl); | |||
| 328 | do | |||
| 328 | do | |||
| 0 | 95330 | - | 328 | do-while (0) |
| 0 | 95330 | - | 328 | do-while (0) |
| 0 | 95330 | - | 328 | do-while (0) |
| 329 | ||||
| 330 | /* no need for flush_tlb */ | |||
| 95330 | 331 | return; | ||
| 332 | out: | |||
| 333 | __free_page(page); | |||
| 334 | force_sig(SIGKILL, current); | |||
| 335 | } | |||
| 336 | ||||
| 337 | #define EXTRA_STACK_VM_PAGES 20 /* random */ | |||
| 338 | ||||
| 65112 | 0 | 339 | int setup_arg_pages(struct linux_binprm *bprm, | |
| 340 | unsigned long stack_top, | |||
| 341 | int executable_stack) | |||
| 342 | { | |||
| 343 | unsigned long stack_base; | |||
| 344 | struct vm_area_struct *mpnt; | |||
| 345 | struct mm_struct *mm = current->mm; | |||
| 346 | int i, ret; | |||
| 347 | long arg_size; | |||
| 348 | ||||
| 349 | #ifdef CONFIG_STACK_GROWSUP | |||
| 350 | /* Move the argument and environment strings to the bottom of the | |||
| 351 | * stack space. | |||
| 352 | */ | |||
| 353 | int offset, j; | |||
| 354 | char *to, *from; | |||
| 355 | ||||
| 356 | /* Start by shifting all the pages down */ | |||
| 357 | i = 0; | |||
| 358 | for (j = 0; j < MAX_ARG_PAGES; j++) { | |||
| 359 | struct page *page = bprm->page[j]; | |||
| 360 | if (!page) | |||
| 361 | continue; | |||
| 362 | bprm->page[i++] = page; | |||
| 363 | } | |||
| 364 | ||||
| 365 | /* Now move them within their pages */ | |||
| 366 | offset = bprm->p % PAGE_SIZE; | |||
| 367 | to = kmap(bprm->page[0]); | |||
| 368 | for (j = 1; j < i; j++) { | |||
| 369 | memmove(to, to + offset, PAGE_SIZE - offset); | |||
| 370 | from = kmap(bprm->page[j]); | |||
| 371 | memcpy(to + PAGE_SIZE - offset, from, offset); | |||
| 372 | kunmap(bprm->page[j - 1]); | |||
| 373 | to = from; | |||
| 374 | } | |||
| 375 | memmove(to, to + offset, PAGE_SIZE - offset); | |||
| 376 | kunmap(bprm->page[j - 1]); | |||
| 377 | ||||
| 378 | /* Limit stack size to 1GB */ | |||
| 379 | stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max; | |||
| 380 | if (stack_base > (1 << 30)) | |||
| 381 | stack_base = 1 << 30; | |||
| 382 | stack_base = PAGE_ALIGN(stack_top - stack_base); | |||
| 383 | ||||
| 384 | /* Adjust bprm->p to point to the end of the strings. */ | |||
| 385 | bprm->p = stack_base + PAGE_SIZE * i - offset; | |||
| 386 | ||||
| 387 | mm->arg_start = stack_base; | |||
| 388 | arg_size = i << PAGE_SHIFT; | |||
| 389 | ||||
| 390 | /* zero pages that were copied above */ | |||
| 391 | while (i < MAX_ARG_PAGES) | |||
| 392 | bprm->page[i++] = NULL; | |||
| 393 | #else | |||
| 394 | stack_base = arch_align_stack(stack_top - MAX_ARG_PAGES*PAGE_SIZE); | |||
| 395 | stack_base = PAGE_ALIGN(stack_base); | |||
| 396 | bprm->p += stack_base; | |||
| 397 | mm->arg_start = bprm->p; | |||
| 398 | arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start); | |||
| 399 | #endif | |||
| 400 | ||||
| 401 | arg_size += EXTRA_STACK_VM_PAGES * PAGE_SIZE; | |||
| 402 | ||||
| 0 | 65112 | - | 403 | if (bprm->loader) |
| 404 | bprm->loader += stack_base; | |||
| 405 | bprm->exec += stack_base; | |||
| 406 | ||||
| 407 | mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); | |||
| 0 | 65112 | - | 408 | if (!mpnt) |
| 0 | - | 409 | return -ENOMEM; | |
| 410 | ||||
| 411 | memset(mpnt, 0, sizeof(*mpnt)); | |||
| 412 | ||||
| 413 | down_write(&mm->mmap_sem); | |||
| 414 | { | |||
| 415 | mpnt->vm_mm = mm; | |||
| 416 | #ifdef CONFIG_STACK_GROWSUP | |||
| 417 | mpnt->vm_start = stack_base; | |||
| 418 | mpnt->vm_end = stack_base + arg_size; | |||
| 419 | #else | |||
| 420 | mpnt->vm_end = stack_top; | |||
| 421 | mpnt->vm_start = mpnt->vm_end - arg_size; | |||
| 422 | #endif | |||
| 423 | /* Adjust stack execute permissions; explicitly enable | |||
| 424 | * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X | |||
| 425 | * and leave alone (arch default) otherwise. */ | |||
| 0 | 65112 | - | 426 | if (unlikely(executable_stack == EXSTACK_ENABLE_X)) |
| 427 | mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC; | |||
| 0 | 0 | - | 427 | ternary-?: ( get_current ( ) -> personalit.. |
| 65112 | 0 | - | 428 | else if (executable_stack == EXSTACK_DISABLE_X) |
| 429 | mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC; | |||
| 0 | 65112 | - | 429 | ternary-?: ( get_current ( ) -> personalit.. |
| 430 | else | |||
| 431 | mpnt->vm_flags = VM_STACK_FLAGS; | |||
| 0 | 0 | - | 431 | ternary-?: ( get_current ( ) -> personalit.. |
| 432 | mpnt->vm_flags |= mm->def_flags; | |||
| 433 | mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7]; | |||
| 0 | 65112 | - | 434 | if ((ret = insert_vm_struct(mm, mpnt))) { |
| 435 | up_write(&mm->mmap_sem); | |||
| 436 | kmem_cache_free(vm_area_cachep, mpnt); | |||
| 0 | - | 437 | return ret; | |
| 438 | } | |||
| 439 | mm->stack_vm = mm->total_vm = vma_pages(mpnt); | |||
| 440 | } | |||
| 441 | ||||
| 2083E3 | 65112 | 442 | for (i = 0 ; i < MAX_ARG_PAGES ; i++) { | |
| 443 | struct page *page = bprm->page[i]; | |||
| 94640 | 1988E3 | 444 | if (page) { | |
| 445 | bprm->page[i] = NULL; | |||
| 446 | install_arg_page(mpnt, page, stack_base); | |||
| 447 | } | |||
| 448 | stack_base += PAGE_SIZE; | |||
| 449 | } | |||
| 450 | up_write(&mm->mmap_sem); | |||
| 451 | ||||
| 65112 | 452 | return 0; | ||
| 453 | } | |||
| 454 | ||||
| 455 | EXPORT_SYMBOL(setup_arg_pages); | |||
| 456 | ||||
| 457 | #define free_arg_pages(bprm) do { } while (0) | |||
| 458 | ||||
| 459 | #else | |||
| 460 | ||||
| 461 | static inline void free_arg_pages(struct linux_binprm *bprm) | |||
| 462 | { | |||
| 463 | int i; | |||
| 464 | ||||
| 465 | for (i = 0; i < MAX_ARG_PAGES; i++) { | |||
| 466 | if (bprm->page[i]) | |||
| 467 | __free_page(bprm->page[i]); | |||
| 468 | bprm->page[i] = NULL; | |||
| 469 | } | |||
| 470 | } | |||
| 471 | ||||
| 472 | #endif /* CONFIG_MMU */ | |||
| 473 | ||||
| 142890 | 0 | 474 | struct file *open_exec(const char *name) | |
| 475 | { | |||
| 476 | struct nameidata nd; | |||
| 477 | int err; | |||
| 478 | struct file *file; | |||
| 479 | ||||
| 480 | err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ); | |||
| 481 | file = ERR_PTR(err); | |||
| 482 | ||||
| 133779 | 9111 | 483 | if (!err) { | |
| 484 | struct inode *inode = nd.dentry->d_inode; | |||
| 485 | file = ERR_PTR(-EACCES); | |||
| 486 | if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && | |||
| 133778 | 1 | 487 | S_ISREG(inode->i_mode)) { | |
| 133778 | 487 | !(F) && (T) | ||
| 0 | - | |||