.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/fs/binfmt_elf.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
12 | 13 | #include <linux/module.h> |
---|
13 | 14 | #include <linux/kernel.h> |
---|
14 | 15 | #include <linux/fs.h> |
---|
| 16 | +#include <linux/log2.h> |
---|
15 | 17 | #include <linux/mm.h> |
---|
16 | 18 | #include <linux/mman.h> |
---|
17 | 19 | #include <linux/errno.h> |
---|
.. | .. |
---|
26 | 28 | #include <linux/highuid.h> |
---|
27 | 29 | #include <linux/compiler.h> |
---|
28 | 30 | #include <linux/highmem.h> |
---|
| 31 | +#include <linux/hugetlb.h> |
---|
29 | 32 | #include <linux/pagemap.h> |
---|
30 | 33 | #include <linux/vmalloc.h> |
---|
31 | 34 | #include <linux/security.h> |
---|
.. | .. |
---|
38 | 41 | #include <linux/sched/coredump.h> |
---|
39 | 42 | #include <linux/sched/task_stack.h> |
---|
40 | 43 | #include <linux/sched/cputime.h> |
---|
| 44 | +#include <linux/sizes.h> |
---|
| 45 | +#include <linux/types.h> |
---|
41 | 46 | #include <linux/cred.h> |
---|
42 | 47 | #include <linux/dax.h> |
---|
43 | 48 | #include <linux/uaccess.h> |
---|
44 | 49 | #include <asm/param.h> |
---|
45 | 50 | #include <asm/page.h> |
---|
| 51 | + |
---|
| 52 | +#ifndef ELF_COMPAT |
---|
| 53 | +#define ELF_COMPAT 0 |
---|
| 54 | +#endif |
---|
46 | 55 | |
---|
47 | 56 | #ifndef user_long_t |
---|
48 | 57 | #define user_long_t long |
---|
.. | .. |
---|
57 | 66 | #endif |
---|
58 | 67 | |
---|
59 | 68 | static int load_elf_binary(struct linux_binprm *bprm); |
---|
60 | | -static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, |
---|
61 | | - int, int, unsigned long); |
---|
62 | 69 | |
---|
63 | 70 | #ifdef CONFIG_USELIB |
---|
64 | 71 | static int load_elf_library(struct file *); |
---|
.. | .. |
---|
98 | 105 | .min_coredump = ELF_EXEC_PAGESIZE, |
---|
99 | 106 | }; |
---|
100 | 107 | |
---|
101 | | -#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) |
---|
| 108 | +#define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE)) |
---|
102 | 109 | |
---|
103 | 110 | static int set_brk(unsigned long start, unsigned long end, int prot) |
---|
104 | 111 | { |
---|
.. | .. |
---|
162 | 169 | #endif |
---|
163 | 170 | |
---|
164 | 171 | static int |
---|
165 | | -create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, |
---|
166 | | - unsigned long load_addr, unsigned long interp_load_addr) |
---|
| 172 | +create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, |
---|
| 173 | + unsigned long interp_load_addr, |
---|
| 174 | + unsigned long e_entry, unsigned long phdr_addr) |
---|
167 | 175 | { |
---|
| 176 | + struct mm_struct *mm = current->mm; |
---|
168 | 177 | unsigned long p = bprm->p; |
---|
169 | 178 | int argc = bprm->argc; |
---|
170 | 179 | int envc = bprm->envc; |
---|
.. | .. |
---|
177 | 186 | unsigned char k_rand_bytes[16]; |
---|
178 | 187 | int items; |
---|
179 | 188 | elf_addr_t *elf_info; |
---|
180 | | - int ei_index = 0; |
---|
| 189 | + int ei_index; |
---|
181 | 190 | const struct cred *cred = current_cred(); |
---|
182 | 191 | struct vm_area_struct *vma; |
---|
183 | 192 | |
---|
.. | .. |
---|
200 | 209 | size_t len = strlen(k_platform) + 1; |
---|
201 | 210 | |
---|
202 | 211 | u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); |
---|
203 | | - if (__copy_to_user(u_platform, k_platform, len)) |
---|
| 212 | + if (copy_to_user(u_platform, k_platform, len)) |
---|
204 | 213 | return -EFAULT; |
---|
205 | 214 | } |
---|
206 | 215 | |
---|
.. | .. |
---|
213 | 222 | size_t len = strlen(k_base_platform) + 1; |
---|
214 | 223 | |
---|
215 | 224 | u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); |
---|
216 | | - if (__copy_to_user(u_base_platform, k_base_platform, len)) |
---|
| 225 | + if (copy_to_user(u_base_platform, k_base_platform, len)) |
---|
217 | 226 | return -EFAULT; |
---|
218 | 227 | } |
---|
219 | 228 | |
---|
.. | .. |
---|
223 | 232 | get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); |
---|
224 | 233 | u_rand_bytes = (elf_addr_t __user *) |
---|
225 | 234 | STACK_ALLOC(p, sizeof(k_rand_bytes)); |
---|
226 | | - if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) |
---|
| 235 | + if (copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) |
---|
227 | 236 | return -EFAULT; |
---|
228 | 237 | |
---|
229 | 238 | /* Create the ELF interpreter info */ |
---|
230 | | - elf_info = (elf_addr_t *)current->mm->saved_auxv; |
---|
| 239 | + elf_info = (elf_addr_t *)mm->saved_auxv; |
---|
231 | 240 | /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ |
---|
232 | 241 | #define NEW_AUX_ENT(id, val) \ |
---|
233 | 242 | do { \ |
---|
234 | | - elf_info[ei_index++] = id; \ |
---|
235 | | - elf_info[ei_index++] = val; \ |
---|
| 243 | + *elf_info++ = id; \ |
---|
| 244 | + *elf_info++ = val; \ |
---|
236 | 245 | } while (0) |
---|
237 | 246 | |
---|
238 | 247 | #ifdef ARCH_DLINFO |
---|
.. | .. |
---|
247 | 256 | NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); |
---|
248 | 257 | NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); |
---|
249 | 258 | NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); |
---|
250 | | - NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); |
---|
| 259 | + NEW_AUX_ENT(AT_PHDR, phdr_addr); |
---|
251 | 260 | NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); |
---|
252 | 261 | NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); |
---|
253 | 262 | NEW_AUX_ENT(AT_BASE, interp_load_addr); |
---|
254 | 263 | NEW_AUX_ENT(AT_FLAGS, 0); |
---|
255 | | - NEW_AUX_ENT(AT_ENTRY, exec->e_entry); |
---|
| 264 | + NEW_AUX_ENT(AT_ENTRY, e_entry); |
---|
256 | 265 | NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); |
---|
257 | 266 | NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); |
---|
258 | 267 | NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); |
---|
.. | .. |
---|
271 | 280 | NEW_AUX_ENT(AT_BASE_PLATFORM, |
---|
272 | 281 | (elf_addr_t)(unsigned long)u_base_platform); |
---|
273 | 282 | } |
---|
274 | | - if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { |
---|
275 | | - NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); |
---|
| 283 | + if (bprm->have_execfd) { |
---|
| 284 | + NEW_AUX_ENT(AT_EXECFD, bprm->execfd); |
---|
276 | 285 | } |
---|
277 | 286 | #undef NEW_AUX_ENT |
---|
278 | 287 | /* AT_NULL is zero; clear the rest too */ |
---|
279 | | - memset(&elf_info[ei_index], 0, |
---|
280 | | - sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); |
---|
| 288 | + memset(elf_info, 0, (char *)mm->saved_auxv + |
---|
| 289 | + sizeof(mm->saved_auxv) - (char *)elf_info); |
---|
281 | 290 | |
---|
282 | 291 | /* And advance past the AT_NULL entry. */ |
---|
283 | | - ei_index += 2; |
---|
| 292 | + elf_info += 2; |
---|
284 | 293 | |
---|
| 294 | + ei_index = elf_info - (elf_addr_t *)mm->saved_auxv; |
---|
285 | 295 | sp = STACK_ADD(p, ei_index); |
---|
286 | 296 | |
---|
287 | 297 | items = (argc + 1) + (envc + 1) + 1; |
---|
.. | .. |
---|
300 | 310 | * Grow the stack manually; some architectures have a limit on how |
---|
301 | 311 | * far ahead a user-space access may be in order to grow the stack. |
---|
302 | 312 | */ |
---|
303 | | - vma = find_extend_vma(current->mm, bprm->p); |
---|
| 313 | + if (mmap_read_lock_killable(mm)) |
---|
| 314 | + return -EINTR; |
---|
| 315 | + vma = find_extend_vma(mm, bprm->p); |
---|
| 316 | + mmap_read_unlock(mm); |
---|
304 | 317 | if (!vma) |
---|
305 | 318 | return -EFAULT; |
---|
306 | 319 | |
---|
307 | 320 | /* Now, let's put argc (and argv, envp if appropriate) on the stack */ |
---|
308 | | - if (__put_user(argc, sp++)) |
---|
| 321 | + if (put_user(argc, sp++)) |
---|
309 | 322 | return -EFAULT; |
---|
310 | 323 | |
---|
311 | 324 | /* Populate list of argv pointers back to argv strings. */ |
---|
312 | | - p = current->mm->arg_end = current->mm->arg_start; |
---|
| 325 | + p = mm->arg_end = mm->arg_start; |
---|
313 | 326 | while (argc-- > 0) { |
---|
314 | 327 | size_t len; |
---|
315 | | - if (__put_user((elf_addr_t)p, sp++)) |
---|
| 328 | + if (put_user((elf_addr_t)p, sp++)) |
---|
316 | 329 | return -EFAULT; |
---|
317 | 330 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); |
---|
318 | 331 | if (!len || len > MAX_ARG_STRLEN) |
---|
319 | 332 | return -EINVAL; |
---|
320 | 333 | p += len; |
---|
321 | 334 | } |
---|
322 | | - if (__put_user(0, sp++)) |
---|
| 335 | + if (put_user(0, sp++)) |
---|
323 | 336 | return -EFAULT; |
---|
324 | | - current->mm->arg_end = p; |
---|
| 337 | + mm->arg_end = p; |
---|
325 | 338 | |
---|
326 | 339 | /* Populate list of envp pointers back to envp strings. */ |
---|
327 | | - current->mm->env_end = current->mm->env_start = p; |
---|
| 340 | + mm->env_end = mm->env_start = p; |
---|
328 | 341 | while (envc-- > 0) { |
---|
329 | 342 | size_t len; |
---|
330 | | - if (__put_user((elf_addr_t)p, sp++)) |
---|
| 343 | + if (put_user((elf_addr_t)p, sp++)) |
---|
331 | 344 | return -EFAULT; |
---|
332 | 345 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); |
---|
333 | 346 | if (!len || len > MAX_ARG_STRLEN) |
---|
334 | 347 | return -EINVAL; |
---|
335 | 348 | p += len; |
---|
336 | 349 | } |
---|
337 | | - if (__put_user(0, sp++)) |
---|
| 350 | + if (put_user(0, sp++)) |
---|
338 | 351 | return -EFAULT; |
---|
339 | | - current->mm->env_end = p; |
---|
| 352 | + mm->env_end = p; |
---|
340 | 353 | |
---|
341 | 354 | /* Put the elf_info on the stack in the right place. */ |
---|
342 | | - if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) |
---|
| 355 | + if (copy_to_user(sp, mm->saved_auxv, ei_index * sizeof(elf_addr_t))) |
---|
343 | 356 | return -EFAULT; |
---|
344 | 357 | return 0; |
---|
345 | 358 | } |
---|
346 | 359 | |
---|
347 | | -#ifndef elf_map |
---|
348 | | - |
---|
349 | 360 | static unsigned long elf_map(struct file *filep, unsigned long addr, |
---|
350 | | - struct elf_phdr *eppnt, int prot, int type, |
---|
| 361 | + const struct elf_phdr *eppnt, int prot, int type, |
---|
351 | 362 | unsigned long total_size) |
---|
352 | 363 | { |
---|
353 | 364 | unsigned long map_addr; |
---|
.. | .. |
---|
385 | 396 | return(map_addr); |
---|
386 | 397 | } |
---|
387 | 398 | |
---|
388 | | -#endif /* !elf_map */ |
---|
389 | | - |
---|
390 | | -static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) |
---|
| 399 | +static unsigned long total_mapping_size(const struct elf_phdr *cmds, int nr) |
---|
391 | 400 | { |
---|
392 | 401 | int i, first_idx = -1, last_idx = -1; |
---|
393 | 402 | |
---|
.. | .. |
---|
405 | 414 | ELF_PAGESTART(cmds[first_idx].p_vaddr); |
---|
406 | 415 | } |
---|
407 | 416 | |
---|
| 417 | +static int elf_read(struct file *file, void *buf, size_t len, loff_t pos) |
---|
| 418 | +{ |
---|
| 419 | + ssize_t rv; |
---|
| 420 | + |
---|
| 421 | + rv = kernel_read(file, buf, len, &pos); |
---|
| 422 | + if (unlikely(rv != len)) { |
---|
| 423 | + return (rv < 0) ? rv : -EIO; |
---|
| 424 | + } |
---|
| 425 | + return 0; |
---|
| 426 | +} |
---|
| 427 | + |
---|
| 428 | +static unsigned long maximum_alignment(struct elf_phdr *cmds, int nr) |
---|
| 429 | +{ |
---|
| 430 | + unsigned long alignment = 0; |
---|
| 431 | + int i; |
---|
| 432 | + |
---|
| 433 | + for (i = 0; i < nr; i++) { |
---|
| 434 | + if (cmds[i].p_type == PT_LOAD) { |
---|
| 435 | + unsigned long p_align = cmds[i].p_align; |
---|
| 436 | + |
---|
| 437 | + /* skip non-power of two alignments as invalid */ |
---|
| 438 | + if (!is_power_of_2(p_align)) |
---|
| 439 | + continue; |
---|
| 440 | + alignment = max(alignment, p_align); |
---|
| 441 | + } |
---|
| 442 | + } |
---|
| 443 | + |
---|
| 444 | + /* ensure we align to at least one page */ |
---|
| 445 | + return ELF_PAGEALIGN(alignment); |
---|
| 446 | +} |
---|
| 447 | + |
---|
408 | 448 | /** |
---|
409 | 449 | * load_elf_phdrs() - load ELF program headers |
---|
410 | 450 | * @elf_ex: ELF header of the binary whose program headers should be loaded |
---|
.. | .. |
---|
414 | 454 | * header pointed to by elf_ex, into a newly allocated array. The caller is |
---|
415 | 455 | * responsible for freeing the allocated data. Returns an ERR_PTR upon failure. |
---|
416 | 456 | */ |
---|
417 | | -static struct elf_phdr *load_elf_phdrs(struct elfhdr *elf_ex, |
---|
| 457 | +static struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex, |
---|
418 | 458 | struct file *elf_file) |
---|
419 | 459 | { |
---|
420 | 460 | struct elf_phdr *elf_phdata = NULL; |
---|
421 | | - int retval, size, err = -1; |
---|
422 | | - loff_t pos = elf_ex->e_phoff; |
---|
| 461 | + int retval, err = -1; |
---|
| 462 | + unsigned int size; |
---|
423 | 463 | |
---|
424 | 464 | /* |
---|
425 | 465 | * If the size of this structure has changed, then punt, since |
---|
.. | .. |
---|
429 | 469 | goto out; |
---|
430 | 470 | |
---|
431 | 471 | /* Sanity check the number of program headers... */ |
---|
432 | | - if (elf_ex->e_phnum < 1 || |
---|
433 | | - elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) |
---|
434 | | - goto out; |
---|
435 | | - |
---|
436 | 472 | /* ...and their total size. */ |
---|
437 | 473 | size = sizeof(struct elf_phdr) * elf_ex->e_phnum; |
---|
438 | | - if (size > ELF_MIN_ALIGN) |
---|
| 474 | + if (size == 0 || size > 65536 || size > ELF_MIN_ALIGN) |
---|
439 | 475 | goto out; |
---|
440 | 476 | |
---|
441 | 477 | elf_phdata = kmalloc(size, GFP_KERNEL); |
---|
.. | .. |
---|
443 | 479 | goto out; |
---|
444 | 480 | |
---|
445 | 481 | /* Read in the program headers */ |
---|
446 | | - retval = kernel_read(elf_file, elf_phdata, size, &pos); |
---|
447 | | - if (retval != size) { |
---|
448 | | - err = (retval < 0) ? retval : -EIO; |
---|
| 482 | + retval = elf_read(elf_file, elf_phdata, size, elf_ex->e_phoff); |
---|
| 483 | + if (retval < 0) { |
---|
| 484 | + err = retval; |
---|
449 | 485 | goto out; |
---|
450 | 486 | } |
---|
451 | 487 | |
---|
.. | .. |
---|
529 | 565 | |
---|
530 | 566 | #endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */ |
---|
531 | 567 | |
---|
| 568 | +static inline int make_prot(u32 p_flags, struct arch_elf_state *arch_state, |
---|
| 569 | + bool has_interp, bool is_interp) |
---|
| 570 | +{ |
---|
| 571 | + int prot = 0; |
---|
| 572 | + |
---|
| 573 | + if (p_flags & PF_R) |
---|
| 574 | + prot |= PROT_READ; |
---|
| 575 | + if (p_flags & PF_W) |
---|
| 576 | + prot |= PROT_WRITE; |
---|
| 577 | + if (p_flags & PF_X) |
---|
| 578 | + prot |= PROT_EXEC; |
---|
| 579 | + |
---|
| 580 | + return arch_elf_adjust_prot(prot, arch_state, has_interp, is_interp); |
---|
| 581 | +} |
---|
| 582 | + |
---|
532 | 583 | /* This is much more generalized than the library routine read function, |
---|
533 | 584 | so we keep this separate. Technically the library read function |
---|
534 | 585 | is only provided so that we can read a.out libraries that have |
---|
535 | 586 | an ELF header */ |
---|
536 | 587 | |
---|
537 | 588 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, |
---|
538 | | - struct file *interpreter, unsigned long *interp_map_addr, |
---|
539 | | - unsigned long no_base, struct elf_phdr *interp_elf_phdata) |
---|
| 589 | + struct file *interpreter, |
---|
| 590 | + unsigned long no_base, struct elf_phdr *interp_elf_phdata, |
---|
| 591 | + struct arch_elf_state *arch_state) |
---|
540 | 592 | { |
---|
541 | 593 | struct elf_phdr *eppnt; |
---|
542 | 594 | unsigned long load_addr = 0; |
---|
.. | .. |
---|
568 | 620 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { |
---|
569 | 621 | if (eppnt->p_type == PT_LOAD) { |
---|
570 | 622 | int elf_type = MAP_PRIVATE | MAP_DENYWRITE; |
---|
571 | | - int elf_prot = 0; |
---|
| 623 | + int elf_prot = make_prot(eppnt->p_flags, arch_state, |
---|
| 624 | + true, true); |
---|
572 | 625 | unsigned long vaddr = 0; |
---|
573 | 626 | unsigned long k, map_addr; |
---|
574 | 627 | |
---|
575 | | - if (eppnt->p_flags & PF_R) |
---|
576 | | - elf_prot = PROT_READ; |
---|
577 | | - if (eppnt->p_flags & PF_W) |
---|
578 | | - elf_prot |= PROT_WRITE; |
---|
579 | | - if (eppnt->p_flags & PF_X) |
---|
580 | | - elf_prot |= PROT_EXEC; |
---|
581 | 628 | vaddr = eppnt->p_vaddr; |
---|
582 | 629 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) |
---|
583 | 630 | elf_type |= MAP_FIXED; |
---|
.. | .. |
---|
587 | 634 | map_addr = elf_map(interpreter, load_addr + vaddr, |
---|
588 | 635 | eppnt, elf_prot, elf_type, total_size); |
---|
589 | 636 | total_size = 0; |
---|
590 | | - if (!*interp_map_addr) |
---|
591 | | - *interp_map_addr = map_addr; |
---|
592 | 637 | error = map_addr; |
---|
593 | 638 | if (BAD_ADDR(map_addr)) |
---|
594 | 639 | goto out; |
---|
.. | .. |
---|
667 | 712 | * libraries. There is no binary dependent code anywhere else. |
---|
668 | 713 | */ |
---|
669 | 714 | |
---|
670 | | -#ifndef STACK_RND_MASK |
---|
671 | | -#define STACK_RND_MASK (0x7ff >> (PAGE_SHIFT - 12)) /* 8MB of VA */ |
---|
672 | | -#endif |
---|
673 | | - |
---|
674 | | -static unsigned long randomize_stack_top(unsigned long stack_top) |
---|
| 715 | +static int parse_elf_property(const char *data, size_t *off, size_t datasz, |
---|
| 716 | + struct arch_elf_state *arch, |
---|
| 717 | + bool have_prev_type, u32 *prev_type) |
---|
675 | 718 | { |
---|
676 | | - unsigned long random_variable = 0; |
---|
| 719 | + size_t o, step; |
---|
| 720 | + const struct gnu_property *pr; |
---|
| 721 | + int ret; |
---|
677 | 722 | |
---|
678 | | - if (current->flags & PF_RANDOMIZE) { |
---|
679 | | - random_variable = get_random_long(); |
---|
680 | | - random_variable &= STACK_RND_MASK; |
---|
681 | | - random_variable <<= PAGE_SHIFT; |
---|
682 | | - } |
---|
683 | | -#ifdef CONFIG_STACK_GROWSUP |
---|
684 | | - return PAGE_ALIGN(stack_top) + random_variable; |
---|
685 | | -#else |
---|
686 | | - return PAGE_ALIGN(stack_top) - random_variable; |
---|
687 | | -#endif |
---|
| 723 | + if (*off == datasz) |
---|
| 724 | + return -ENOENT; |
---|
| 725 | + |
---|
| 726 | + if (WARN_ON_ONCE(*off > datasz || *off % ELF_GNU_PROPERTY_ALIGN)) |
---|
| 727 | + return -EIO; |
---|
| 728 | + o = *off; |
---|
| 729 | + datasz -= *off; |
---|
| 730 | + |
---|
| 731 | + if (datasz < sizeof(*pr)) |
---|
| 732 | + return -ENOEXEC; |
---|
| 733 | + pr = (const struct gnu_property *)(data + o); |
---|
| 734 | + o += sizeof(*pr); |
---|
| 735 | + datasz -= sizeof(*pr); |
---|
| 736 | + |
---|
| 737 | + if (pr->pr_datasz > datasz) |
---|
| 738 | + return -ENOEXEC; |
---|
| 739 | + |
---|
| 740 | + WARN_ON_ONCE(o % ELF_GNU_PROPERTY_ALIGN); |
---|
| 741 | + step = round_up(pr->pr_datasz, ELF_GNU_PROPERTY_ALIGN); |
---|
| 742 | + if (step > datasz) |
---|
| 743 | + return -ENOEXEC; |
---|
| 744 | + |
---|
| 745 | + /* Properties are supposed to be unique and sorted on pr_type: */ |
---|
| 746 | + if (have_prev_type && pr->pr_type <= *prev_type) |
---|
| 747 | + return -ENOEXEC; |
---|
| 748 | + *prev_type = pr->pr_type; |
---|
| 749 | + |
---|
| 750 | + ret = arch_parse_elf_property(pr->pr_type, data + o, |
---|
| 751 | + pr->pr_datasz, ELF_COMPAT, arch); |
---|
| 752 | + if (ret) |
---|
| 753 | + return ret; |
---|
| 754 | + |
---|
| 755 | + *off = o + step; |
---|
| 756 | + return 0; |
---|
| 757 | +} |
---|
| 758 | + |
---|
| 759 | +#define NOTE_DATA_SZ SZ_1K |
---|
| 760 | +#define GNU_PROPERTY_TYPE_0_NAME "GNU" |
---|
| 761 | +#define NOTE_NAME_SZ (sizeof(GNU_PROPERTY_TYPE_0_NAME)) |
---|
| 762 | + |
---|
| 763 | +static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr, |
---|
| 764 | + struct arch_elf_state *arch) |
---|
| 765 | +{ |
---|
| 766 | + union { |
---|
| 767 | + struct elf_note nhdr; |
---|
| 768 | + char data[NOTE_DATA_SZ]; |
---|
| 769 | + } note; |
---|
| 770 | + loff_t pos; |
---|
| 771 | + ssize_t n; |
---|
| 772 | + size_t off, datasz; |
---|
| 773 | + int ret; |
---|
| 774 | + bool have_prev_type; |
---|
| 775 | + u32 prev_type; |
---|
| 776 | + |
---|
| 777 | + if (!IS_ENABLED(CONFIG_ARCH_USE_GNU_PROPERTY) || !phdr) |
---|
| 778 | + return 0; |
---|
| 779 | + |
---|
| 780 | + /* load_elf_binary() shouldn't call us unless this is true... */ |
---|
| 781 | + if (WARN_ON_ONCE(phdr->p_type != PT_GNU_PROPERTY)) |
---|
| 782 | + return -ENOEXEC; |
---|
| 783 | + |
---|
| 784 | + /* If the properties are crazy large, that's too bad (for now): */ |
---|
| 785 | + if (phdr->p_filesz > sizeof(note)) |
---|
| 786 | + return -ENOEXEC; |
---|
| 787 | + |
---|
| 788 | + pos = phdr->p_offset; |
---|
| 789 | + n = kernel_read(f, ¬e, phdr->p_filesz, &pos); |
---|
| 790 | + |
---|
| 791 | + BUILD_BUG_ON(sizeof(note) < sizeof(note.nhdr) + NOTE_NAME_SZ); |
---|
| 792 | + if (n < 0 || n < sizeof(note.nhdr) + NOTE_NAME_SZ) |
---|
| 793 | + return -EIO; |
---|
| 794 | + |
---|
| 795 | + if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 || |
---|
| 796 | + note.nhdr.n_namesz != NOTE_NAME_SZ || |
---|
| 797 | + strncmp(note.data + sizeof(note.nhdr), |
---|
| 798 | + GNU_PROPERTY_TYPE_0_NAME, n - sizeof(note.nhdr))) |
---|
| 799 | + return -ENOEXEC; |
---|
| 800 | + |
---|
| 801 | + off = round_up(sizeof(note.nhdr) + NOTE_NAME_SZ, |
---|
| 802 | + ELF_GNU_PROPERTY_ALIGN); |
---|
| 803 | + if (off > n) |
---|
| 804 | + return -ENOEXEC; |
---|
| 805 | + |
---|
| 806 | + if (note.nhdr.n_descsz > n - off) |
---|
| 807 | + return -ENOEXEC; |
---|
| 808 | + datasz = off + note.nhdr.n_descsz; |
---|
| 809 | + |
---|
| 810 | + have_prev_type = false; |
---|
| 811 | + do { |
---|
| 812 | + ret = parse_elf_property(note.data, &off, datasz, arch, |
---|
| 813 | + have_prev_type, &prev_type); |
---|
| 814 | + have_prev_type = true; |
---|
| 815 | + } while (!ret); |
---|
| 816 | + |
---|
| 817 | + return ret == -ENOENT ? 0 : ret; |
---|
688 | 818 | } |
---|
689 | 819 | |
---|
690 | 820 | static int load_elf_binary(struct linux_binprm *bprm) |
---|
691 | 821 | { |
---|
692 | 822 | struct file *interpreter = NULL; /* to shut gcc up */ |
---|
693 | | - unsigned long load_addr = 0, load_bias = 0; |
---|
| 823 | + unsigned long load_addr, load_bias = 0, phdr_addr = 0; |
---|
694 | 824 | int load_addr_set = 0; |
---|
695 | | - char * elf_interpreter = NULL; |
---|
696 | 825 | unsigned long error; |
---|
697 | 826 | struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; |
---|
| 827 | + struct elf_phdr *elf_property_phdata = NULL; |
---|
698 | 828 | unsigned long elf_bss, elf_brk; |
---|
699 | 829 | int bss_prot = 0; |
---|
700 | 830 | int retval, i; |
---|
701 | 831 | unsigned long elf_entry; |
---|
| 832 | + unsigned long e_entry; |
---|
702 | 833 | unsigned long interp_load_addr = 0; |
---|
703 | 834 | unsigned long start_code, end_code, start_data, end_data; |
---|
704 | 835 | unsigned long reloc_func_desc __maybe_unused = 0; |
---|
705 | 836 | int executable_stack = EXSTACK_DEFAULT; |
---|
706 | | - struct pt_regs *regs = current_pt_regs(); |
---|
707 | | - struct { |
---|
708 | | - struct elfhdr elf_ex; |
---|
709 | | - struct elfhdr interp_elf_ex; |
---|
710 | | - } *loc; |
---|
| 837 | + struct elfhdr *elf_ex = (struct elfhdr *)bprm->buf; |
---|
| 838 | + struct elfhdr *interp_elf_ex = NULL; |
---|
711 | 839 | struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE; |
---|
712 | | - loff_t pos; |
---|
713 | | - |
---|
714 | | - loc = kmalloc(sizeof(*loc), GFP_KERNEL); |
---|
715 | | - if (!loc) { |
---|
716 | | - retval = -ENOMEM; |
---|
717 | | - goto out_ret; |
---|
718 | | - } |
---|
719 | | - |
---|
720 | | - /* Get the exec-header */ |
---|
721 | | - loc->elf_ex = *((struct elfhdr *)bprm->buf); |
---|
| 840 | + struct mm_struct *mm; |
---|
| 841 | + struct pt_regs *regs; |
---|
722 | 842 | |
---|
723 | 843 | retval = -ENOEXEC; |
---|
724 | 844 | /* First of all, some simple consistency checks */ |
---|
725 | | - if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) |
---|
| 845 | + if (memcmp(elf_ex->e_ident, ELFMAG, SELFMAG) != 0) |
---|
726 | 846 | goto out; |
---|
727 | 847 | |
---|
728 | | - if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN) |
---|
| 848 | + if (elf_ex->e_type != ET_EXEC && elf_ex->e_type != ET_DYN) |
---|
729 | 849 | goto out; |
---|
730 | | - if (!elf_check_arch(&loc->elf_ex)) |
---|
| 850 | + if (!elf_check_arch(elf_ex)) |
---|
731 | 851 | goto out; |
---|
732 | | - if (elf_check_fdpic(&loc->elf_ex)) |
---|
| 852 | + if (elf_check_fdpic(elf_ex)) |
---|
733 | 853 | goto out; |
---|
734 | 854 | if (!bprm->file->f_op->mmap) |
---|
735 | 855 | goto out; |
---|
736 | 856 | |
---|
737 | | - elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file); |
---|
| 857 | + elf_phdata = load_elf_phdrs(elf_ex, bprm->file); |
---|
738 | 858 | if (!elf_phdata) |
---|
739 | 859 | goto out; |
---|
740 | 860 | |
---|
741 | 861 | elf_ppnt = elf_phdata; |
---|
742 | | - elf_bss = 0; |
---|
743 | | - elf_brk = 0; |
---|
| 862 | + for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) { |
---|
| 863 | + char *elf_interpreter; |
---|
744 | 864 | |
---|
745 | | - start_code = ~0UL; |
---|
746 | | - end_code = 0; |
---|
747 | | - start_data = 0; |
---|
748 | | - end_data = 0; |
---|
749 | | - |
---|
750 | | - for (i = 0; i < loc->elf_ex.e_phnum; i++) { |
---|
751 | | - if (elf_ppnt->p_type == PT_INTERP) { |
---|
752 | | - /* This is the program interpreter used for |
---|
753 | | - * shared libraries - for now assume that this |
---|
754 | | - * is an a.out format binary |
---|
755 | | - */ |
---|
756 | | - retval = -ENOEXEC; |
---|
757 | | - if (elf_ppnt->p_filesz > PATH_MAX || |
---|
758 | | - elf_ppnt->p_filesz < 2) |
---|
759 | | - goto out_free_ph; |
---|
760 | | - |
---|
761 | | - retval = -ENOMEM; |
---|
762 | | - elf_interpreter = kmalloc(elf_ppnt->p_filesz, |
---|
763 | | - GFP_KERNEL); |
---|
764 | | - if (!elf_interpreter) |
---|
765 | | - goto out_free_ph; |
---|
766 | | - |
---|
767 | | - pos = elf_ppnt->p_offset; |
---|
768 | | - retval = kernel_read(bprm->file, elf_interpreter, |
---|
769 | | - elf_ppnt->p_filesz, &pos); |
---|
770 | | - if (retval != elf_ppnt->p_filesz) { |
---|
771 | | - if (retval >= 0) |
---|
772 | | - retval = -EIO; |
---|
773 | | - goto out_free_interp; |
---|
774 | | - } |
---|
775 | | - /* make sure path is NULL terminated */ |
---|
776 | | - retval = -ENOEXEC; |
---|
777 | | - if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') |
---|
778 | | - goto out_free_interp; |
---|
779 | | - |
---|
780 | | - interpreter = open_exec(elf_interpreter); |
---|
781 | | - retval = PTR_ERR(interpreter); |
---|
782 | | - if (IS_ERR(interpreter)) |
---|
783 | | - goto out_free_interp; |
---|
784 | | - |
---|
785 | | - /* |
---|
786 | | - * If the binary is not readable then enforce |
---|
787 | | - * mm->dumpable = 0 regardless of the interpreter's |
---|
788 | | - * permissions. |
---|
789 | | - */ |
---|
790 | | - would_dump(bprm, interpreter); |
---|
791 | | - |
---|
792 | | - /* Get the exec headers */ |
---|
793 | | - pos = 0; |
---|
794 | | - retval = kernel_read(interpreter, &loc->interp_elf_ex, |
---|
795 | | - sizeof(loc->interp_elf_ex), &pos); |
---|
796 | | - if (retval != sizeof(loc->interp_elf_ex)) { |
---|
797 | | - if (retval >= 0) |
---|
798 | | - retval = -EIO; |
---|
799 | | - goto out_free_dentry; |
---|
800 | | - } |
---|
801 | | - |
---|
802 | | - break; |
---|
| 865 | + if (elf_ppnt->p_type == PT_GNU_PROPERTY) { |
---|
| 866 | + elf_property_phdata = elf_ppnt; |
---|
| 867 | + continue; |
---|
803 | 868 | } |
---|
804 | | - elf_ppnt++; |
---|
| 869 | + |
---|
| 870 | + if (elf_ppnt->p_type != PT_INTERP) |
---|
| 871 | + continue; |
---|
| 872 | + |
---|
| 873 | + /* |
---|
| 874 | + * This is the program interpreter used for shared libraries - |
---|
| 875 | + * for now assume that this is an a.out format binary. |
---|
| 876 | + */ |
---|
| 877 | + retval = -ENOEXEC; |
---|
| 878 | + if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2) |
---|
| 879 | + goto out_free_ph; |
---|
| 880 | + |
---|
| 881 | + retval = -ENOMEM; |
---|
| 882 | + elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); |
---|
| 883 | + if (!elf_interpreter) |
---|
| 884 | + goto out_free_ph; |
---|
| 885 | + |
---|
| 886 | + retval = elf_read(bprm->file, elf_interpreter, elf_ppnt->p_filesz, |
---|
| 887 | + elf_ppnt->p_offset); |
---|
| 888 | + if (retval < 0) |
---|
| 889 | + goto out_free_interp; |
---|
| 890 | + /* make sure path is NULL terminated */ |
---|
| 891 | + retval = -ENOEXEC; |
---|
| 892 | + if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') |
---|
| 893 | + goto out_free_interp; |
---|
| 894 | + |
---|
| 895 | + interpreter = open_exec(elf_interpreter); |
---|
| 896 | + kfree(elf_interpreter); |
---|
| 897 | + retval = PTR_ERR(interpreter); |
---|
| 898 | + if (IS_ERR(interpreter)) |
---|
| 899 | + goto out_free_ph; |
---|
| 900 | + |
---|
| 901 | + /* |
---|
| 902 | + * If the binary is not readable then enforce mm->dumpable = 0 |
---|
| 903 | + * regardless of the interpreter's permissions. |
---|
| 904 | + */ |
---|
| 905 | + would_dump(bprm, interpreter); |
---|
| 906 | + |
---|
| 907 | + interp_elf_ex = kmalloc(sizeof(*interp_elf_ex), GFP_KERNEL); |
---|
| 908 | + if (!interp_elf_ex) { |
---|
| 909 | + retval = -ENOMEM; |
---|
| 910 | + goto out_free_file; |
---|
| 911 | + } |
---|
| 912 | + |
---|
| 913 | + /* Get the exec headers */ |
---|
| 914 | + retval = elf_read(interpreter, interp_elf_ex, |
---|
| 915 | + sizeof(*interp_elf_ex), 0); |
---|
| 916 | + if (retval < 0) |
---|
| 917 | + goto out_free_dentry; |
---|
| 918 | + |
---|
| 919 | + break; |
---|
| 920 | + |
---|
| 921 | +out_free_interp: |
---|
| 922 | + kfree(elf_interpreter); |
---|
| 923 | + goto out_free_ph; |
---|
805 | 924 | } |
---|
806 | 925 | |
---|
807 | 926 | elf_ppnt = elf_phdata; |
---|
808 | | - for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) |
---|
| 927 | + for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) |
---|
809 | 928 | switch (elf_ppnt->p_type) { |
---|
810 | 929 | case PT_GNU_STACK: |
---|
811 | 930 | if (elf_ppnt->p_flags & PF_X) |
---|
.. | .. |
---|
815 | 934 | break; |
---|
816 | 935 | |
---|
817 | 936 | case PT_LOPROC ... PT_HIPROC: |
---|
818 | | - retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt, |
---|
| 937 | + retval = arch_elf_pt_proc(elf_ex, elf_ppnt, |
---|
819 | 938 | bprm->file, false, |
---|
820 | 939 | &arch_state); |
---|
821 | 940 | if (retval) |
---|
.. | .. |
---|
824 | 943 | } |
---|
825 | 944 | |
---|
826 | 945 | /* Some simple consistency checks for the interpreter */ |
---|
827 | | - if (elf_interpreter) { |
---|
| 946 | + if (interpreter) { |
---|
828 | 947 | retval = -ELIBBAD; |
---|
829 | 948 | /* Not an ELF interpreter */ |
---|
830 | | - if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) |
---|
| 949 | + if (memcmp(interp_elf_ex->e_ident, ELFMAG, SELFMAG) != 0) |
---|
831 | 950 | goto out_free_dentry; |
---|
832 | 951 | /* Verify the interpreter has a valid arch */ |
---|
833 | | - if (!elf_check_arch(&loc->interp_elf_ex) || |
---|
834 | | - elf_check_fdpic(&loc->interp_elf_ex)) |
---|
| 952 | + if (!elf_check_arch(interp_elf_ex) || |
---|
| 953 | + elf_check_fdpic(interp_elf_ex)) |
---|
835 | 954 | goto out_free_dentry; |
---|
836 | 955 | |
---|
837 | 956 | /* Load the interpreter program headers */ |
---|
838 | | - interp_elf_phdata = load_elf_phdrs(&loc->interp_elf_ex, |
---|
| 957 | + interp_elf_phdata = load_elf_phdrs(interp_elf_ex, |
---|
839 | 958 | interpreter); |
---|
840 | 959 | if (!interp_elf_phdata) |
---|
841 | 960 | goto out_free_dentry; |
---|
842 | 961 | |
---|
843 | 962 | /* Pass PT_LOPROC..PT_HIPROC headers to arch code */ |
---|
| 963 | + elf_property_phdata = NULL; |
---|
844 | 964 | elf_ppnt = interp_elf_phdata; |
---|
845 | | - for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++) |
---|
| 965 | + for (i = 0; i < interp_elf_ex->e_phnum; i++, elf_ppnt++) |
---|
846 | 966 | switch (elf_ppnt->p_type) { |
---|
| 967 | + case PT_GNU_PROPERTY: |
---|
| 968 | + elf_property_phdata = elf_ppnt; |
---|
| 969 | + break; |
---|
| 970 | + |
---|
847 | 971 | case PT_LOPROC ... PT_HIPROC: |
---|
848 | | - retval = arch_elf_pt_proc(&loc->interp_elf_ex, |
---|
| 972 | + retval = arch_elf_pt_proc(interp_elf_ex, |
---|
849 | 973 | elf_ppnt, interpreter, |
---|
850 | 974 | true, &arch_state); |
---|
851 | 975 | if (retval) |
---|
.. | .. |
---|
854 | 978 | } |
---|
855 | 979 | } |
---|
856 | 980 | |
---|
| 981 | + retval = parse_elf_properties(interpreter ?: bprm->file, |
---|
| 982 | + elf_property_phdata, &arch_state); |
---|
| 983 | + if (retval) |
---|
| 984 | + goto out_free_dentry; |
---|
| 985 | + |
---|
857 | 986 | /* |
---|
858 | 987 | * Allow arch code to reject the ELF at this point, whilst it's |
---|
859 | 988 | * still possible to return an error to the code that invoked |
---|
860 | 989 | * the exec syscall. |
---|
861 | 990 | */ |
---|
862 | | - retval = arch_check_elf(&loc->elf_ex, |
---|
863 | | - !!interpreter, &loc->interp_elf_ex, |
---|
| 991 | + retval = arch_check_elf(elf_ex, |
---|
| 992 | + !!interpreter, interp_elf_ex, |
---|
864 | 993 | &arch_state); |
---|
865 | 994 | if (retval) |
---|
866 | 995 | goto out_free_dentry; |
---|
867 | 996 | |
---|
868 | 997 | /* Flush all traces of the currently running executable */ |
---|
869 | | - retval = flush_old_exec(bprm); |
---|
| 998 | + retval = begin_new_exec(bprm); |
---|
870 | 999 | if (retval) |
---|
871 | 1000 | goto out_free_dentry; |
---|
872 | 1001 | |
---|
873 | 1002 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages |
---|
874 | 1003 | may depend on the personality. */ |
---|
875 | | - SET_PERSONALITY2(loc->elf_ex, &arch_state); |
---|
876 | | - if (elf_read_implies_exec(loc->elf_ex, executable_stack)) |
---|
| 1004 | + SET_PERSONALITY2(*elf_ex, &arch_state); |
---|
| 1005 | + if (elf_read_implies_exec(*elf_ex, executable_stack)) |
---|
877 | 1006 | current->personality |= READ_IMPLIES_EXEC; |
---|
878 | 1007 | |
---|
879 | 1008 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) |
---|
880 | 1009 | current->flags |= PF_RANDOMIZE; |
---|
881 | 1010 | |
---|
882 | 1011 | setup_new_exec(bprm); |
---|
883 | | - install_exec_creds(bprm); |
---|
884 | 1012 | |
---|
885 | 1013 | /* Do this so that we can load the interpreter, if need be. We will |
---|
886 | 1014 | change some of these later */ |
---|
.. | .. |
---|
889 | 1017 | if (retval < 0) |
---|
890 | 1018 | goto out_free_dentry; |
---|
891 | 1019 | |
---|
892 | | - current->mm->start_stack = bprm->p; |
---|
| 1020 | + elf_bss = 0; |
---|
| 1021 | + elf_brk = 0; |
---|
| 1022 | + |
---|
| 1023 | + start_code = ~0UL; |
---|
| 1024 | + end_code = 0; |
---|
| 1025 | + start_data = 0; |
---|
| 1026 | + end_data = 0; |
---|
893 | 1027 | |
---|
894 | 1028 | /* Now we do a little grungy work by mmapping the ELF image into |
---|
895 | 1029 | the correct location in memory. */ |
---|
896 | 1030 | for(i = 0, elf_ppnt = elf_phdata; |
---|
897 | | - i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { |
---|
898 | | - int elf_prot = 0, elf_flags, elf_fixed = MAP_FIXED_NOREPLACE; |
---|
| 1031 | + i < elf_ex->e_phnum; i++, elf_ppnt++) { |
---|
| 1032 | + int elf_prot, elf_flags; |
---|
899 | 1033 | unsigned long k, vaddr; |
---|
900 | 1034 | unsigned long total_size = 0; |
---|
| 1035 | + unsigned long alignment; |
---|
901 | 1036 | |
---|
902 | 1037 | if (elf_ppnt->p_type != PT_LOAD) |
---|
903 | 1038 | continue; |
---|
.. | .. |
---|
927 | 1062 | */ |
---|
928 | 1063 | } |
---|
929 | 1064 | } |
---|
930 | | - |
---|
931 | | - /* |
---|
932 | | - * Some binaries have overlapping elf segments and then |
---|
933 | | - * we have to forcefully map over an existing mapping |
---|
934 | | - * e.g. over this newly established brk mapping. |
---|
935 | | - */ |
---|
936 | | - elf_fixed = MAP_FIXED; |
---|
937 | 1065 | } |
---|
938 | 1066 | |
---|
939 | | - if (elf_ppnt->p_flags & PF_R) |
---|
940 | | - elf_prot |= PROT_READ; |
---|
941 | | - if (elf_ppnt->p_flags & PF_W) |
---|
942 | | - elf_prot |= PROT_WRITE; |
---|
943 | | - if (elf_ppnt->p_flags & PF_X) |
---|
944 | | - elf_prot |= PROT_EXEC; |
---|
| 1067 | + elf_prot = make_prot(elf_ppnt->p_flags, &arch_state, |
---|
| 1068 | + !!interpreter, false); |
---|
945 | 1069 | |
---|
946 | 1070 | elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; |
---|
947 | 1071 | |
---|
.. | .. |
---|
950 | 1074 | * If we are loading ET_EXEC or we have already performed |
---|
951 | 1075 | * the ET_DYN load_addr calculations, proceed normally. |
---|
952 | 1076 | */ |
---|
953 | | - if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { |
---|
954 | | - elf_flags |= elf_fixed; |
---|
955 | | - } else if (loc->elf_ex.e_type == ET_DYN) { |
---|
| 1077 | + if (elf_ex->e_type == ET_EXEC || load_addr_set) { |
---|
| 1078 | + elf_flags |= MAP_FIXED; |
---|
| 1079 | + } else if (elf_ex->e_type == ET_DYN) { |
---|
956 | 1080 | /* |
---|
957 | 1081 | * This logic is run once for the first LOAD Program |
---|
958 | 1082 | * Header for ET_DYN binaries to calculate the |
---|
.. | .. |
---|
983 | 1107 | * independently randomized mmap region (0 load_bias |
---|
984 | 1108 | * without MAP_FIXED). |
---|
985 | 1109 | */ |
---|
986 | | - if (elf_interpreter) { |
---|
| 1110 | + if (interpreter) { |
---|
987 | 1111 | load_bias = ELF_ET_DYN_BASE; |
---|
988 | 1112 | if (current->flags & PF_RANDOMIZE) |
---|
989 | 1113 | load_bias += arch_mmap_rnd(); |
---|
990 | | - elf_flags |= elf_fixed; |
---|
| 1114 | + alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); |
---|
| 1115 | + if (alignment) |
---|
| 1116 | + load_bias &= ~(alignment - 1); |
---|
| 1117 | + elf_flags |= MAP_FIXED; |
---|
991 | 1118 | } else |
---|
992 | 1119 | load_bias = 0; |
---|
993 | 1120 | |
---|
.. | .. |
---|
1001 | 1128 | load_bias = ELF_PAGESTART(load_bias - vaddr); |
---|
1002 | 1129 | |
---|
1003 | 1130 | total_size = total_mapping_size(elf_phdata, |
---|
1004 | | - loc->elf_ex.e_phnum); |
---|
| 1131 | + elf_ex->e_phnum); |
---|
1005 | 1132 | if (!total_size) { |
---|
1006 | 1133 | retval = -EINVAL; |
---|
1007 | 1134 | goto out_free_dentry; |
---|
.. | .. |
---|
1019 | 1146 | if (!load_addr_set) { |
---|
1020 | 1147 | load_addr_set = 1; |
---|
1021 | 1148 | load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); |
---|
1022 | | - if (loc->elf_ex.e_type == ET_DYN) { |
---|
| 1149 | + if (elf_ex->e_type == ET_DYN) { |
---|
1023 | 1150 | load_bias += error - |
---|
1024 | 1151 | ELF_PAGESTART(load_bias + vaddr); |
---|
1025 | 1152 | load_addr += load_bias; |
---|
1026 | 1153 | reloc_func_desc = load_bias; |
---|
1027 | 1154 | } |
---|
1028 | 1155 | } |
---|
| 1156 | + |
---|
| 1157 | + /* |
---|
| 1158 | + * Figure out which segment in the file contains the Program |
---|
| 1159 | + * Header table, and map to the associated memory address. |
---|
| 1160 | + */ |
---|
| 1161 | + if (elf_ppnt->p_offset <= elf_ex->e_phoff && |
---|
| 1162 | + elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { |
---|
| 1163 | + phdr_addr = elf_ex->e_phoff - elf_ppnt->p_offset + |
---|
| 1164 | + elf_ppnt->p_vaddr; |
---|
| 1165 | + } |
---|
| 1166 | + |
---|
1029 | 1167 | k = elf_ppnt->p_vaddr; |
---|
1030 | | - if (k < start_code) |
---|
| 1168 | + if ((elf_ppnt->p_flags & PF_X) && k < start_code) |
---|
1031 | 1169 | start_code = k; |
---|
1032 | 1170 | if (start_data < k) |
---|
1033 | 1171 | start_data = k; |
---|
.. | .. |
---|
1060 | 1198 | } |
---|
1061 | 1199 | } |
---|
1062 | 1200 | |
---|
1063 | | - loc->elf_ex.e_entry += load_bias; |
---|
| 1201 | + e_entry = elf_ex->e_entry + load_bias; |
---|
| 1202 | + phdr_addr += load_bias; |
---|
1064 | 1203 | elf_bss += load_bias; |
---|
1065 | 1204 | elf_brk += load_bias; |
---|
1066 | 1205 | start_code += load_bias; |
---|
.. | .. |
---|
1081 | 1220 | goto out_free_dentry; |
---|
1082 | 1221 | } |
---|
1083 | 1222 | |
---|
1084 | | - if (elf_interpreter) { |
---|
1085 | | - unsigned long interp_map_addr = 0; |
---|
1086 | | - |
---|
1087 | | - elf_entry = load_elf_interp(&loc->interp_elf_ex, |
---|
| 1223 | + if (interpreter) { |
---|
| 1224 | + elf_entry = load_elf_interp(interp_elf_ex, |
---|
1088 | 1225 | interpreter, |
---|
1089 | | - &interp_map_addr, |
---|
1090 | | - load_bias, interp_elf_phdata); |
---|
| 1226 | + load_bias, interp_elf_phdata, |
---|
| 1227 | + &arch_state); |
---|
1091 | 1228 | if (!IS_ERR((void *)elf_entry)) { |
---|
1092 | 1229 | /* |
---|
1093 | 1230 | * load_elf_interp() returns relocation |
---|
1094 | 1231 | * adjustment |
---|
1095 | 1232 | */ |
---|
1096 | 1233 | interp_load_addr = elf_entry; |
---|
1097 | | - elf_entry += loc->interp_elf_ex.e_entry; |
---|
| 1234 | + elf_entry += interp_elf_ex->e_entry; |
---|
1098 | 1235 | } |
---|
1099 | 1236 | if (BAD_ADDR(elf_entry)) { |
---|
1100 | 1237 | retval = IS_ERR((void *)elf_entry) ? |
---|
.. | .. |
---|
1105 | 1242 | |
---|
1106 | 1243 | allow_write_access(interpreter); |
---|
1107 | 1244 | fput(interpreter); |
---|
1108 | | - kfree(elf_interpreter); |
---|
| 1245 | + |
---|
| 1246 | + kfree(interp_elf_ex); |
---|
| 1247 | + kfree(interp_elf_phdata); |
---|
1109 | 1248 | } else { |
---|
1110 | | - elf_entry = loc->elf_ex.e_entry; |
---|
| 1249 | + elf_entry = e_entry; |
---|
1111 | 1250 | if (BAD_ADDR(elf_entry)) { |
---|
1112 | 1251 | retval = -EINVAL; |
---|
1113 | 1252 | goto out_free_dentry; |
---|
1114 | 1253 | } |
---|
1115 | 1254 | } |
---|
1116 | 1255 | |
---|
1117 | | - kfree(interp_elf_phdata); |
---|
1118 | 1256 | kfree(elf_phdata); |
---|
1119 | 1257 | |
---|
1120 | 1258 | set_binfmt(&elf_format); |
---|
1121 | 1259 | |
---|
1122 | 1260 | #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES |
---|
1123 | | - retval = arch_setup_additional_pages(bprm, !!elf_interpreter); |
---|
| 1261 | + retval = arch_setup_additional_pages(bprm, !!interpreter); |
---|
1124 | 1262 | if (retval < 0) |
---|
1125 | 1263 | goto out; |
---|
1126 | 1264 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ |
---|
1127 | 1265 | |
---|
1128 | | - retval = create_elf_tables(bprm, &loc->elf_ex, |
---|
1129 | | - load_addr, interp_load_addr); |
---|
| 1266 | + retval = create_elf_tables(bprm, elf_ex, interp_load_addr, |
---|
| 1267 | + e_entry, phdr_addr); |
---|
1130 | 1268 | if (retval < 0) |
---|
1131 | 1269 | goto out; |
---|
1132 | | - /* N.B. passed_fileno might not be initialized? */ |
---|
1133 | | - current->mm->end_code = end_code; |
---|
1134 | | - current->mm->start_code = start_code; |
---|
1135 | | - current->mm->start_data = start_data; |
---|
1136 | | - current->mm->end_data = end_data; |
---|
1137 | | - current->mm->start_stack = bprm->p; |
---|
| 1270 | + |
---|
| 1271 | + mm = current->mm; |
---|
| 1272 | + mm->end_code = end_code; |
---|
| 1273 | + mm->start_code = start_code; |
---|
| 1274 | + mm->start_data = start_data; |
---|
| 1275 | + mm->end_data = end_data; |
---|
| 1276 | + mm->start_stack = bprm->p; |
---|
1138 | 1277 | |
---|
1139 | 1278 | if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { |
---|
1140 | 1279 | /* |
---|
.. | .. |
---|
1145 | 1284 | * growing down), and into the unused ELF_ET_DYN_BASE region. |
---|
1146 | 1285 | */ |
---|
1147 | 1286 | if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && |
---|
1148 | | - loc->elf_ex.e_type == ET_DYN && !interpreter) |
---|
1149 | | - current->mm->brk = current->mm->start_brk = |
---|
1150 | | - ELF_ET_DYN_BASE; |
---|
| 1287 | + elf_ex->e_type == ET_DYN && !interpreter) { |
---|
| 1288 | + mm->brk = mm->start_brk = ELF_ET_DYN_BASE; |
---|
| 1289 | + } |
---|
1151 | 1290 | |
---|
1152 | | - current->mm->brk = current->mm->start_brk = |
---|
1153 | | - arch_randomize_brk(current->mm); |
---|
| 1291 | + mm->brk = mm->start_brk = arch_randomize_brk(mm); |
---|
1154 | 1292 | #ifdef compat_brk_randomized |
---|
1155 | 1293 | current->brk_randomized = 1; |
---|
1156 | 1294 | #endif |
---|
.. | .. |
---|
1165 | 1303 | MAP_FIXED | MAP_PRIVATE, 0); |
---|
1166 | 1304 | } |
---|
1167 | 1305 | |
---|
| 1306 | + regs = current_pt_regs(); |
---|
1168 | 1307 | #ifdef ELF_PLAT_INIT |
---|
1169 | 1308 | /* |
---|
1170 | 1309 | * The ABI may specify that certain registers be set up in special |
---|
.. | .. |
---|
1183 | 1322 | start_thread(regs, elf_entry, bprm->p); |
---|
1184 | 1323 | retval = 0; |
---|
1185 | 1324 | out: |
---|
1186 | | - kfree(loc); |
---|
1187 | | -out_ret: |
---|
1188 | 1325 | return retval; |
---|
1189 | 1326 | |
---|
1190 | 1327 | /* error cleanup */ |
---|
1191 | 1328 | out_free_dentry: |
---|
| 1329 | + kfree(interp_elf_ex); |
---|
1192 | 1330 | kfree(interp_elf_phdata); |
---|
| 1331 | +out_free_file: |
---|
1193 | 1332 | allow_write_access(interpreter); |
---|
1194 | 1333 | if (interpreter) |
---|
1195 | 1334 | fput(interpreter); |
---|
1196 | | -out_free_interp: |
---|
1197 | | - kfree(elf_interpreter); |
---|
1198 | 1335 | out_free_ph: |
---|
1199 | 1336 | kfree(elf_phdata); |
---|
1200 | 1337 | goto out; |
---|
.. | .. |
---|
1210 | 1347 | unsigned long elf_bss, bss, len; |
---|
1211 | 1348 | int retval, error, i, j; |
---|
1212 | 1349 | struct elfhdr elf_ex; |
---|
1213 | | - loff_t pos = 0; |
---|
1214 | 1350 | |
---|
1215 | 1351 | error = -ENOEXEC; |
---|
1216 | | - retval = kernel_read(file, &elf_ex, sizeof(elf_ex), &pos); |
---|
1217 | | - if (retval != sizeof(elf_ex)) |
---|
| 1352 | + retval = elf_read(file, &elf_ex, sizeof(elf_ex), 0); |
---|
| 1353 | + if (retval < 0) |
---|
1218 | 1354 | goto out; |
---|
1219 | 1355 | |
---|
1220 | 1356 | if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) |
---|
.. | .. |
---|
1239 | 1375 | |
---|
1240 | 1376 | eppnt = elf_phdata; |
---|
1241 | 1377 | error = -ENOEXEC; |
---|
1242 | | - pos = elf_ex.e_phoff; |
---|
1243 | | - retval = kernel_read(file, eppnt, j, &pos); |
---|
1244 | | - if (retval != j) |
---|
| 1378 | + retval = elf_read(file, eppnt, j, elf_ex.e_phoff); |
---|
| 1379 | + if (retval < 0) |
---|
1245 | 1380 | goto out_free_ph; |
---|
1246 | 1381 | |
---|
1247 | 1382 | for (j = 0, i = 0; i<elf_ex.e_phnum; i++) |
---|
.. | .. |
---|
1295 | 1430 | * Jeremy Fitzhardinge <jeremy@sw.oz.au> |
---|
1296 | 1431 | */ |
---|
1297 | 1432 | |
---|
1298 | | -/* |
---|
1299 | | - * The purpose of always_dump_vma() is to make sure that special kernel mappings |
---|
1300 | | - * that are useful for post-mortem analysis are included in every core dump. |
---|
1301 | | - * In that way we ensure that the core dump is fully interpretable later |
---|
1302 | | - * without matching up the same kernel and hardware config to see what PC values |
---|
1303 | | - * meant. These special mappings include - vDSO, vsyscall, and other |
---|
1304 | | - * architecture specific mappings |
---|
1305 | | - */ |
---|
1306 | | -static bool always_dump_vma(struct vm_area_struct *vma) |
---|
1307 | | -{ |
---|
1308 | | - /* Any vsyscall mappings? */ |
---|
1309 | | - if (vma == get_gate_vma(vma->vm_mm)) |
---|
1310 | | - return true; |
---|
1311 | | - |
---|
1312 | | - /* |
---|
1313 | | - * Assume that all vmas with a .name op should always be dumped. |
---|
1314 | | - * If this changes, a new vm_ops field can easily be added. |
---|
1315 | | - */ |
---|
1316 | | - if (vma->vm_ops && vma->vm_ops->name && vma->vm_ops->name(vma)) |
---|
1317 | | - return true; |
---|
1318 | | - |
---|
1319 | | - /* |
---|
1320 | | - * arch_vma_name() returns non-NULL for special architecture mappings, |
---|
1321 | | - * such as vDSO sections. |
---|
1322 | | - */ |
---|
1323 | | - if (arch_vma_name(vma)) |
---|
1324 | | - return true; |
---|
1325 | | - |
---|
1326 | | - return false; |
---|
1327 | | -} |
---|
1328 | | - |
---|
1329 | | -/* |
---|
1330 | | - * Decide what to dump of a segment, part, all or none. |
---|
1331 | | - */ |
---|
1332 | | -static unsigned long vma_dump_size(struct vm_area_struct *vma, |
---|
1333 | | - unsigned long mm_flags) |
---|
1334 | | -{ |
---|
1335 | | -#define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) |
---|
1336 | | - |
---|
1337 | | - /* always dump the vdso and vsyscall sections */ |
---|
1338 | | - if (always_dump_vma(vma)) |
---|
1339 | | - goto whole; |
---|
1340 | | - |
---|
1341 | | - if (vma->vm_flags & VM_DONTDUMP) |
---|
1342 | | - return 0; |
---|
1343 | | - |
---|
1344 | | - /* support for DAX */ |
---|
1345 | | - if (vma_is_dax(vma)) { |
---|
1346 | | - if ((vma->vm_flags & VM_SHARED) && FILTER(DAX_SHARED)) |
---|
1347 | | - goto whole; |
---|
1348 | | - if (!(vma->vm_flags & VM_SHARED) && FILTER(DAX_PRIVATE)) |
---|
1349 | | - goto whole; |
---|
1350 | | - return 0; |
---|
1351 | | - } |
---|
1352 | | - |
---|
1353 | | - /* Hugetlb memory check */ |
---|
1354 | | - if (vma->vm_flags & VM_HUGETLB) { |
---|
1355 | | - if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) |
---|
1356 | | - goto whole; |
---|
1357 | | - if (!(vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_PRIVATE)) |
---|
1358 | | - goto whole; |
---|
1359 | | - return 0; |
---|
1360 | | - } |
---|
1361 | | - |
---|
1362 | | - /* Do not dump I/O mapped devices or special mappings */ |
---|
1363 | | - if (vma->vm_flags & VM_IO) |
---|
1364 | | - return 0; |
---|
1365 | | - |
---|
1366 | | - /* By default, dump shared memory if mapped from an anonymous file. */ |
---|
1367 | | - if (vma->vm_flags & VM_SHARED) { |
---|
1368 | | - if (file_inode(vma->vm_file)->i_nlink == 0 ? |
---|
1369 | | - FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED)) |
---|
1370 | | - goto whole; |
---|
1371 | | - return 0; |
---|
1372 | | - } |
---|
1373 | | - |
---|
1374 | | - /* Dump segments that have been written to. */ |
---|
1375 | | - if (vma->anon_vma && FILTER(ANON_PRIVATE)) |
---|
1376 | | - goto whole; |
---|
1377 | | - if (vma->vm_file == NULL) |
---|
1378 | | - return 0; |
---|
1379 | | - |
---|
1380 | | - if (FILTER(MAPPED_PRIVATE)) |
---|
1381 | | - goto whole; |
---|
1382 | | - |
---|
1383 | | - /* |
---|
1384 | | - * If this looks like the beginning of a DSO or executable mapping, |
---|
1385 | | - * check for an ELF header. If we find one, dump the first page to |
---|
1386 | | - * aid in determining what was mapped here. |
---|
1387 | | - */ |
---|
1388 | | - if (FILTER(ELF_HEADERS) && |
---|
1389 | | - vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { |
---|
1390 | | - u32 __user *header = (u32 __user *) vma->vm_start; |
---|
1391 | | - u32 word; |
---|
1392 | | - mm_segment_t fs = get_fs(); |
---|
1393 | | - /* |
---|
1394 | | - * Doing it this way gets the constant folded by GCC. |
---|
1395 | | - */ |
---|
1396 | | - union { |
---|
1397 | | - u32 cmp; |
---|
1398 | | - char elfmag[SELFMAG]; |
---|
1399 | | - } magic; |
---|
1400 | | - BUILD_BUG_ON(SELFMAG != sizeof word); |
---|
1401 | | - magic.elfmag[EI_MAG0] = ELFMAG0; |
---|
1402 | | - magic.elfmag[EI_MAG1] = ELFMAG1; |
---|
1403 | | - magic.elfmag[EI_MAG2] = ELFMAG2; |
---|
1404 | | - magic.elfmag[EI_MAG3] = ELFMAG3; |
---|
1405 | | - /* |
---|
1406 | | - * Switch to the user "segment" for get_user(), |
---|
1407 | | - * then put back what elf_core_dump() had in place. |
---|
1408 | | - */ |
---|
1409 | | - set_fs(USER_DS); |
---|
1410 | | - if (unlikely(get_user(word, header))) |
---|
1411 | | - word = 0; |
---|
1412 | | - set_fs(fs); |
---|
1413 | | - if (word == magic.cmp) |
---|
1414 | | - return PAGE_SIZE; |
---|
1415 | | - } |
---|
1416 | | - |
---|
1417 | | -#undef FILTER |
---|
1418 | | - |
---|
1419 | | - return 0; |
---|
1420 | | - |
---|
1421 | | -whole: |
---|
1422 | | - return vma->vm_end - vma->vm_start; |
---|
1423 | | -} |
---|
1424 | | - |
---|
1425 | 1433 | /* An ELF note in memory */ |
---|
1426 | 1434 | struct memelfnote |
---|
1427 | 1435 | { |
---|
.. | .. |
---|
1473 | 1481 | elf->e_ehsize = sizeof(struct elfhdr); |
---|
1474 | 1482 | elf->e_phentsize = sizeof(struct elf_phdr); |
---|
1475 | 1483 | elf->e_phnum = segs; |
---|
1476 | | - |
---|
1477 | | - return; |
---|
1478 | 1484 | } |
---|
1479 | 1485 | |
---|
1480 | 1486 | static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) |
---|
.. | .. |
---|
1487 | 1493 | phdr->p_memsz = 0; |
---|
1488 | 1494 | phdr->p_flags = 0; |
---|
1489 | 1495 | phdr->p_align = 0; |
---|
1490 | | - return; |
---|
1491 | 1496 | } |
---|
1492 | 1497 | |
---|
1493 | 1498 | static void fill_note(struct memelfnote *note, const char *name, int type, |
---|
.. | .. |
---|
1497 | 1502 | note->type = type; |
---|
1498 | 1503 | note->datasz = sz; |
---|
1499 | 1504 | note->data = data; |
---|
1500 | | - return; |
---|
1501 | 1505 | } |
---|
1502 | 1506 | |
---|
1503 | 1507 | /* |
---|
.. | .. |
---|
1524 | 1528 | * group-wide total, not its individual thread total. |
---|
1525 | 1529 | */ |
---|
1526 | 1530 | thread_group_cputime(p, &cputime); |
---|
1527 | | - prstatus->pr_utime = ns_to_timeval(cputime.utime); |
---|
1528 | | - prstatus->pr_stime = ns_to_timeval(cputime.stime); |
---|
| 1531 | + prstatus->pr_utime = ns_to_kernel_old_timeval(cputime.utime); |
---|
| 1532 | + prstatus->pr_stime = ns_to_kernel_old_timeval(cputime.stime); |
---|
1529 | 1533 | } else { |
---|
1530 | 1534 | u64 utime, stime; |
---|
1531 | 1535 | |
---|
1532 | 1536 | task_cputime(p, &utime, &stime); |
---|
1533 | | - prstatus->pr_utime = ns_to_timeval(utime); |
---|
1534 | | - prstatus->pr_stime = ns_to_timeval(stime); |
---|
| 1537 | + prstatus->pr_utime = ns_to_kernel_old_timeval(utime); |
---|
| 1538 | + prstatus->pr_stime = ns_to_kernel_old_timeval(stime); |
---|
1535 | 1539 | } |
---|
1536 | 1540 | |
---|
1537 | | - prstatus->pr_cutime = ns_to_timeval(p->signal->cutime); |
---|
1538 | | - prstatus->pr_cstime = ns_to_timeval(p->signal->cstime); |
---|
| 1541 | + prstatus->pr_cutime = ns_to_kernel_old_timeval(p->signal->cutime); |
---|
| 1542 | + prstatus->pr_cstime = ns_to_kernel_old_timeval(p->signal->cstime); |
---|
1539 | 1543 | } |
---|
1540 | 1544 | |
---|
1541 | 1545 | static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, |
---|
.. | .. |
---|
1592 | 1596 | } |
---|
1593 | 1597 | |
---|
1594 | 1598 | static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, |
---|
1595 | | - const siginfo_t *siginfo) |
---|
| 1599 | + const kernel_siginfo_t *siginfo) |
---|
1596 | 1600 | { |
---|
1597 | | - mm_segment_t old_fs = get_fs(); |
---|
1598 | | - set_fs(KERNEL_DS); |
---|
1599 | | - copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo); |
---|
1600 | | - set_fs(old_fs); |
---|
| 1601 | + copy_siginfo_to_external(csigdata, siginfo); |
---|
1601 | 1602 | fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); |
---|
1602 | 1603 | } |
---|
1603 | 1604 | |
---|
.. | .. |
---|
1615 | 1616 | */ |
---|
1616 | 1617 | static int fill_files_note(struct memelfnote *note) |
---|
1617 | 1618 | { |
---|
| 1619 | + struct mm_struct *mm = current->mm; |
---|
1618 | 1620 | struct vm_area_struct *vma; |
---|
1619 | 1621 | unsigned count, size, names_ofs, remaining, n; |
---|
1620 | 1622 | user_long_t *data; |
---|
.. | .. |
---|
1622 | 1624 | char *name_base, *name_curpos; |
---|
1623 | 1625 | |
---|
1624 | 1626 | /* *Estimated* file count and total data size needed */ |
---|
1625 | | - count = current->mm->map_count; |
---|
| 1627 | + count = mm->map_count; |
---|
1626 | 1628 | if (count > UINT_MAX / 64) |
---|
1627 | 1629 | return -EINVAL; |
---|
1628 | 1630 | size = count * 64; |
---|
.. | .. |
---|
1632 | 1634 | if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ |
---|
1633 | 1635 | return -EINVAL; |
---|
1634 | 1636 | size = round_up(size, PAGE_SIZE); |
---|
| 1637 | + /* |
---|
| 1638 | + * "size" can be 0 here legitimately. |
---|
| 1639 | + * Let it ENOMEM and omit NT_FILE section which will be empty anyway. |
---|
| 1640 | + */ |
---|
1635 | 1641 | data = kvmalloc(size, GFP_KERNEL); |
---|
1636 | 1642 | if (ZERO_OR_NULL_PTR(data)) |
---|
1637 | 1643 | return -ENOMEM; |
---|
.. | .. |
---|
1640 | 1646 | name_base = name_curpos = ((char *)data) + names_ofs; |
---|
1641 | 1647 | remaining = size - names_ofs; |
---|
1642 | 1648 | count = 0; |
---|
1643 | | - for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { |
---|
| 1649 | + for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { |
---|
1644 | 1650 | struct file *file; |
---|
1645 | 1651 | const char *filename; |
---|
1646 | 1652 | |
---|
.. | .. |
---|
1674 | 1680 | data[0] = count; |
---|
1675 | 1681 | data[1] = PAGE_SIZE; |
---|
1676 | 1682 | /* |
---|
1677 | | - * Count usually is less than current->mm->map_count, |
---|
| 1683 | + * Count usually is less than mm->map_count, |
---|
1678 | 1684 | * we need to move filenames down. |
---|
1679 | 1685 | */ |
---|
1680 | | - n = current->mm->map_count - count; |
---|
| 1686 | + n = mm->map_count - count; |
---|
1681 | 1687 | if (n != 0) { |
---|
1682 | 1688 | unsigned shift_bytes = n * 3 * sizeof(data[0]); |
---|
1683 | 1689 | memmove(name_base - shift_bytes, name_base, |
---|
.. | .. |
---|
1697 | 1703 | struct elf_thread_core_info *next; |
---|
1698 | 1704 | struct task_struct *task; |
---|
1699 | 1705 | struct elf_prstatus prstatus; |
---|
1700 | | - struct memelfnote notes[0]; |
---|
| 1706 | + struct memelfnote notes[]; |
---|
1701 | 1707 | }; |
---|
1702 | 1708 | |
---|
1703 | 1709 | struct elf_note_info { |
---|
.. | .. |
---|
1736 | 1742 | long signr, size_t *total) |
---|
1737 | 1743 | { |
---|
1738 | 1744 | unsigned int i; |
---|
1739 | | - unsigned int regset0_size = regset_size(t->task, &view->regsets[0]); |
---|
| 1745 | + int regset0_size; |
---|
1740 | 1746 | |
---|
1741 | 1747 | /* |
---|
1742 | 1748 | * NT_PRSTATUS is the one special case, because the regset data |
---|
.. | .. |
---|
1745 | 1751 | * We assume that regset 0 is NT_PRSTATUS. |
---|
1746 | 1752 | */ |
---|
1747 | 1753 | fill_prstatus(&t->prstatus, t->task, signr); |
---|
1748 | | - (void) view->regsets[0].get(t->task, &view->regsets[0], 0, regset0_size, |
---|
1749 | | - &t->prstatus.pr_reg, NULL); |
---|
| 1754 | + regset0_size = regset_get(t->task, &view->regsets[0], |
---|
| 1755 | + sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); |
---|
| 1756 | + if (regset0_size < 0) |
---|
| 1757 | + return 0; |
---|
1750 | 1758 | |
---|
1751 | 1759 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, |
---|
1752 | 1760 | PRSTATUS_SIZE(t->prstatus, regset0_size), &t->prstatus); |
---|
.. | .. |
---|
1761 | 1769 | */ |
---|
1762 | 1770 | for (i = 1; i < view->n; ++i) { |
---|
1763 | 1771 | const struct user_regset *regset = &view->regsets[i]; |
---|
| 1772 | + int note_type = regset->core_note_type; |
---|
| 1773 | + bool is_fpreg = note_type == NT_PRFPREG; |
---|
| 1774 | + void *data; |
---|
| 1775 | + int ret; |
---|
| 1776 | + |
---|
1764 | 1777 | do_thread_regset_writeback(t->task, regset); |
---|
1765 | | - if (regset->core_note_type && regset->get && |
---|
1766 | | - (!regset->active || regset->active(t->task, regset) > 0)) { |
---|
1767 | | - int ret; |
---|
1768 | | - size_t size = regset_size(t->task, regset); |
---|
1769 | | - void *data = kzalloc(size, GFP_KERNEL); |
---|
1770 | | - if (unlikely(!data)) |
---|
1771 | | - return 0; |
---|
1772 | | - ret = regset->get(t->task, regset, |
---|
1773 | | - 0, size, data, NULL); |
---|
1774 | | - if (unlikely(ret)) |
---|
1775 | | - kfree(data); |
---|
1776 | | - else { |
---|
1777 | | - if (regset->core_note_type != NT_PRFPREG) |
---|
1778 | | - fill_note(&t->notes[i], "LINUX", |
---|
1779 | | - regset->core_note_type, |
---|
1780 | | - size, data); |
---|
1781 | | - else { |
---|
1782 | | - SET_PR_FPVALID(&t->prstatus, |
---|
1783 | | - 1, regset0_size); |
---|
1784 | | - fill_note(&t->notes[i], "CORE", |
---|
1785 | | - NT_PRFPREG, size, data); |
---|
1786 | | - } |
---|
1787 | | - *total += notesize(&t->notes[i]); |
---|
1788 | | - } |
---|
1789 | | - } |
---|
| 1778 | + if (!note_type) // not for coredumps |
---|
| 1779 | + continue; |
---|
| 1780 | + if (regset->active && regset->active(t->task, regset) <= 0) |
---|
| 1781 | + continue; |
---|
| 1782 | + |
---|
| 1783 | + ret = regset_get_alloc(t->task, regset, ~0U, &data); |
---|
| 1784 | + if (ret < 0) |
---|
| 1785 | + continue; |
---|
| 1786 | + |
---|
| 1787 | + if (is_fpreg) |
---|
| 1788 | + SET_PR_FPVALID(&t->prstatus, 1, regset0_size); |
---|
| 1789 | + |
---|
| 1790 | + fill_note(&t->notes[i], is_fpreg ? "CORE" : "LINUX", |
---|
| 1791 | + note_type, ret, data); |
---|
| 1792 | + |
---|
| 1793 | + *total += notesize(&t->notes[i]); |
---|
1790 | 1794 | } |
---|
1791 | 1795 | |
---|
1792 | 1796 | return 1; |
---|
.. | .. |
---|
1794 | 1798 | |
---|
1795 | 1799 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
---|
1796 | 1800 | struct elf_note_info *info, |
---|
1797 | | - const siginfo_t *siginfo, struct pt_regs *regs) |
---|
| 1801 | + struct coredump_params *cprm) |
---|
1798 | 1802 | { |
---|
1799 | 1803 | struct task_struct *dump_task = current; |
---|
1800 | 1804 | const struct user_regset_view *view = task_user_regset_view(dump_task); |
---|
.. | .. |
---|
1866 | 1870 | * Now fill in each thread's information. |
---|
1867 | 1871 | */ |
---|
1868 | 1872 | for (t = info->thread; t != NULL; t = t->next) |
---|
1869 | | - if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) |
---|
| 1873 | + if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, &info->size)) |
---|
1870 | 1874 | return 0; |
---|
1871 | 1875 | |
---|
1872 | 1876 | /* |
---|
.. | .. |
---|
1875 | 1879 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); |
---|
1876 | 1880 | info->size += notesize(&info->psinfo); |
---|
1877 | 1881 | |
---|
1878 | | - fill_siginfo_note(&info->signote, &info->csigdata, siginfo); |
---|
| 1882 | + fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo); |
---|
1879 | 1883 | info->size += notesize(&info->signote); |
---|
1880 | 1884 | |
---|
1881 | 1885 | fill_auxv_note(&info->auxv, current->mm); |
---|
.. | .. |
---|
1955 | 1959 | struct elf_prstatus prstatus; /* NT_PRSTATUS */ |
---|
1956 | 1960 | elf_fpregset_t fpu; /* NT_PRFPREG */ |
---|
1957 | 1961 | struct task_struct *thread; |
---|
1958 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1959 | | - elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ |
---|
1960 | | -#endif |
---|
1961 | 1962 | struct memelfnote notes[3]; |
---|
1962 | 1963 | int num_notes; |
---|
1963 | 1964 | }; |
---|
.. | .. |
---|
1988 | 1989 | t->num_notes++; |
---|
1989 | 1990 | sz += notesize(&t->notes[1]); |
---|
1990 | 1991 | } |
---|
1991 | | - |
---|
1992 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1993 | | - if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { |
---|
1994 | | - fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, |
---|
1995 | | - sizeof(t->xfpu), &t->xfpu); |
---|
1996 | | - t->num_notes++; |
---|
1997 | | - sz += notesize(&t->notes[2]); |
---|
1998 | | - } |
---|
1999 | | -#endif |
---|
2000 | 1992 | return sz; |
---|
2001 | 1993 | } |
---|
2002 | 1994 | |
---|
.. | .. |
---|
2007 | 1999 | struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ |
---|
2008 | 2000 | struct list_head thread_list; |
---|
2009 | 2001 | elf_fpregset_t *fpu; |
---|
2010 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
2011 | | - elf_fpxregset_t *xfpu; |
---|
2012 | | -#endif |
---|
2013 | 2002 | user_siginfo_t csigdata; |
---|
2014 | 2003 | int thread_status_size; |
---|
2015 | 2004 | int numnote; |
---|
.. | .. |
---|
2033 | 2022 | info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); |
---|
2034 | 2023 | if (!info->fpu) |
---|
2035 | 2024 | return 0; |
---|
2036 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
2037 | | - info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); |
---|
2038 | | - if (!info->xfpu) |
---|
2039 | | - return 0; |
---|
2040 | | -#endif |
---|
2041 | 2025 | return 1; |
---|
2042 | 2026 | } |
---|
2043 | 2027 | |
---|
2044 | 2028 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
---|
2045 | 2029 | struct elf_note_info *info, |
---|
2046 | | - const siginfo_t *siginfo, struct pt_regs *regs) |
---|
| 2030 | + struct coredump_params *cprm) |
---|
2047 | 2031 | { |
---|
2048 | | - struct list_head *t; |
---|
2049 | 2032 | struct core_thread *ct; |
---|
2050 | 2033 | struct elf_thread_status *ets; |
---|
2051 | 2034 | |
---|
.. | .. |
---|
2062 | 2045 | list_add(&ets->list, &info->thread_list); |
---|
2063 | 2046 | } |
---|
2064 | 2047 | |
---|
2065 | | - list_for_each(t, &info->thread_list) { |
---|
| 2048 | + list_for_each_entry(ets, &info->thread_list, list) { |
---|
2066 | 2049 | int sz; |
---|
2067 | 2050 | |
---|
2068 | | - ets = list_entry(t, struct elf_thread_status, list); |
---|
2069 | | - sz = elf_dump_thread_status(siginfo->si_signo, ets); |
---|
| 2051 | + sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets); |
---|
2070 | 2052 | info->thread_status_size += sz; |
---|
2071 | 2053 | } |
---|
2072 | 2054 | /* now collect the dump for the current */ |
---|
2073 | 2055 | memset(info->prstatus, 0, sizeof(*info->prstatus)); |
---|
2074 | | - fill_prstatus(info->prstatus, current, siginfo->si_signo); |
---|
2075 | | - elf_core_copy_regs(&info->prstatus->pr_reg, regs); |
---|
| 2056 | + fill_prstatus(info->prstatus, current, cprm->siginfo->si_signo); |
---|
| 2057 | + elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs); |
---|
2076 | 2058 | |
---|
2077 | 2059 | /* Set up header */ |
---|
2078 | 2060 | fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); |
---|
.. | .. |
---|
2088 | 2070 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, |
---|
2089 | 2071 | sizeof(*info->psinfo), info->psinfo); |
---|
2090 | 2072 | |
---|
2091 | | - fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); |
---|
| 2073 | + fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo); |
---|
2092 | 2074 | fill_auxv_note(info->notes + 3, current->mm); |
---|
2093 | 2075 | info->numnote = 4; |
---|
2094 | 2076 | |
---|
.. | .. |
---|
2098 | 2080 | } |
---|
2099 | 2081 | |
---|
2100 | 2082 | /* Try to dump the FPU. */ |
---|
2101 | | - info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, |
---|
2102 | | - info->fpu); |
---|
| 2083 | + info->prstatus->pr_fpvalid = |
---|
| 2084 | + elf_core_copy_task_fpregs(current, cprm->regs, info->fpu); |
---|
2103 | 2085 | if (info->prstatus->pr_fpvalid) |
---|
2104 | 2086 | fill_note(info->notes + info->numnote++, |
---|
2105 | 2087 | "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); |
---|
2106 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
2107 | | - if (elf_core_copy_task_xfpregs(current, info->xfpu)) |
---|
2108 | | - fill_note(info->notes + info->numnote++, |
---|
2109 | | - "LINUX", ELF_CORE_XFPREG_TYPE, |
---|
2110 | | - sizeof(*info->xfpu), info->xfpu); |
---|
2111 | | -#endif |
---|
2112 | | - |
---|
2113 | 2088 | return 1; |
---|
2114 | 2089 | } |
---|
2115 | 2090 | |
---|
.. | .. |
---|
2129 | 2104 | static int write_note_info(struct elf_note_info *info, |
---|
2130 | 2105 | struct coredump_params *cprm) |
---|
2131 | 2106 | { |
---|
| 2107 | + struct elf_thread_status *ets; |
---|
2132 | 2108 | int i; |
---|
2133 | | - struct list_head *t; |
---|
2134 | 2109 | |
---|
2135 | 2110 | for (i = 0; i < info->numnote; i++) |
---|
2136 | 2111 | if (!writenote(info->notes + i, cprm)) |
---|
2137 | 2112 | return 0; |
---|
2138 | 2113 | |
---|
2139 | 2114 | /* write out the thread status notes section */ |
---|
2140 | | - list_for_each(t, &info->thread_list) { |
---|
2141 | | - struct elf_thread_status *tmp = |
---|
2142 | | - list_entry(t, struct elf_thread_status, list); |
---|
2143 | | - |
---|
2144 | | - for (i = 0; i < tmp->num_notes; i++) |
---|
2145 | | - if (!writenote(&tmp->notes[i], cprm)) |
---|
| 2115 | + list_for_each_entry(ets, &info->thread_list, list) { |
---|
| 2116 | + for (i = 0; i < ets->num_notes; i++) |
---|
| 2117 | + if (!writenote(&ets->notes[i], cprm)) |
---|
2146 | 2118 | return 0; |
---|
2147 | 2119 | } |
---|
2148 | 2120 | |
---|
.. | .. |
---|
2165 | 2137 | kfree(info->psinfo); |
---|
2166 | 2138 | kfree(info->notes); |
---|
2167 | 2139 | kfree(info->fpu); |
---|
2168 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
2169 | | - kfree(info->xfpu); |
---|
2170 | | -#endif |
---|
2171 | 2140 | } |
---|
2172 | 2141 | |
---|
2173 | 2142 | #endif |
---|
2174 | | - |
---|
2175 | | -static struct vm_area_struct *first_vma(struct task_struct *tsk, |
---|
2176 | | - struct vm_area_struct *gate_vma) |
---|
2177 | | -{ |
---|
2178 | | - struct vm_area_struct *ret = tsk->mm->mmap; |
---|
2179 | | - |
---|
2180 | | - if (ret) |
---|
2181 | | - return ret; |
---|
2182 | | - return gate_vma; |
---|
2183 | | -} |
---|
2184 | | -/* |
---|
2185 | | - * Helper function for iterating across a vma list. It ensures that the caller |
---|
2186 | | - * will visit `gate_vma' prior to terminating the search. |
---|
2187 | | - */ |
---|
2188 | | -static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, |
---|
2189 | | - struct vm_area_struct *gate_vma) |
---|
2190 | | -{ |
---|
2191 | | - struct vm_area_struct *ret; |
---|
2192 | | - |
---|
2193 | | - ret = this_vma->vm_next; |
---|
2194 | | - if (ret) |
---|
2195 | | - return ret; |
---|
2196 | | - if (this_vma == gate_vma) |
---|
2197 | | - return NULL; |
---|
2198 | | - return gate_vma; |
---|
2199 | | -} |
---|
2200 | 2143 | |
---|
2201 | 2144 | static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, |
---|
2202 | 2145 | elf_addr_t e_shoff, int segs) |
---|
.. | .. |
---|
2224 | 2167 | static int elf_core_dump(struct coredump_params *cprm) |
---|
2225 | 2168 | { |
---|
2226 | 2169 | int has_dumped = 0; |
---|
2227 | | - mm_segment_t fs; |
---|
2228 | | - int segs, i; |
---|
2229 | | - size_t vma_data_size = 0; |
---|
2230 | | - struct vm_area_struct *vma, *gate_vma; |
---|
2231 | | - struct elfhdr *elf = NULL; |
---|
| 2170 | + int vma_count, segs, i; |
---|
| 2171 | + size_t vma_data_size; |
---|
| 2172 | + struct elfhdr elf; |
---|
2232 | 2173 | loff_t offset = 0, dataoff; |
---|
2233 | 2174 | struct elf_note_info info = { }; |
---|
2234 | 2175 | struct elf_phdr *phdr4note = NULL; |
---|
2235 | 2176 | struct elf_shdr *shdr4extnum = NULL; |
---|
2236 | 2177 | Elf_Half e_phnum; |
---|
2237 | 2178 | elf_addr_t e_shoff; |
---|
2238 | | - elf_addr_t *vma_filesz = NULL; |
---|
| 2179 | + struct core_vma_metadata *vma_meta; |
---|
2239 | 2180 | |
---|
2240 | | - /* |
---|
2241 | | - * We no longer stop all VM operations. |
---|
2242 | | - * |
---|
2243 | | - * This is because those proceses that could possibly change map_count |
---|
2244 | | - * or the mmap / vma pages are now blocked in do_exit on current |
---|
2245 | | - * finishing this core dump. |
---|
2246 | | - * |
---|
2247 | | - * Only ptrace can touch these memory addresses, but it doesn't change |
---|
2248 | | - * the map_count or the pages allocated. So no possibility of crashing |
---|
2249 | | - * exists while dumping the mm->vm_next areas to the core file. |
---|
2250 | | - */ |
---|
2251 | | - |
---|
2252 | | - /* alloc memory for large data structures: too large to be on stack */ |
---|
2253 | | - elf = kmalloc(sizeof(*elf), GFP_KERNEL); |
---|
2254 | | - if (!elf) |
---|
2255 | | - goto out; |
---|
| 2181 | + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) |
---|
| 2182 | + return 0; |
---|
| 2183 | + |
---|
2256 | 2184 | /* |
---|
2257 | 2185 | * The number of segs are recored into ELF header as 16bit value. |
---|
2258 | 2186 | * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. |
---|
2259 | 2187 | */ |
---|
2260 | | - segs = current->mm->map_count; |
---|
2261 | | - segs += elf_core_extra_phdrs(); |
---|
2262 | | - |
---|
2263 | | - gate_vma = get_gate_vma(current->mm); |
---|
2264 | | - if (gate_vma != NULL) |
---|
2265 | | - segs++; |
---|
| 2188 | + segs = vma_count + elf_core_extra_phdrs(); |
---|
2266 | 2189 | |
---|
2267 | 2190 | /* for notes section */ |
---|
2268 | 2191 | segs++; |
---|
.. | .. |
---|
2276 | 2199 | * Collect all the non-memory information about the process for the |
---|
2277 | 2200 | * notes. This also sets up the file header. |
---|
2278 | 2201 | */ |
---|
2279 | | - if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs)) |
---|
2280 | | - goto cleanup; |
---|
| 2202 | + if (!fill_note_info(&elf, e_phnum, &info, cprm)) |
---|
| 2203 | + goto end_coredump; |
---|
2281 | 2204 | |
---|
2282 | 2205 | has_dumped = 1; |
---|
2283 | 2206 | |
---|
2284 | | - fs = get_fs(); |
---|
2285 | | - set_fs(KERNEL_DS); |
---|
2286 | | - |
---|
2287 | | - offset += sizeof(*elf); /* Elf header */ |
---|
| 2207 | + offset += sizeof(elf); /* Elf header */ |
---|
2288 | 2208 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
---|
2289 | 2209 | |
---|
2290 | 2210 | /* Write notes phdr entry */ |
---|
.. | .. |
---|
2303 | 2223 | |
---|
2304 | 2224 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
---|
2305 | 2225 | |
---|
2306 | | - if (segs - 1 > ULONG_MAX / sizeof(*vma_filesz)) |
---|
2307 | | - goto end_coredump; |
---|
2308 | | - vma_filesz = kvmalloc(array_size(sizeof(*vma_filesz), (segs - 1)), |
---|
2309 | | - GFP_KERNEL); |
---|
2310 | | - if (ZERO_OR_NULL_PTR(vma_filesz)) |
---|
2311 | | - goto end_coredump; |
---|
2312 | | - |
---|
2313 | | - for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; |
---|
2314 | | - vma = next_vma(vma, gate_vma)) { |
---|
2315 | | - unsigned long dump_size; |
---|
2316 | | - |
---|
2317 | | - dump_size = vma_dump_size(vma, cprm->mm_flags); |
---|
2318 | | - vma_filesz[i++] = dump_size; |
---|
2319 | | - vma_data_size += dump_size; |
---|
2320 | | - } |
---|
2321 | | - |
---|
2322 | 2226 | offset += vma_data_size; |
---|
2323 | 2227 | offset += elf_core_extra_data_size(); |
---|
2324 | 2228 | e_shoff = offset; |
---|
.. | .. |
---|
2327 | 2231 | shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); |
---|
2328 | 2232 | if (!shdr4extnum) |
---|
2329 | 2233 | goto end_coredump; |
---|
2330 | | - fill_extnum_info(elf, shdr4extnum, e_shoff, segs); |
---|
| 2234 | + fill_extnum_info(&elf, shdr4extnum, e_shoff, segs); |
---|
2331 | 2235 | } |
---|
2332 | 2236 | |
---|
2333 | 2237 | offset = dataoff; |
---|
2334 | 2238 | |
---|
2335 | | - if (!dump_emit(cprm, elf, sizeof(*elf))) |
---|
| 2239 | + if (!dump_emit(cprm, &elf, sizeof(elf))) |
---|
2336 | 2240 | goto end_coredump; |
---|
2337 | 2241 | |
---|
2338 | 2242 | if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note))) |
---|
2339 | 2243 | goto end_coredump; |
---|
2340 | 2244 | |
---|
2341 | 2245 | /* Write program headers for segments dump */ |
---|
2342 | | - for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; |
---|
2343 | | - vma = next_vma(vma, gate_vma)) { |
---|
| 2246 | + for (i = 0; i < vma_count; i++) { |
---|
| 2247 | + struct core_vma_metadata *meta = vma_meta + i; |
---|
2344 | 2248 | struct elf_phdr phdr; |
---|
2345 | 2249 | |
---|
2346 | 2250 | phdr.p_type = PT_LOAD; |
---|
2347 | 2251 | phdr.p_offset = offset; |
---|
2348 | | - phdr.p_vaddr = vma->vm_start; |
---|
| 2252 | + phdr.p_vaddr = meta->start; |
---|
2349 | 2253 | phdr.p_paddr = 0; |
---|
2350 | | - phdr.p_filesz = vma_filesz[i++]; |
---|
2351 | | - phdr.p_memsz = vma->vm_end - vma->vm_start; |
---|
| 2254 | + phdr.p_filesz = meta->dump_size; |
---|
| 2255 | + phdr.p_memsz = meta->end - meta->start; |
---|
2352 | 2256 | offset += phdr.p_filesz; |
---|
2353 | | - phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
---|
2354 | | - if (vma->vm_flags & VM_WRITE) |
---|
| 2257 | + phdr.p_flags = 0; |
---|
| 2258 | + if (meta->flags & VM_READ) |
---|
| 2259 | + phdr.p_flags |= PF_R; |
---|
| 2260 | + if (meta->flags & VM_WRITE) |
---|
2355 | 2261 | phdr.p_flags |= PF_W; |
---|
2356 | | - if (vma->vm_flags & VM_EXEC) |
---|
| 2262 | + if (meta->flags & VM_EXEC) |
---|
2357 | 2263 | phdr.p_flags |= PF_X; |
---|
2358 | 2264 | phdr.p_align = ELF_EXEC_PAGESIZE; |
---|
2359 | 2265 | |
---|
.. | .. |
---|
2375 | 2281 | if (!dump_skip(cprm, dataoff - cprm->pos)) |
---|
2376 | 2282 | goto end_coredump; |
---|
2377 | 2283 | |
---|
2378 | | - for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; |
---|
2379 | | - vma = next_vma(vma, gate_vma)) { |
---|
2380 | | - unsigned long addr; |
---|
2381 | | - unsigned long end; |
---|
| 2284 | + for (i = 0; i < vma_count; i++) { |
---|
| 2285 | + struct core_vma_metadata *meta = vma_meta + i; |
---|
2382 | 2286 | |
---|
2383 | | - end = vma->vm_start + vma_filesz[i++]; |
---|
2384 | | - |
---|
2385 | | - for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { |
---|
2386 | | - struct page *page; |
---|
2387 | | - int stop; |
---|
2388 | | - |
---|
2389 | | - page = get_dump_page(addr); |
---|
2390 | | - if (page) { |
---|
2391 | | - void *kaddr = kmap(page); |
---|
2392 | | - stop = !dump_emit(cprm, kaddr, PAGE_SIZE); |
---|
2393 | | - kunmap(page); |
---|
2394 | | - put_page(page); |
---|
2395 | | - } else |
---|
2396 | | - stop = !dump_skip(cprm, PAGE_SIZE); |
---|
2397 | | - if (stop) |
---|
2398 | | - goto end_coredump; |
---|
2399 | | - } |
---|
| 2287 | + if (!dump_user_range(cprm, meta->start, meta->dump_size)) |
---|
| 2288 | + goto end_coredump; |
---|
2400 | 2289 | } |
---|
2401 | 2290 | dump_truncate(cprm); |
---|
2402 | 2291 | |
---|
.. | .. |
---|
2409 | 2298 | } |
---|
2410 | 2299 | |
---|
2411 | 2300 | end_coredump: |
---|
2412 | | - set_fs(fs); |
---|
2413 | | - |
---|
2414 | | -cleanup: |
---|
2415 | 2301 | free_note_info(&info); |
---|
2416 | 2302 | kfree(shdr4extnum); |
---|
2417 | | - kvfree(vma_filesz); |
---|
| 2303 | + kvfree(vma_meta); |
---|
2418 | 2304 | kfree(phdr4note); |
---|
2419 | | - kfree(elf); |
---|
2420 | | -out: |
---|
2421 | 2305 | return has_dumped; |
---|
2422 | 2306 | } |
---|
2423 | 2307 | |
---|