elfcore.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/coredump.h>
  3. #include <linux/elfcore.h>
  4. #include <linux/kernel.h>
  5. #include <linux/mm.h>
  6. #include <asm/cpufeature.h>
  7. #include <asm/mte.h>
  8. #define for_each_mte_vma(cprm, i, m) \
  9. if (system_supports_mte()) \
  10. for (i = 0, m = cprm->vma_meta; \
  11. i < cprm->vma_count; \
  12. i++, m = cprm->vma_meta + i) \
  13. if (m->flags & VM_MTE)
  14. static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m)
  15. {
  16. return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE;
  17. }
  18. /* Derived from dump_user_range(); start/end must be page-aligned */
  19. static int mte_dump_tag_range(struct coredump_params *cprm,
  20. unsigned long start, unsigned long len)
  21. {
  22. int ret = 1;
  23. unsigned long addr;
  24. void *tags = NULL;
  25. for (addr = start; addr < start + len; addr += PAGE_SIZE) {
  26. struct page *page = get_dump_page(addr);
  27. /*
  28. * get_dump_page() returns NULL when encountering an empty
  29. * page table entry that would otherwise have been filled with
  30. * the zero page. Skip the equivalent tag dump which would
  31. * have been all zeros.
  32. */
  33. if (!page) {
  34. dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
  35. continue;
  36. }
  37. /*
  38. * Pages mapped in user space as !pte_access_permitted() (e.g.
  39. * PROT_EXEC only) may not have the PG_mte_tagged flag set.
  40. */
  41. if (!page_mte_tagged(page)) {
  42. put_page(page);
  43. dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
  44. continue;
  45. }
  46. if (!tags) {
  47. tags = mte_allocate_tag_storage();
  48. if (!tags) {
  49. put_page(page);
  50. ret = 0;
  51. break;
  52. }
  53. }
  54. mte_save_page_tags(page_address(page), tags);
  55. put_page(page);
  56. if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
  57. ret = 0;
  58. break;
  59. }
  60. }
  61. if (tags)
  62. mte_free_tag_storage(tags);
  63. return ret;
  64. }
  65. Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
  66. {
  67. int i;
  68. struct core_vma_metadata *m;
  69. int vma_count = 0;
  70. for_each_mte_vma(cprm, i, m)
  71. vma_count++;
  72. return vma_count;
  73. }
  74. int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
  75. {
  76. int i;
  77. struct core_vma_metadata *m;
  78. for_each_mte_vma(cprm, i, m) {
  79. struct elf_phdr phdr;
  80. phdr.p_type = PT_AARCH64_MEMTAG_MTE;
  81. phdr.p_offset = offset;
  82. phdr.p_vaddr = m->start;
  83. phdr.p_paddr = 0;
  84. phdr.p_filesz = mte_vma_tag_dump_size(m);
  85. phdr.p_memsz = m->end - m->start;
  86. offset += phdr.p_filesz;
  87. phdr.p_flags = 0;
  88. phdr.p_align = 0;
  89. if (!dump_emit(cprm, &phdr, sizeof(phdr)))
  90. return 0;
  91. }
  92. return 1;
  93. }
  94. size_t elf_core_extra_data_size(struct coredump_params *cprm)
  95. {
  96. int i;
  97. struct core_vma_metadata *m;
  98. size_t data_size = 0;
  99. for_each_mte_vma(cprm, i, m)
  100. data_size += mte_vma_tag_dump_size(m);
  101. return data_size;
  102. }
  103. int elf_core_write_extra_data(struct coredump_params *cprm)
  104. {
  105. int i;
  106. struct core_vma_metadata *m;
  107. for_each_mte_vma(cprm, i, m) {
  108. if (!mte_dump_tag_range(cprm, m->start, m->dump_size))
  109. return 0;
  110. }
  111. return 1;
  112. }