.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* binfmt_elf_fdpic.c: FDPIC ELF binary format |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved. |
---|
4 | 5 | * Written by David Howells (dhowells@redhat.com) |
---|
5 | 6 | * Derived from binfmt_elf.c |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License |
---|
9 | | - * as published by the Free Software Foundation; either version |
---|
10 | | - * 2 of the License, or (at your option) any later version. |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
39 | 35 | #include <linux/elfcore.h> |
---|
40 | 36 | #include <linux/coredump.h> |
---|
41 | 37 | #include <linux/dax.h> |
---|
| 38 | +#include <linux/regset.h> |
---|
42 | 39 | |
---|
43 | 40 | #include <linux/uaccess.h> |
---|
44 | 41 | #include <asm/param.h> |
---|
45 | | -#include <asm/pgalloc.h> |
---|
46 | 42 | |
---|
47 | 43 | typedef char *elf_caddr_t; |
---|
48 | 44 | |
---|
.. | .. |
---|
342 | 338 | interp_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; |
---|
343 | 339 | |
---|
344 | 340 | /* flush all traces of the currently running executable */ |
---|
345 | | - retval = flush_old_exec(bprm); |
---|
| 341 | + retval = begin_new_exec(bprm); |
---|
346 | 342 | if (retval) |
---|
347 | 343 | goto error; |
---|
348 | 344 | |
---|
349 | 345 | /* there's now no turning back... the old userspace image is dead, |
---|
350 | 346 | * defunct, deceased, etc. |
---|
351 | 347 | */ |
---|
| 348 | + SET_PERSONALITY(exec_params.hdr); |
---|
352 | 349 | if (elf_check_fdpic(&exec_params.hdr)) |
---|
353 | | - set_personality(PER_LINUX_FDPIC); |
---|
354 | | - else |
---|
355 | | - set_personality(PER_LINUX); |
---|
| 350 | + current->personality |= PER_LINUX_FDPIC; |
---|
356 | 351 | if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) |
---|
357 | 352 | current->personality |= READ_IMPLIES_EXEC; |
---|
358 | 353 | |
---|
.. | .. |
---|
438 | 433 | current->mm->start_stack = current->mm->start_brk + stack_size; |
---|
439 | 434 | #endif |
---|
440 | 435 | |
---|
441 | | - install_exec_creds(bprm); |
---|
442 | | - if (create_elf_fdpic_tables(bprm, current->mm, |
---|
443 | | - &exec_params, &interp_params) < 0) |
---|
| 436 | + retval = create_elf_fdpic_tables(bprm, current->mm, &exec_params, |
---|
| 437 | + &interp_params); |
---|
| 438 | + if (retval < 0) |
---|
444 | 439 | goto error; |
---|
445 | 440 | |
---|
446 | 441 | kdebug("- start_code %lx", current->mm->start_code); |
---|
.. | .. |
---|
541 | 536 | platform_len = strlen(k_platform) + 1; |
---|
542 | 537 | sp -= platform_len; |
---|
543 | 538 | u_platform = (char __user *) sp; |
---|
544 | | - if (__copy_to_user(u_platform, k_platform, platform_len) != 0) |
---|
| 539 | + if (copy_to_user(u_platform, k_platform, platform_len) != 0) |
---|
545 | 540 | return -EFAULT; |
---|
546 | 541 | } |
---|
547 | 542 | |
---|
.. | .. |
---|
556 | 551 | platform_len = strlen(k_base_platform) + 1; |
---|
557 | 552 | sp -= platform_len; |
---|
558 | 553 | u_base_platform = (char __user *) sp; |
---|
559 | | - if (__copy_to_user(u_base_platform, k_base_platform, platform_len) != 0) |
---|
| 554 | + if (copy_to_user(u_base_platform, k_base_platform, platform_len) != 0) |
---|
560 | 555 | return -EFAULT; |
---|
561 | 556 | } |
---|
562 | 557 | |
---|
.. | .. |
---|
593 | 588 | nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) + |
---|
594 | 589 | (k_base_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH; |
---|
595 | 590 | |
---|
596 | | - if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) |
---|
| 591 | + if (bprm->have_execfd) |
---|
597 | 592 | nitems++; |
---|
598 | 593 | |
---|
599 | 594 | csp = sp; |
---|
.. | .. |
---|
608 | 603 | /* put the ELF interpreter info on the stack */ |
---|
609 | 604 | #define NEW_AUX_ENT(id, val) \ |
---|
610 | 605 | do { \ |
---|
611 | | - struct { unsigned long _id, _val; } __user *ent; \ |
---|
| 606 | + struct { unsigned long _id, _val; } __user *ent, v; \ |
---|
612 | 607 | \ |
---|
613 | 608 | ent = (void __user *) csp; \ |
---|
614 | | - __put_user((id), &ent[nr]._id); \ |
---|
615 | | - __put_user((val), &ent[nr]._val); \ |
---|
| 609 | + v._id = (id); \ |
---|
| 610 | + v._val = (val); \ |
---|
| 611 | + if (copy_to_user(ent + nr, &v, sizeof(v))) \ |
---|
| 612 | + return -EFAULT; \ |
---|
616 | 613 | nr++; \ |
---|
617 | 614 | } while (0) |
---|
618 | 615 | |
---|
.. | .. |
---|
633 | 630 | (elf_addr_t) (unsigned long) u_base_platform); |
---|
634 | 631 | } |
---|
635 | 632 | |
---|
636 | | - if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { |
---|
| 633 | + if (bprm->have_execfd) { |
---|
637 | 634 | nr = 0; |
---|
638 | 635 | csp -= 2 * sizeof(unsigned long); |
---|
639 | | - NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); |
---|
| 636 | + NEW_AUX_ENT(AT_EXECFD, bprm->execfd); |
---|
640 | 637 | } |
---|
641 | 638 | |
---|
642 | 639 | nr = 0; |
---|
.. | .. |
---|
679 | 676 | |
---|
680 | 677 | /* stack argc */ |
---|
681 | 678 | csp -= sizeof(unsigned long); |
---|
682 | | - __put_user(bprm->argc, (unsigned long __user *) csp); |
---|
| 679 | + if (put_user(bprm->argc, (unsigned long __user *) csp)) |
---|
| 680 | + return -EFAULT; |
---|
683 | 681 | |
---|
684 | 682 | BUG_ON(csp != sp); |
---|
685 | 683 | |
---|
.. | .. |
---|
693 | 691 | |
---|
694 | 692 | p = (char __user *) current->mm->arg_start; |
---|
695 | 693 | for (loop = bprm->argc; loop > 0; loop--) { |
---|
696 | | - __put_user((elf_caddr_t) p, argv++); |
---|
| 694 | + if (put_user((elf_caddr_t) p, argv++)) |
---|
| 695 | + return -EFAULT; |
---|
697 | 696 | len = strnlen_user(p, MAX_ARG_STRLEN); |
---|
698 | 697 | if (!len || len > MAX_ARG_STRLEN) |
---|
699 | 698 | return -EINVAL; |
---|
700 | 699 | p += len; |
---|
701 | 700 | } |
---|
702 | | - __put_user(NULL, argv); |
---|
| 701 | + if (put_user(NULL, argv)) |
---|
| 702 | + return -EFAULT; |
---|
703 | 703 | current->mm->arg_end = (unsigned long) p; |
---|
704 | 704 | |
---|
705 | 705 | /* fill in the envv[] array */ |
---|
706 | 706 | current->mm->env_start = (unsigned long) p; |
---|
707 | 707 | for (loop = bprm->envc; loop > 0; loop--) { |
---|
708 | | - __put_user((elf_caddr_t)(unsigned long) p, envp++); |
---|
| 708 | + if (put_user((elf_caddr_t)(unsigned long) p, envp++)) |
---|
| 709 | + return -EFAULT; |
---|
709 | 710 | len = strnlen_user(p, MAX_ARG_STRLEN); |
---|
710 | 711 | if (!len || len > MAX_ARG_STRLEN) |
---|
711 | 712 | return -EINVAL; |
---|
712 | 713 | p += len; |
---|
713 | 714 | } |
---|
714 | | - __put_user(NULL, envp); |
---|
| 715 | + if (put_user(NULL, envp)) |
---|
| 716 | + return -EFAULT; |
---|
715 | 717 | current->mm->env_end = (unsigned long) p; |
---|
716 | 718 | |
---|
717 | 719 | mm->start_stack = (unsigned long) sp; |
---|
.. | .. |
---|
853 | 855 | |
---|
854 | 856 | tmp = phdr->p_memsz / sizeof(Elf32_Dyn); |
---|
855 | 857 | dyn = (Elf32_Dyn __user *)params->dynamic_addr; |
---|
856 | | - __get_user(d_tag, &dyn[tmp - 1].d_tag); |
---|
857 | | - if (d_tag != 0) |
---|
| 858 | + if (get_user(d_tag, &dyn[tmp - 1].d_tag) || |
---|
| 859 | + d_tag != 0) |
---|
858 | 860 | goto dynamic_error; |
---|
859 | 861 | break; |
---|
860 | 862 | } |
---|
.. | .. |
---|
1187 | 1189 | */ |
---|
1188 | 1190 | #ifdef CONFIG_ELF_CORE |
---|
1189 | 1191 | |
---|
1190 | | -/* |
---|
1191 | | - * Decide whether a segment is worth dumping; default is yes to be |
---|
1192 | | - * sure (missing info is worse than too much; etc). |
---|
1193 | | - * Personally I'd include everything, and use the coredump limit... |
---|
1194 | | - * |
---|
1195 | | - * I think we should skip something. But I am not sure how. H.J. |
---|
1196 | | - */ |
---|
1197 | | -static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) |
---|
| 1192 | +struct elf_prstatus_fdpic |
---|
1198 | 1193 | { |
---|
1199 | | - int dump_ok; |
---|
1200 | | - |
---|
1201 | | - /* Do not dump I/O mapped devices or special mappings */ |
---|
1202 | | - if (vma->vm_flags & VM_IO) { |
---|
1203 | | - kdcore("%08lx: %08lx: no (IO)", vma->vm_start, vma->vm_flags); |
---|
1204 | | - return 0; |
---|
1205 | | - } |
---|
1206 | | - |
---|
1207 | | - /* If we may not read the contents, don't allow us to dump |
---|
1208 | | - * them either. "dump_write()" can't handle it anyway. |
---|
| 1194 | + struct elf_siginfo pr_info; /* Info associated with signal */ |
---|
| 1195 | + short pr_cursig; /* Current signal */ |
---|
| 1196 | + unsigned long pr_sigpend; /* Set of pending signals */ |
---|
| 1197 | + unsigned long pr_sighold; /* Set of held signals */ |
---|
| 1198 | + pid_t pr_pid; |
---|
| 1199 | + pid_t pr_ppid; |
---|
| 1200 | + pid_t pr_pgrp; |
---|
| 1201 | + pid_t pr_sid; |
---|
| 1202 | + struct __kernel_old_timeval pr_utime; /* User time */ |
---|
| 1203 | + struct __kernel_old_timeval pr_stime; /* System time */ |
---|
| 1204 | + struct __kernel_old_timeval pr_cutime; /* Cumulative user time */ |
---|
| 1205 | + struct __kernel_old_timeval pr_cstime; /* Cumulative system time */ |
---|
| 1206 | + elf_gregset_t pr_reg; /* GP registers */ |
---|
| 1207 | + /* When using FDPIC, the loadmap addresses need to be communicated |
---|
| 1208 | + * to GDB in order for GDB to do the necessary relocations. The |
---|
| 1209 | + * fields (below) used to communicate this information are placed |
---|
| 1210 | + * immediately after ``pr_reg'', so that the loadmap addresses may |
---|
| 1211 | + * be viewed as part of the register set if so desired. |
---|
1209 | 1212 | */ |
---|
1210 | | - if (!(vma->vm_flags & VM_READ)) { |
---|
1211 | | - kdcore("%08lx: %08lx: no (!read)", vma->vm_start, vma->vm_flags); |
---|
1212 | | - return 0; |
---|
1213 | | - } |
---|
1214 | | - |
---|
1215 | | - /* support for DAX */ |
---|
1216 | | - if (vma_is_dax(vma)) { |
---|
1217 | | - if (vma->vm_flags & VM_SHARED) { |
---|
1218 | | - dump_ok = test_bit(MMF_DUMP_DAX_SHARED, &mm_flags); |
---|
1219 | | - kdcore("%08lx: %08lx: %s (DAX shared)", vma->vm_start, |
---|
1220 | | - vma->vm_flags, dump_ok ? "yes" : "no"); |
---|
1221 | | - } else { |
---|
1222 | | - dump_ok = test_bit(MMF_DUMP_DAX_PRIVATE, &mm_flags); |
---|
1223 | | - kdcore("%08lx: %08lx: %s (DAX private)", vma->vm_start, |
---|
1224 | | - vma->vm_flags, dump_ok ? "yes" : "no"); |
---|
1225 | | - } |
---|
1226 | | - return dump_ok; |
---|
1227 | | - } |
---|
1228 | | - |
---|
1229 | | - /* By default, dump shared memory if mapped from an anonymous file. */ |
---|
1230 | | - if (vma->vm_flags & VM_SHARED) { |
---|
1231 | | - if (file_inode(vma->vm_file)->i_nlink == 0) { |
---|
1232 | | - dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); |
---|
1233 | | - kdcore("%08lx: %08lx: %s (share)", vma->vm_start, |
---|
1234 | | - vma->vm_flags, dump_ok ? "yes" : "no"); |
---|
1235 | | - return dump_ok; |
---|
1236 | | - } |
---|
1237 | | - |
---|
1238 | | - dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); |
---|
1239 | | - kdcore("%08lx: %08lx: %s (share)", vma->vm_start, |
---|
1240 | | - vma->vm_flags, dump_ok ? "yes" : "no"); |
---|
1241 | | - return dump_ok; |
---|
1242 | | - } |
---|
1243 | | - |
---|
1244 | | -#ifdef CONFIG_MMU |
---|
1245 | | - /* By default, if it hasn't been written to, don't write it out */ |
---|
1246 | | - if (!vma->anon_vma) { |
---|
1247 | | - dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); |
---|
1248 | | - kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start, |
---|
1249 | | - vma->vm_flags, dump_ok ? "yes" : "no"); |
---|
1250 | | - return dump_ok; |
---|
1251 | | - } |
---|
1252 | | -#endif |
---|
1253 | | - |
---|
1254 | | - dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); |
---|
1255 | | - kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags, |
---|
1256 | | - dump_ok ? "yes" : "no"); |
---|
1257 | | - return dump_ok; |
---|
1258 | | -} |
---|
| 1213 | + unsigned long pr_exec_fdpic_loadmap; |
---|
| 1214 | + unsigned long pr_interp_fdpic_loadmap; |
---|
| 1215 | + int pr_fpvalid; /* True if math co-processor being used. */ |
---|
| 1216 | +}; |
---|
1259 | 1217 | |
---|
1260 | 1218 | /* An ELF note in memory */ |
---|
1261 | 1219 | struct memelfnote |
---|
.. | .. |
---|
1343 | 1301 | * fill up all the fields in prstatus from the given task struct, except |
---|
1344 | 1302 | * registers which need to be filled up separately. |
---|
1345 | 1303 | */ |
---|
1346 | | -static void fill_prstatus(struct elf_prstatus *prstatus, |
---|
| 1304 | +static void fill_prstatus(struct elf_prstatus_fdpic *prstatus, |
---|
1347 | 1305 | struct task_struct *p, long signr) |
---|
1348 | 1306 | { |
---|
1349 | 1307 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
---|
.. | .. |
---|
1363 | 1321 | * group-wide total, not its individual thread total. |
---|
1364 | 1322 | */ |
---|
1365 | 1323 | thread_group_cputime(p, &cputime); |
---|
1366 | | - prstatus->pr_utime = ns_to_timeval(cputime.utime); |
---|
1367 | | - prstatus->pr_stime = ns_to_timeval(cputime.stime); |
---|
| 1324 | + prstatus->pr_utime = ns_to_kernel_old_timeval(cputime.utime); |
---|
| 1325 | + prstatus->pr_stime = ns_to_kernel_old_timeval(cputime.stime); |
---|
1368 | 1326 | } else { |
---|
1369 | 1327 | u64 utime, stime; |
---|
1370 | 1328 | |
---|
1371 | 1329 | task_cputime(p, &utime, &stime); |
---|
1372 | | - prstatus->pr_utime = ns_to_timeval(utime); |
---|
1373 | | - prstatus->pr_stime = ns_to_timeval(stime); |
---|
| 1330 | + prstatus->pr_utime = ns_to_kernel_old_timeval(utime); |
---|
| 1331 | + prstatus->pr_stime = ns_to_kernel_old_timeval(stime); |
---|
1374 | 1332 | } |
---|
1375 | | - prstatus->pr_cutime = ns_to_timeval(p->signal->cutime); |
---|
1376 | | - prstatus->pr_cstime = ns_to_timeval(p->signal->cstime); |
---|
| 1333 | + prstatus->pr_cutime = ns_to_kernel_old_timeval(p->signal->cutime); |
---|
| 1334 | + prstatus->pr_cstime = ns_to_kernel_old_timeval(p->signal->cstime); |
---|
1377 | 1335 | |
---|
1378 | 1336 | prstatus->pr_exec_fdpic_loadmap = p->mm->context.exec_fdpic_loadmap; |
---|
1379 | 1337 | prstatus->pr_interp_fdpic_loadmap = p->mm->context.interp_fdpic_loadmap; |
---|
.. | .. |
---|
1425 | 1383 | /* Here is the structure in which status of each thread is captured. */ |
---|
1426 | 1384 | struct elf_thread_status |
---|
1427 | 1385 | { |
---|
1428 | | - struct list_head list; |
---|
1429 | | - struct elf_prstatus prstatus; /* NT_PRSTATUS */ |
---|
| 1386 | + struct elf_thread_status *next; |
---|
| 1387 | + struct elf_prstatus_fdpic prstatus; /* NT_PRSTATUS */ |
---|
1430 | 1388 | elf_fpregset_t fpu; /* NT_PRFPREG */ |
---|
1431 | | - struct task_struct *thread; |
---|
1432 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1433 | | - elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ |
---|
1434 | | -#endif |
---|
1435 | | - struct memelfnote notes[3]; |
---|
| 1389 | + struct memelfnote notes[2]; |
---|
1436 | 1390 | int num_notes; |
---|
1437 | 1391 | }; |
---|
1438 | 1392 | |
---|
.. | .. |
---|
1441 | 1395 | * we need to keep a linked list of every thread's pr_status and then create |
---|
1442 | 1396 | * a single section for them in the final core file. |
---|
1443 | 1397 | */ |
---|
1444 | | -static int elf_dump_thread_status(long signr, struct elf_thread_status *t) |
---|
| 1398 | +static struct elf_thread_status *elf_dump_thread_status(long signr, struct task_struct *p, int *sz) |
---|
1445 | 1399 | { |
---|
1446 | | - struct task_struct *p = t->thread; |
---|
1447 | | - int sz = 0; |
---|
| 1400 | + const struct user_regset_view *view = task_user_regset_view(p); |
---|
| 1401 | + struct elf_thread_status *t; |
---|
| 1402 | + int i, ret; |
---|
1448 | 1403 | |
---|
1449 | | - t->num_notes = 0; |
---|
| 1404 | + t = kzalloc(sizeof(struct elf_thread_status), GFP_KERNEL); |
---|
| 1405 | + if (!t) |
---|
| 1406 | + return t; |
---|
1450 | 1407 | |
---|
1451 | 1408 | fill_prstatus(&t->prstatus, p, signr); |
---|
1452 | | - elf_core_copy_task_regs(p, &t->prstatus.pr_reg); |
---|
| 1409 | + regset_get(p, &view->regsets[0], |
---|
| 1410 | + sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); |
---|
1453 | 1411 | |
---|
1454 | 1412 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), |
---|
1455 | 1413 | &t->prstatus); |
---|
1456 | 1414 | t->num_notes++; |
---|
1457 | | - sz += notesize(&t->notes[0]); |
---|
| 1415 | + *sz += notesize(&t->notes[0]); |
---|
1458 | 1416 | |
---|
1459 | | - t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu); |
---|
| 1417 | + for (i = 1; i < view->n; ++i) { |
---|
| 1418 | + const struct user_regset *regset = &view->regsets[i]; |
---|
| 1419 | + if (regset->core_note_type != NT_PRFPREG) |
---|
| 1420 | + continue; |
---|
| 1421 | + if (regset->active && regset->active(p, regset) <= 0) |
---|
| 1422 | + continue; |
---|
| 1423 | + ret = regset_get(p, regset, sizeof(t->fpu), &t->fpu); |
---|
| 1424 | + if (ret >= 0) |
---|
| 1425 | + t->prstatus.pr_fpvalid = 1; |
---|
| 1426 | + break; |
---|
| 1427 | + } |
---|
| 1428 | + |
---|
1460 | 1429 | if (t->prstatus.pr_fpvalid) { |
---|
1461 | 1430 | fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), |
---|
1462 | 1431 | &t->fpu); |
---|
1463 | 1432 | t->num_notes++; |
---|
1464 | | - sz += notesize(&t->notes[1]); |
---|
| 1433 | + *sz += notesize(&t->notes[1]); |
---|
1465 | 1434 | } |
---|
1466 | | - |
---|
1467 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1468 | | - if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { |
---|
1469 | | - fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, |
---|
1470 | | - sizeof(t->xfpu), &t->xfpu); |
---|
1471 | | - t->num_notes++; |
---|
1472 | | - sz += notesize(&t->notes[2]); |
---|
1473 | | - } |
---|
1474 | | -#endif |
---|
1475 | | - return sz; |
---|
| 1435 | + return t; |
---|
1476 | 1436 | } |
---|
1477 | 1437 | |
---|
1478 | 1438 | static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, |
---|
.. | .. |
---|
1494 | 1454 | /* |
---|
1495 | 1455 | * dump the segments for an MMU process |
---|
1496 | 1456 | */ |
---|
1497 | | -static bool elf_fdpic_dump_segments(struct coredump_params *cprm) |
---|
| 1457 | +static bool elf_fdpic_dump_segments(struct coredump_params *cprm, |
---|
| 1458 | + struct core_vma_metadata *vma_meta, |
---|
| 1459 | + int vma_count) |
---|
1498 | 1460 | { |
---|
1499 | | - struct vm_area_struct *vma; |
---|
| 1461 | + int i; |
---|
1500 | 1462 | |
---|
1501 | | - for (vma = current->mm->mmap; vma; vma = vma->vm_next) { |
---|
1502 | | -#ifdef CONFIG_MMU |
---|
1503 | | - unsigned long addr; |
---|
1504 | | -#endif |
---|
| 1463 | + for (i = 0; i < vma_count; i++) { |
---|
| 1464 | + struct core_vma_metadata *meta = vma_meta + i; |
---|
1505 | 1465 | |
---|
1506 | | - if (!maydump(vma, cprm->mm_flags)) |
---|
1507 | | - continue; |
---|
1508 | | - |
---|
1509 | | -#ifdef CONFIG_MMU |
---|
1510 | | - for (addr = vma->vm_start; addr < vma->vm_end; |
---|
1511 | | - addr += PAGE_SIZE) { |
---|
1512 | | - bool res; |
---|
1513 | | - struct page *page = get_dump_page(addr); |
---|
1514 | | - if (page) { |
---|
1515 | | - void *kaddr = kmap(page); |
---|
1516 | | - res = dump_emit(cprm, kaddr, PAGE_SIZE); |
---|
1517 | | - kunmap(page); |
---|
1518 | | - put_page(page); |
---|
1519 | | - } else { |
---|
1520 | | - res = dump_skip(cprm, PAGE_SIZE); |
---|
1521 | | - } |
---|
1522 | | - if (!res) |
---|
1523 | | - return false; |
---|
1524 | | - } |
---|
1525 | | -#else |
---|
1526 | | - if (!dump_emit(cprm, (void *) vma->vm_start, |
---|
1527 | | - vma->vm_end - vma->vm_start)) |
---|
| 1466 | + if (!dump_user_range(cprm, meta->start, meta->dump_size)) |
---|
1528 | 1467 | return false; |
---|
1529 | | -#endif |
---|
1530 | 1468 | } |
---|
1531 | 1469 | return true; |
---|
1532 | | -} |
---|
1533 | | - |
---|
1534 | | -static size_t elf_core_vma_data_size(unsigned long mm_flags) |
---|
1535 | | -{ |
---|
1536 | | - struct vm_area_struct *vma; |
---|
1537 | | - size_t size = 0; |
---|
1538 | | - |
---|
1539 | | - for (vma = current->mm->mmap; vma; vma = vma->vm_next) |
---|
1540 | | - if (maydump(vma, mm_flags)) |
---|
1541 | | - size += vma->vm_end - vma->vm_start; |
---|
1542 | | - return size; |
---|
1543 | 1470 | } |
---|
1544 | 1471 | |
---|
1545 | 1472 | /* |
---|
.. | .. |
---|
1551 | 1478 | */ |
---|
1552 | 1479 | static int elf_fdpic_core_dump(struct coredump_params *cprm) |
---|
1553 | 1480 | { |
---|
1554 | | -#define NUM_NOTES 6 |
---|
1555 | 1481 | int has_dumped = 0; |
---|
1556 | | - mm_segment_t fs; |
---|
1557 | | - int segs; |
---|
| 1482 | + int vma_count, segs; |
---|
1558 | 1483 | int i; |
---|
1559 | | - struct vm_area_struct *vma; |
---|
1560 | 1484 | struct elfhdr *elf = NULL; |
---|
1561 | 1485 | loff_t offset = 0, dataoff; |
---|
1562 | | - int numnote; |
---|
1563 | | - struct memelfnote *notes = NULL; |
---|
1564 | | - struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ |
---|
| 1486 | + struct memelfnote psinfo_note, auxv_note; |
---|
1565 | 1487 | struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ |
---|
1566 | | - LIST_HEAD(thread_list); |
---|
1567 | | - struct list_head *t; |
---|
1568 | | - elf_fpregset_t *fpu = NULL; |
---|
1569 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1570 | | - elf_fpxregset_t *xfpu = NULL; |
---|
1571 | | -#endif |
---|
| 1488 | + struct elf_thread_status *thread_list = NULL; |
---|
1572 | 1489 | int thread_status_size = 0; |
---|
1573 | 1490 | elf_addr_t *auxv; |
---|
1574 | 1491 | struct elf_phdr *phdr4note = NULL; |
---|
.. | .. |
---|
1577 | 1494 | elf_addr_t e_shoff; |
---|
1578 | 1495 | struct core_thread *ct; |
---|
1579 | 1496 | struct elf_thread_status *tmp; |
---|
1580 | | - |
---|
1581 | | - /* |
---|
1582 | | - * We no longer stop all VM operations. |
---|
1583 | | - * |
---|
1584 | | - * This is because those proceses that could possibly change map_count |
---|
1585 | | - * or the mmap / vma pages are now blocked in do_exit on current |
---|
1586 | | - * finishing this core dump. |
---|
1587 | | - * |
---|
1588 | | - * Only ptrace can touch these memory addresses, but it doesn't change |
---|
1589 | | - * the map_count or the pages allocated. So no possibility of crashing |
---|
1590 | | - * exists while dumping the mm->vm_next areas to the core file. |
---|
1591 | | - */ |
---|
| 1497 | + struct core_vma_metadata *vma_meta = NULL; |
---|
| 1498 | + size_t vma_data_size; |
---|
1592 | 1499 | |
---|
1593 | 1500 | /* alloc memory for large data structures: too large to be on stack */ |
---|
1594 | 1501 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); |
---|
1595 | 1502 | if (!elf) |
---|
1596 | | - goto cleanup; |
---|
1597 | | - prstatus = kzalloc(sizeof(*prstatus), GFP_KERNEL); |
---|
1598 | | - if (!prstatus) |
---|
1599 | | - goto cleanup; |
---|
| 1503 | + goto end_coredump; |
---|
1600 | 1504 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); |
---|
1601 | 1505 | if (!psinfo) |
---|
1602 | | - goto cleanup; |
---|
1603 | | - notes = kmalloc_array(NUM_NOTES, sizeof(struct memelfnote), |
---|
1604 | | - GFP_KERNEL); |
---|
1605 | | - if (!notes) |
---|
1606 | | - goto cleanup; |
---|
1607 | | - fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); |
---|
1608 | | - if (!fpu) |
---|
1609 | | - goto cleanup; |
---|
1610 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1611 | | - xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL); |
---|
1612 | | - if (!xfpu) |
---|
1613 | | - goto cleanup; |
---|
1614 | | -#endif |
---|
| 1506 | + goto end_coredump; |
---|
| 1507 | + |
---|
| 1508 | + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) |
---|
| 1509 | + goto end_coredump; |
---|
1615 | 1510 | |
---|
1616 | 1511 | for (ct = current->mm->core_state->dumper.next; |
---|
1617 | 1512 | ct; ct = ct->next) { |
---|
1618 | | - tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
---|
| 1513 | + tmp = elf_dump_thread_status(cprm->siginfo->si_signo, |
---|
| 1514 | + ct->task, &thread_status_size); |
---|
1619 | 1515 | if (!tmp) |
---|
1620 | | - goto cleanup; |
---|
| 1516 | + goto end_coredump; |
---|
1621 | 1517 | |
---|
1622 | | - tmp->thread = ct->task; |
---|
1623 | | - list_add(&tmp->list, &thread_list); |
---|
1624 | | - } |
---|
1625 | | - |
---|
1626 | | - list_for_each(t, &thread_list) { |
---|
1627 | | - struct elf_thread_status *tmp; |
---|
1628 | | - int sz; |
---|
1629 | | - |
---|
1630 | | - tmp = list_entry(t, struct elf_thread_status, list); |
---|
1631 | | - sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); |
---|
1632 | | - thread_status_size += sz; |
---|
| 1518 | + tmp->next = thread_list; |
---|
| 1519 | + thread_list = tmp; |
---|
1633 | 1520 | } |
---|
1634 | 1521 | |
---|
1635 | 1522 | /* now collect the dump for the current */ |
---|
1636 | | - fill_prstatus(prstatus, current, cprm->siginfo->si_signo); |
---|
1637 | | - elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); |
---|
| 1523 | + tmp = elf_dump_thread_status(cprm->siginfo->si_signo, |
---|
| 1524 | + current, &thread_status_size); |
---|
| 1525 | + if (!tmp) |
---|
| 1526 | + goto end_coredump; |
---|
| 1527 | + tmp->next = thread_list; |
---|
| 1528 | + thread_list = tmp; |
---|
1638 | 1529 | |
---|
1639 | | - segs = current->mm->map_count; |
---|
1640 | | - segs += elf_core_extra_phdrs(); |
---|
| 1530 | + segs = vma_count + elf_core_extra_phdrs(); |
---|
1641 | 1531 | |
---|
1642 | 1532 | /* for notes section */ |
---|
1643 | 1533 | segs++; |
---|
.. | .. |
---|
1656 | 1546 | * with info from their /proc. |
---|
1657 | 1547 | */ |
---|
1658 | 1548 | |
---|
1659 | | - fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); |
---|
1660 | 1549 | fill_psinfo(psinfo, current->group_leader, current->mm); |
---|
1661 | | - fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); |
---|
1662 | | - |
---|
1663 | | - numnote = 2; |
---|
| 1550 | + fill_note(&psinfo_note, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); |
---|
| 1551 | + thread_status_size += notesize(&psinfo_note); |
---|
1664 | 1552 | |
---|
1665 | 1553 | auxv = (elf_addr_t *) current->mm->saved_auxv; |
---|
1666 | | - |
---|
1667 | 1554 | i = 0; |
---|
1668 | 1555 | do |
---|
1669 | 1556 | i += 2; |
---|
1670 | 1557 | while (auxv[i - 2] != AT_NULL); |
---|
1671 | | - fill_note(¬es[numnote++], "CORE", NT_AUXV, |
---|
1672 | | - i * sizeof(elf_addr_t), auxv); |
---|
| 1558 | + fill_note(&auxv_note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); |
---|
| 1559 | + thread_status_size += notesize(&auxv_note); |
---|
1673 | 1560 | |
---|
1674 | | - /* Try to dump the FPU. */ |
---|
1675 | | - if ((prstatus->pr_fpvalid = |
---|
1676 | | - elf_core_copy_task_fpregs(current, cprm->regs, fpu))) |
---|
1677 | | - fill_note(notes + numnote++, |
---|
1678 | | - "CORE", NT_PRFPREG, sizeof(*fpu), fpu); |
---|
1679 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1680 | | - if (elf_core_copy_task_xfpregs(current, xfpu)) |
---|
1681 | | - fill_note(notes + numnote++, |
---|
1682 | | - "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); |
---|
1683 | | -#endif |
---|
1684 | | - |
---|
1685 | | - fs = get_fs(); |
---|
1686 | | - set_fs(KERNEL_DS); |
---|
1687 | | - |
---|
1688 | | - offset += sizeof(*elf); /* Elf header */ |
---|
| 1561 | + offset = sizeof(*elf); /* Elf header */ |
---|
1689 | 1562 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
---|
1690 | 1563 | |
---|
1691 | 1564 | /* Write notes phdr entry */ |
---|
1692 | | - { |
---|
1693 | | - int sz = 0; |
---|
| 1565 | + phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); |
---|
| 1566 | + if (!phdr4note) |
---|
| 1567 | + goto end_coredump; |
---|
1694 | 1568 | |
---|
1695 | | - for (i = 0; i < numnote; i++) |
---|
1696 | | - sz += notesize(notes + i); |
---|
1697 | | - |
---|
1698 | | - sz += thread_status_size; |
---|
1699 | | - |
---|
1700 | | - phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); |
---|
1701 | | - if (!phdr4note) |
---|
1702 | | - goto end_coredump; |
---|
1703 | | - |
---|
1704 | | - fill_elf_note_phdr(phdr4note, sz, offset); |
---|
1705 | | - offset += sz; |
---|
1706 | | - } |
---|
| 1569 | + fill_elf_note_phdr(phdr4note, thread_status_size, offset); |
---|
| 1570 | + offset += thread_status_size; |
---|
1707 | 1571 | |
---|
1708 | 1572 | /* Page-align dumped data */ |
---|
1709 | 1573 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
---|
1710 | 1574 | |
---|
1711 | | - offset += elf_core_vma_data_size(cprm->mm_flags); |
---|
| 1575 | + offset += vma_data_size; |
---|
1712 | 1576 | offset += elf_core_extra_data_size(); |
---|
1713 | 1577 | e_shoff = offset; |
---|
1714 | 1578 | |
---|
.. | .. |
---|
1728 | 1592 | goto end_coredump; |
---|
1729 | 1593 | |
---|
1730 | 1594 | /* write program headers for segments dump */ |
---|
1731 | | - for (vma = current->mm->mmap; vma; vma = vma->vm_next) { |
---|
| 1595 | + for (i = 0; i < vma_count; i++) { |
---|
| 1596 | + struct core_vma_metadata *meta = vma_meta + i; |
---|
1732 | 1597 | struct elf_phdr phdr; |
---|
1733 | 1598 | size_t sz; |
---|
1734 | 1599 | |
---|
1735 | | - sz = vma->vm_end - vma->vm_start; |
---|
| 1600 | + sz = meta->end - meta->start; |
---|
1736 | 1601 | |
---|
1737 | 1602 | phdr.p_type = PT_LOAD; |
---|
1738 | 1603 | phdr.p_offset = offset; |
---|
1739 | | - phdr.p_vaddr = vma->vm_start; |
---|
| 1604 | + phdr.p_vaddr = meta->start; |
---|
1740 | 1605 | phdr.p_paddr = 0; |
---|
1741 | | - phdr.p_filesz = maydump(vma, cprm->mm_flags) ? sz : 0; |
---|
| 1606 | + phdr.p_filesz = meta->dump_size; |
---|
1742 | 1607 | phdr.p_memsz = sz; |
---|
1743 | 1608 | offset += phdr.p_filesz; |
---|
1744 | | - phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
---|
1745 | | - if (vma->vm_flags & VM_WRITE) |
---|
| 1609 | + phdr.p_flags = 0; |
---|
| 1610 | + if (meta->flags & VM_READ) |
---|
| 1611 | + phdr.p_flags |= PF_R; |
---|
| 1612 | + if (meta->flags & VM_WRITE) |
---|
1746 | 1613 | phdr.p_flags |= PF_W; |
---|
1747 | | - if (vma->vm_flags & VM_EXEC) |
---|
| 1614 | + if (meta->flags & VM_EXEC) |
---|
1748 | 1615 | phdr.p_flags |= PF_X; |
---|
1749 | 1616 | phdr.p_align = ELF_EXEC_PAGESIZE; |
---|
1750 | 1617 | |
---|
.. | .. |
---|
1756 | 1623 | goto end_coredump; |
---|
1757 | 1624 | |
---|
1758 | 1625 | /* write out the notes section */ |
---|
1759 | | - for (i = 0; i < numnote; i++) |
---|
1760 | | - if (!writenote(notes + i, cprm)) |
---|
| 1626 | + if (!writenote(thread_list->notes, cprm)) |
---|
| 1627 | + goto end_coredump; |
---|
| 1628 | + if (!writenote(&psinfo_note, cprm)) |
---|
| 1629 | + goto end_coredump; |
---|
| 1630 | + if (!writenote(&auxv_note, cprm)) |
---|
| 1631 | + goto end_coredump; |
---|
| 1632 | + for (i = 1; i < thread_list->num_notes; i++) |
---|
| 1633 | + if (!writenote(thread_list->notes + i, cprm)) |
---|
1761 | 1634 | goto end_coredump; |
---|
1762 | 1635 | |
---|
1763 | 1636 | /* write out the thread status notes section */ |
---|
1764 | | - list_for_each(t, &thread_list) { |
---|
1765 | | - struct elf_thread_status *tmp = |
---|
1766 | | - list_entry(t, struct elf_thread_status, list); |
---|
1767 | | - |
---|
| 1637 | + for (tmp = thread_list->next; tmp; tmp = tmp->next) { |
---|
1768 | 1638 | for (i = 0; i < tmp->num_notes; i++) |
---|
1769 | 1639 | if (!writenote(&tmp->notes[i], cprm)) |
---|
1770 | 1640 | goto end_coredump; |
---|
.. | .. |
---|
1773 | 1643 | if (!dump_skip(cprm, dataoff - cprm->pos)) |
---|
1774 | 1644 | goto end_coredump; |
---|
1775 | 1645 | |
---|
1776 | | - if (!elf_fdpic_dump_segments(cprm)) |
---|
| 1646 | + if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count)) |
---|
1777 | 1647 | goto end_coredump; |
---|
1778 | 1648 | |
---|
1779 | 1649 | if (!elf_core_write_extra_data(cprm)) |
---|
.. | .. |
---|
1792 | 1662 | } |
---|
1793 | 1663 | |
---|
1794 | 1664 | end_coredump: |
---|
1795 | | - set_fs(fs); |
---|
1796 | | - |
---|
1797 | | -cleanup: |
---|
1798 | | - while (!list_empty(&thread_list)) { |
---|
1799 | | - struct list_head *tmp = thread_list.next; |
---|
1800 | | - list_del(tmp); |
---|
1801 | | - kfree(list_entry(tmp, struct elf_thread_status, list)); |
---|
| 1665 | + while (thread_list) { |
---|
| 1666 | + tmp = thread_list; |
---|
| 1667 | + thread_list = thread_list->next; |
---|
| 1668 | + kfree(tmp); |
---|
1802 | 1669 | } |
---|
| 1670 | + kvfree(vma_meta); |
---|
1803 | 1671 | kfree(phdr4note); |
---|
1804 | 1672 | kfree(elf); |
---|
1805 | | - kfree(prstatus); |
---|
1806 | 1673 | kfree(psinfo); |
---|
1807 | | - kfree(notes); |
---|
1808 | | - kfree(fpu); |
---|
1809 | 1674 | kfree(shdr4extnum); |
---|
1810 | | -#ifdef ELF_CORE_COPY_XFPREGS |
---|
1811 | | - kfree(xfpu); |
---|
1812 | | -#endif |
---|
1813 | 1675 | return has_dumped; |
---|
1814 | | -#undef NUM_NOTES |
---|
1815 | 1676 | } |
---|
1816 | 1677 | |
---|
1817 | 1678 | #endif /* CONFIG_ELF_CORE */ |
---|