-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bpf: Move stack_map_get_build_id into lib
Moving stack_map_get_build_id into lib with declaration in linux/buildid.h header: int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id); This function returns build id for given struct vm_area_struct. There is no functional change to stack_map_get_build_id function. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Song Liu <songliubraving@fb.com> Link: https://lore.kernel.org/bpf/20210114134044.1418404-2-jolsa@kernel.org
- Loading branch information
Jiri Olsa
authored and
Alexei Starovoitov
committed
Jan 15, 2021
1 parent
7064a73
commit bd7525d
Showing
4 changed files
with
153 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
#ifndef _LINUX_BUILDID_H | ||
#define _LINUX_BUILDID_H | ||
|
||
#include <linux/mm_types.h> | ||
|
||
#define BUILD_ID_SIZE_MAX 20 | ||
|
||
int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
#include <linux/buildid.h> | ||
#include <linux/elf.h> | ||
#include <linux/pagemap.h> | ||
|
||
#define BUILD_ID 3 | ||
/* | ||
* Parse build id from the note segment. This logic can be shared between | ||
* 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are | ||
* identical. | ||
*/ | ||
static inline int parse_build_id(void *page_addr, | ||
unsigned char *build_id, | ||
void *note_start, | ||
Elf32_Word note_size) | ||
{ | ||
Elf32_Word note_offs = 0, new_offs; | ||
|
||
/* check for overflow */ | ||
if (note_start < page_addr || note_start + note_size < note_start) | ||
return -EINVAL; | ||
|
||
/* only supports note that fits in the first page */ | ||
if (note_start + note_size > page_addr + PAGE_SIZE) | ||
return -EINVAL; | ||
|
||
while (note_offs + sizeof(Elf32_Nhdr) < note_size) { | ||
Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs); | ||
|
||
if (nhdr->n_type == BUILD_ID && | ||
nhdr->n_namesz == sizeof("GNU") && | ||
nhdr->n_descsz > 0 && | ||
nhdr->n_descsz <= BUILD_ID_SIZE_MAX) { | ||
memcpy(build_id, | ||
note_start + note_offs + | ||
ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), | ||
nhdr->n_descsz); | ||
memset(build_id + nhdr->n_descsz, 0, | ||
BUILD_ID_SIZE_MAX - nhdr->n_descsz); | ||
return 0; | ||
} | ||
new_offs = note_offs + sizeof(Elf32_Nhdr) + | ||
ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4); | ||
if (new_offs <= note_offs) /* overflow */ | ||
break; | ||
note_offs = new_offs; | ||
} | ||
return -EINVAL; | ||
} | ||
|
||
/* Parse build ID from 32-bit ELF */ | ||
static int get_build_id_32(void *page_addr, unsigned char *build_id) | ||
{ | ||
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr; | ||
Elf32_Phdr *phdr; | ||
int i; | ||
|
||
/* only supports phdr that fits in one page */ | ||
if (ehdr->e_phnum > | ||
(PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr)) | ||
return -EINVAL; | ||
|
||
phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr)); | ||
|
||
for (i = 0; i < ehdr->e_phnum; ++i) { | ||
if (phdr[i].p_type == PT_NOTE && | ||
!parse_build_id(page_addr, build_id, | ||
page_addr + phdr[i].p_offset, | ||
phdr[i].p_filesz)) | ||
return 0; | ||
} | ||
return -EINVAL; | ||
} | ||
|
||
/* Parse build ID from 64-bit ELF */ | ||
static int get_build_id_64(void *page_addr, unsigned char *build_id) | ||
{ | ||
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr; | ||
Elf64_Phdr *phdr; | ||
int i; | ||
|
||
/* only supports phdr that fits in one page */ | ||
if (ehdr->e_phnum > | ||
(PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr)) | ||
return -EINVAL; | ||
|
||
phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_Ehdr)); | ||
|
||
for (i = 0; i < ehdr->e_phnum; ++i) { | ||
if (phdr[i].p_type == PT_NOTE && | ||
!parse_build_id(page_addr, build_id, | ||
page_addr + phdr[i].p_offset, | ||
phdr[i].p_filesz)) | ||
return 0; | ||
} | ||
return -EINVAL; | ||
} | ||
|
||
/* Parse build ID of ELF file mapped to vma */ | ||
int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id) | ||
{ | ||
Elf32_Ehdr *ehdr; | ||
struct page *page; | ||
void *page_addr; | ||
int ret; | ||
|
||
/* only works for page backed storage */ | ||
if (!vma->vm_file) | ||
return -EINVAL; | ||
|
||
page = find_get_page(vma->vm_file->f_mapping, 0); | ||
if (!page) | ||
return -EFAULT; /* page not mapped */ | ||
|
||
ret = -EINVAL; | ||
page_addr = kmap_atomic(page); | ||
ehdr = (Elf32_Ehdr *)page_addr; | ||
|
||
/* compare magic x7f "ELF" */ | ||
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) | ||
goto out; | ||
|
||
/* only support executable file and shared object file */ | ||
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) | ||
goto out; | ||
|
||
if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) | ||
ret = get_build_id_32(page_addr, build_id); | ||
else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) | ||
ret = get_build_id_64(page_addr, build_id); | ||
out: | ||
kunmap_atomic(page_addr); | ||
put_page(page); | ||
return ret; | ||
} |