1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/buildid.h> 4 #include <linux/cache.h> 5 #include <linux/elf.h> 6 #include <linux/kernel.h> 7 #include <linux/pagemap.h> 8 9 #define BUILD_ID 3 10 11 /* 12 * Parse build id from the note segment. This logic can be shared between 13 * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are 14 * identical. 15 */ 16 static int parse_build_id_buf(unsigned char *build_id, 17 __u32 *size, 18 const void *note_start, 19 Elf32_Word note_size) 20 { 21 Elf32_Word note_offs = 0, new_offs; 22 23 while (note_offs + sizeof(Elf32_Nhdr) < note_size) { 24 Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs); 25 26 if (nhdr->n_type == BUILD_ID && 27 nhdr->n_namesz == sizeof("GNU") && 28 !strcmp((char *)(nhdr + 1), "GNU") && 29 nhdr->n_descsz > 0 && 30 nhdr->n_descsz <= BUILD_ID_SIZE_MAX) { 31 memcpy(build_id, 32 note_start + note_offs + 33 ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), 34 nhdr->n_descsz); 35 memset(build_id + nhdr->n_descsz, 0, 36 BUILD_ID_SIZE_MAX - nhdr->n_descsz); 37 if (size) 38 *size = nhdr->n_descsz; 39 return 0; 40 } 41 new_offs = note_offs + sizeof(Elf32_Nhdr) + 42 ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4); 43 if (new_offs <= note_offs) /* overflow */ 44 break; 45 note_offs = new_offs; 46 } 47 48 return -EINVAL; 49 } 50 51 static inline int parse_build_id(const void *page_addr, 52 unsigned char *build_id, 53 __u32 *size, 54 const void *note_start, 55 Elf32_Word note_size) 56 { 57 /* check for overflow */ 58 if (note_start < page_addr || note_start + note_size < note_start) 59 return -EINVAL; 60 61 /* only supports note that fits in the first page */ 62 if (note_start + note_size > page_addr + PAGE_SIZE) 63 return -EINVAL; 64 65 return parse_build_id_buf(build_id, size, note_start, note_size); 66 } 67 68 /* Parse build ID from 32-bit ELF */ 69 static int get_build_id_32(const void *page_addr, unsigned char *build_id, 70 __u32 *size) 71 { 72 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr; 73 Elf32_Phdr *phdr; 74 int i; 75 76 /* 77 * FIXME 78 * Neither ELF spec nor ELF loader require that program headers 79 * start immediately after ELF header. 80 */ 81 if (ehdr->e_phoff != sizeof(Elf32_Ehdr)) 82 return -EINVAL; 83 /* only supports phdr that fits in one page */ 84 if (ehdr->e_phnum > 85 (PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr)) 86 return -EINVAL; 87 88 phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr)); 89 90 for (i = 0; i < ehdr->e_phnum; ++i) { 91 if (phdr[i].p_type == PT_NOTE && 92 !parse_build_id(page_addr, build_id, size, 93 page_addr + phdr[i].p_offset, 94 phdr[i].p_filesz)) 95 return 0; 96 } 97 return -EINVAL; 98 } 99 100 /* Parse build ID from 64-bit ELF */ 101 static int get_build_id_64(const void *page_addr, unsigned char *build_id, 102 __u32 *size) 103 { 104 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr; 105 Elf64_Phdr *phdr; 106 int i; 107 108 /* 109 * FIXME 110 * Neither ELF spec nor ELF loader require that program headers 111 * start immediately after ELF header. 112 */ 113 if (ehdr->e_phoff != sizeof(Elf64_Ehdr)) 114 return -EINVAL; 115 /* only supports phdr that fits in one page */ 116 if (ehdr->e_phnum > 117 (PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr)) 118 return -EINVAL; 119 120 phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_Ehdr)); 121 122 for (i = 0; i < ehdr->e_phnum; ++i) { 123 if (phdr[i].p_type == PT_NOTE && 124 !parse_build_id(page_addr, build_id, size, 125 page_addr + phdr[i].p_offset, 126 phdr[i].p_filesz)) 127 return 0; 128 } 129 return -EINVAL; 130 } 131 132 /* 133 * Parse build ID of ELF file mapped to vma 134 * @vma: vma object 135 * @build_id: buffer to store build id, at least BUILD_ID_SIZE long 136 * @size: returns actual build id size in case of success 137 * 138 * Return: 0 on success, -EINVAL otherwise 139 */ 140 int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id, 141 __u32 *size) 142 { 143 Elf32_Ehdr *ehdr; 144 struct page *page; 145 void *page_addr; 146 int ret; 147 148 /* only works for page backed storage */ 149 if (!vma->vm_file) 150 return -EINVAL; 151 152 page = find_get_page(vma->vm_file->f_mapping, 0); 153 if (!page) 154 return -EFAULT; /* page not mapped */ 155 156 ret = -EINVAL; 157 page_addr = kmap_local_page(page); 158 ehdr = (Elf32_Ehdr *)page_addr; 159 160 /* compare magic x7f "ELF" */ 161 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) 162 goto out; 163 164 /* only support executable file and shared object file */ 165 if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) 166 goto out; 167 168 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) 169 ret = get_build_id_32(page_addr, build_id, size); 170 else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) 171 ret = get_build_id_64(page_addr, build_id, size); 172 out: 173 kunmap_local(page_addr); 174 put_page(page); 175 return ret; 176 } 177 178 /** 179 * build_id_parse_buf - Get build ID from a buffer 180 * @buf: ELF note section(s) to parse 181 * @buf_size: Size of @buf in bytes 182 * @build_id: Build ID parsed from @buf, at least BUILD_ID_SIZE_MAX long 183 * 184 * Return: 0 on success, -EINVAL otherwise 185 */ 186 int build_id_parse_buf(const void *buf, unsigned char *build_id, u32 buf_size) 187 { 188 return parse_build_id_buf(build_id, NULL, buf, buf_size); 189 } 190 191 #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) || IS_ENABLED(CONFIG_VMCORE_INFO) 192 unsigned char vmlinux_build_id[BUILD_ID_SIZE_MAX] __ro_after_init; 193 194 /** 195 * init_vmlinux_build_id - Compute and stash the running kernel's build ID 196 */ 197 void __init init_vmlinux_build_id(void) 198 { 199 extern const void __start_notes; 200 extern const void __stop_notes; 201 unsigned int size = &__stop_notes - &__start_notes; 202 203 build_id_parse_buf(&__start_notes, vmlinux_build_id, size); 204 } 205 #endif 206