1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/buildid.h>
4 #include <linux/cache.h>
6 #include <linux/kernel.h>
7 #include <linux/pagemap.h>
8 #include <linux/secretmem.h>
12 #define MAX_PHDR_CNT 256
33 static void freader_init_from_file(struct freader
*r
, void *buf
, u32 buf_sz
,
34 struct file
*file
, bool may_fault
)
36 memset(r
, 0, sizeof(*r
));
40 r
->may_fault
= may_fault
;
43 static void freader_init_from_mem(struct freader
*r
, const char *data
, u64 data_sz
)
45 memset(r
, 0, sizeof(*r
));
50 static void freader_put_folio(struct freader
*r
)
54 kunmap_local(r
->addr
);
59 static int freader_get_folio(struct freader
*r
, loff_t file_off
)
61 /* check if we can just reuse current folio */
62 if (r
->folio
&& file_off
>= r
->folio_off
&&
63 file_off
< r
->folio_off
+ folio_size(r
->folio
))
68 /* reject secretmem folios created with memfd_secret() */
69 if (secretmem_mapping(r
->file
->f_mapping
))
72 r
->folio
= filemap_get_folio(r
->file
->f_mapping
, file_off
>> PAGE_SHIFT
);
74 /* if sleeping is allowed, wait for the page, if necessary */
75 if (r
->may_fault
&& (IS_ERR(r
->folio
) || !folio_test_uptodate(r
->folio
))) {
76 filemap_invalidate_lock_shared(r
->file
->f_mapping
);
77 r
->folio
= read_cache_folio(r
->file
->f_mapping
, file_off
>> PAGE_SHIFT
,
79 filemap_invalidate_unlock_shared(r
->file
->f_mapping
);
82 if (IS_ERR(r
->folio
) || !folio_test_uptodate(r
->folio
)) {
83 if (!IS_ERR(r
->folio
))
89 r
->folio_off
= folio_pos(r
->folio
);
90 r
->addr
= kmap_local_folio(r
->folio
, 0);
95 static const void *freader_fetch(struct freader
*r
, loff_t file_off
, size_t sz
)
99 /* provided internal temporary buffer should be sized correctly */
100 if (WARN_ON(r
->buf
&& sz
> r
->buf_sz
)) {
105 if (unlikely(file_off
+ sz
< file_off
)) {
110 /* working with memory buffer is much more straightforward */
112 if (file_off
+ sz
> r
->data_sz
) {
116 return r
->data
+ file_off
;
119 /* fetch or reuse folio for given file offset */
120 r
->err
= freader_get_folio(r
, file_off
);
124 /* if requested data is crossing folio boundaries, we have to copy
125 * everything into our local buffer to keep a simple linear memory
128 folio_sz
= folio_size(r
->folio
);
129 if (file_off
+ sz
> r
->folio_off
+ folio_sz
) {
130 int part_sz
= r
->folio_off
+ folio_sz
- file_off
;
132 /* copy the part that resides in the current folio */
133 memcpy(r
->buf
, r
->addr
+ (file_off
- r
->folio_off
), part_sz
);
135 /* fetch next folio */
136 r
->err
= freader_get_folio(r
, r
->folio_off
+ folio_sz
);
140 /* copy the rest of requested data */
141 memcpy(r
->buf
+ part_sz
, r
->addr
, sz
- part_sz
);
146 /* if data fits in a single folio, just return direct pointer */
147 return r
->addr
+ (file_off
- r
->folio_off
);
150 static void freader_cleanup(struct freader
*r
)
153 return; /* non-file-backed mode */
155 freader_put_folio(r
);
159 * Parse build id from the note segment. This logic can be shared between
160 * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
163 static int parse_build_id(struct freader
*r
, unsigned char *build_id
, __u32
*size
,
164 loff_t note_off
, Elf32_Word note_size
)
166 const char note_name
[] = "GNU";
167 const size_t note_name_sz
= sizeof(note_name
);
168 u32 build_id_off
, new_off
, note_end
, name_sz
, desc_sz
;
169 const Elf32_Nhdr
*nhdr
;
172 if (check_add_overflow(note_off
, note_size
, ¬e_end
))
175 while (note_end
- note_off
> sizeof(Elf32_Nhdr
) + note_name_sz
) {
176 nhdr
= freader_fetch(r
, note_off
, sizeof(Elf32_Nhdr
) + note_name_sz
);
180 name_sz
= READ_ONCE(nhdr
->n_namesz
);
181 desc_sz
= READ_ONCE(nhdr
->n_descsz
);
183 new_off
= note_off
+ sizeof(Elf32_Nhdr
);
184 if (check_add_overflow(new_off
, ALIGN(name_sz
, 4), &new_off
) ||
185 check_add_overflow(new_off
, ALIGN(desc_sz
, 4), &new_off
) ||
189 if (nhdr
->n_type
== BUILD_ID
&&
190 name_sz
== note_name_sz
&&
191 memcmp(nhdr
+ 1, note_name
, note_name_sz
) == 0 &&
192 desc_sz
> 0 && desc_sz
<= BUILD_ID_SIZE_MAX
) {
193 build_id_off
= note_off
+ sizeof(Elf32_Nhdr
) + ALIGN(note_name_sz
, 4);
195 /* freader_fetch() will invalidate nhdr pointer */
196 data
= freader_fetch(r
, build_id_off
, desc_sz
);
200 memcpy(build_id
, data
, desc_sz
);
201 memset(build_id
+ desc_sz
, 0, BUILD_ID_SIZE_MAX
- desc_sz
);
213 /* Parse build ID from 32-bit ELF */
214 static int get_build_id_32(struct freader
*r
, unsigned char *build_id
, __u32
*size
)
216 const Elf32_Ehdr
*ehdr
;
217 const Elf32_Phdr
*phdr
;
218 __u32 phnum
, phoff
, i
;
220 ehdr
= freader_fetch(r
, 0, sizeof(Elf32_Ehdr
));
224 /* subsequent freader_fetch() calls invalidate pointers, so remember locally */
225 phnum
= READ_ONCE(ehdr
->e_phnum
);
226 phoff
= READ_ONCE(ehdr
->e_phoff
);
228 /* set upper bound on amount of segments (phdrs) we iterate */
229 if (phnum
> MAX_PHDR_CNT
)
230 phnum
= MAX_PHDR_CNT
;
232 /* check that phoff is not large enough to cause an overflow */
233 if (phoff
+ phnum
* sizeof(Elf32_Phdr
) < phoff
)
236 for (i
= 0; i
< phnum
; ++i
) {
237 phdr
= freader_fetch(r
, phoff
+ i
* sizeof(Elf32_Phdr
), sizeof(Elf32_Phdr
));
241 if (phdr
->p_type
== PT_NOTE
&&
242 !parse_build_id(r
, build_id
, size
, READ_ONCE(phdr
->p_offset
),
243 READ_ONCE(phdr
->p_filesz
)))
249 /* Parse build ID from 64-bit ELF */
250 static int get_build_id_64(struct freader
*r
, unsigned char *build_id
, __u32
*size
)
252 const Elf64_Ehdr
*ehdr
;
253 const Elf64_Phdr
*phdr
;
257 ehdr
= freader_fetch(r
, 0, sizeof(Elf64_Ehdr
));
261 /* subsequent freader_fetch() calls invalidate pointers, so remember locally */
262 phnum
= READ_ONCE(ehdr
->e_phnum
);
263 phoff
= READ_ONCE(ehdr
->e_phoff
);
265 /* set upper bound on amount of segments (phdrs) we iterate */
266 if (phnum
> MAX_PHDR_CNT
)
267 phnum
= MAX_PHDR_CNT
;
269 /* check that phoff is not large enough to cause an overflow */
270 if (phoff
+ phnum
* sizeof(Elf64_Phdr
) < phoff
)
273 for (i
= 0; i
< phnum
; ++i
) {
274 phdr
= freader_fetch(r
, phoff
+ i
* sizeof(Elf64_Phdr
), sizeof(Elf64_Phdr
));
278 if (phdr
->p_type
== PT_NOTE
&&
279 !parse_build_id(r
, build_id
, size
, READ_ONCE(phdr
->p_offset
),
280 READ_ONCE(phdr
->p_filesz
)))
287 /* enough for Elf64_Ehdr, Elf64_Phdr, and all the smaller requests */
288 #define MAX_FREADER_BUF_SZ 64
290 static int __build_id_parse(struct vm_area_struct
*vma
, unsigned char *build_id
,
291 __u32
*size
, bool may_fault
)
293 const Elf32_Ehdr
*ehdr
;
295 char buf
[MAX_FREADER_BUF_SZ
];
298 /* only works for page backed storage */
302 freader_init_from_file(&r
, buf
, sizeof(buf
), vma
->vm_file
, may_fault
);
304 /* fetch first 18 bytes of ELF header for checks */
305 ehdr
= freader_fetch(&r
, 0, offsetofend(Elf32_Ehdr
, e_type
));
313 /* compare magic x7f "ELF" */
314 if (memcmp(ehdr
->e_ident
, ELFMAG
, SELFMAG
) != 0)
317 /* only support executable file and shared object file */
318 if (ehdr
->e_type
!= ET_EXEC
&& ehdr
->e_type
!= ET_DYN
)
321 if (ehdr
->e_ident
[EI_CLASS
] == ELFCLASS32
)
322 ret
= get_build_id_32(&r
, build_id
, size
);
323 else if (ehdr
->e_ident
[EI_CLASS
] == ELFCLASS64
)
324 ret
= get_build_id_64(&r
, build_id
, size
);
331 * Parse build ID of ELF file mapped to vma
333 * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
334 * @size: returns actual build id size in case of success
336 * Assumes no page fault can be taken, so if relevant portions of ELF file are
337 * not already paged in, fetching of build ID fails.
339 * Return: 0 on success; negative error, otherwise
341 int build_id_parse_nofault(struct vm_area_struct
*vma
, unsigned char *build_id
, __u32
*size
)
343 return __build_id_parse(vma
, build_id
, size
, false /* !may_fault */);
347 * Parse build ID of ELF file mapped to VMA
349 * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
350 * @size: returns actual build id size in case of success
352 * Assumes faultable context and can cause page faults to bring in file data
355 * Return: 0 on success; negative error, otherwise
357 int build_id_parse(struct vm_area_struct
*vma
, unsigned char *build_id
, __u32
*size
)
359 return __build_id_parse(vma
, build_id
, size
, true /* may_fault */);
363 * build_id_parse_buf - Get build ID from a buffer
364 * @buf: ELF note section(s) to parse
365 * @buf_size: Size of @buf in bytes
366 * @build_id: Build ID parsed from @buf, at least BUILD_ID_SIZE_MAX long
368 * Return: 0 on success, -EINVAL otherwise
370 int build_id_parse_buf(const void *buf
, unsigned char *build_id
, u32 buf_size
)
375 freader_init_from_mem(&r
, buf
, buf_size
);
377 err
= parse_build_id(&r
, build_id
, NULL
, 0, buf_size
);
383 #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) || IS_ENABLED(CONFIG_VMCORE_INFO)
384 unsigned char vmlinux_build_id
[BUILD_ID_SIZE_MAX
] __ro_after_init
;
387 * init_vmlinux_build_id - Compute and stash the running kernel's build ID
389 void __init
init_vmlinux_build_id(void)
391 extern const void __start_notes
;
392 extern const void __stop_notes
;
393 unsigned int size
= &__stop_notes
- &__start_notes
;
395 build_id_parse_buf(&__start_notes
, vmlinux_build_id
, size
);