Skip to content

Commit bd7525d

Browse files
olsajiriAlexei Starovoitov
authored andcommitted
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 <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Song Liu <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 7064a73 commit bd7525d

File tree

4 files changed

+153
-140
lines changed

4 files changed

+153
-140
lines changed

include/linux/buildid.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _LINUX_BUILDID_H
3+
#define _LINUX_BUILDID_H
4+
5+
#include <linux/mm_types.h>
6+
7+
#define BUILD_ID_SIZE_MAX 20
8+
9+
int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id);
10+
11+
#endif

kernel/bpf/stackmap.c

Lines changed: 4 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
#include <linux/kernel.h>
88
#include <linux/stacktrace.h>
99
#include <linux/perf_event.h>
10-
#include <linux/elf.h>
11-
#include <linux/pagemap.h>
1210
#include <linux/irq_work.h>
1311
#include <linux/btf_ids.h>
12+
#include <linux/buildid.h>
1413
#include "percpu_freelist.h"
1514

1615
#define STACK_CREATE_FLAG_MASK \
@@ -143,140 +142,6 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
143142
return ERR_PTR(err);
144143
}
145144

146-
#define BPF_BUILD_ID 3
147-
/*
148-
* Parse build id from the note segment. This logic can be shared between
149-
* 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
150-
* identical.
151-
*/
152-
static inline int stack_map_parse_build_id(void *page_addr,
153-
unsigned char *build_id,
154-
void *note_start,
155-
Elf32_Word note_size)
156-
{
157-
Elf32_Word note_offs = 0, new_offs;
158-
159-
/* check for overflow */
160-
if (note_start < page_addr || note_start + note_size < note_start)
161-
return -EINVAL;
162-
163-
/* only supports note that fits in the first page */
164-
if (note_start + note_size > page_addr + PAGE_SIZE)
165-
return -EINVAL;
166-
167-
while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
168-
Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
169-
170-
if (nhdr->n_type == BPF_BUILD_ID &&
171-
nhdr->n_namesz == sizeof("GNU") &&
172-
nhdr->n_descsz > 0 &&
173-
nhdr->n_descsz <= BPF_BUILD_ID_SIZE) {
174-
memcpy(build_id,
175-
note_start + note_offs +
176-
ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr),
177-
nhdr->n_descsz);
178-
memset(build_id + nhdr->n_descsz, 0,
179-
BPF_BUILD_ID_SIZE - nhdr->n_descsz);
180-
return 0;
181-
}
182-
new_offs = note_offs + sizeof(Elf32_Nhdr) +
183-
ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
184-
if (new_offs <= note_offs) /* overflow */
185-
break;
186-
note_offs = new_offs;
187-
}
188-
return -EINVAL;
189-
}
190-
191-
/* Parse build ID from 32-bit ELF */
192-
static int stack_map_get_build_id_32(void *page_addr,
193-
unsigned char *build_id)
194-
{
195-
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr;
196-
Elf32_Phdr *phdr;
197-
int i;
198-
199-
/* only supports phdr that fits in one page */
200-
if (ehdr->e_phnum >
201-
(PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))
202-
return -EINVAL;
203-
204-
phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr));
205-
206-
for (i = 0; i < ehdr->e_phnum; ++i) {
207-
if (phdr[i].p_type == PT_NOTE &&
208-
!stack_map_parse_build_id(page_addr, build_id,
209-
page_addr + phdr[i].p_offset,
210-
phdr[i].p_filesz))
211-
return 0;
212-
}
213-
return -EINVAL;
214-
}
215-
216-
/* Parse build ID from 64-bit ELF */
217-
static int stack_map_get_build_id_64(void *page_addr,
218-
unsigned char *build_id)
219-
{
220-
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr;
221-
Elf64_Phdr *phdr;
222-
int i;
223-
224-
/* only supports phdr that fits in one page */
225-
if (ehdr->e_phnum >
226-
(PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))
227-
return -EINVAL;
228-
229-
phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_Ehdr));
230-
231-
for (i = 0; i < ehdr->e_phnum; ++i) {
232-
if (phdr[i].p_type == PT_NOTE &&
233-
!stack_map_parse_build_id(page_addr, build_id,
234-
page_addr + phdr[i].p_offset,
235-
phdr[i].p_filesz))
236-
return 0;
237-
}
238-
return -EINVAL;
239-
}
240-
241-
/* Parse build ID of ELF file mapped to vma */
242-
static int stack_map_get_build_id(struct vm_area_struct *vma,
243-
unsigned char *build_id)
244-
{
245-
Elf32_Ehdr *ehdr;
246-
struct page *page;
247-
void *page_addr;
248-
int ret;
249-
250-
/* only works for page backed storage */
251-
if (!vma->vm_file)
252-
return -EINVAL;
253-
254-
page = find_get_page(vma->vm_file->f_mapping, 0);
255-
if (!page)
256-
return -EFAULT; /* page not mapped */
257-
258-
ret = -EINVAL;
259-
page_addr = kmap_atomic(page);
260-
ehdr = (Elf32_Ehdr *)page_addr;
261-
262-
/* compare magic x7f "ELF" */
263-
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
264-
goto out;
265-
266-
/* only support executable file and shared object file */
267-
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
268-
goto out;
269-
270-
if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
271-
ret = stack_map_get_build_id_32(page_addr, build_id);
272-
else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
273-
ret = stack_map_get_build_id_64(page_addr, build_id);
274-
out:
275-
kunmap_atomic(page_addr);
276-
put_page(page);
277-
return ret;
278-
}
279-
280145
static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
281146
u64 *ips, u32 trace_nr, bool user)
282147
{
@@ -317,18 +182,18 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
317182
for (i = 0; i < trace_nr; i++) {
318183
id_offs[i].status = BPF_STACK_BUILD_ID_IP;
319184
id_offs[i].ip = ips[i];
320-
memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE);
185+
memset(id_offs[i].build_id, 0, BUILD_ID_SIZE_MAX);
321186
}
322187
return;
323188
}
324189

325190
for (i = 0; i < trace_nr; i++) {
326191
vma = find_vma(current->mm, ips[i]);
327-
if (!vma || stack_map_get_build_id(vma, id_offs[i].build_id)) {
192+
if (!vma || build_id_parse(vma, id_offs[i].build_id)) {
328193
/* per entry fall back to ips */
329194
id_offs[i].status = BPF_STACK_BUILD_ID_IP;
330195
id_offs[i].ip = ips[i];
331-
memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE);
196+
memset(id_offs[i].build_id, 0, BUILD_ID_SIZE_MAX);
332197
continue;
333198
}
334199
id_offs[i].offset = (vma->vm_pgoff << PAGE_SHIFT) + ips[i]

lib/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
3636
flex_proportions.o ratelimit.o show_mem.o \
3737
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
3838
earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
39-
nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o
39+
nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o \
40+
buildid.o
4041

4142
lib-$(CONFIG_PRINTK) += dump_stack.o
4243
lib-$(CONFIG_SMP) += cpumask.o

lib/buildid.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/buildid.h>
4+
#include <linux/elf.h>
5+
#include <linux/pagemap.h>
6+
7+
#define BUILD_ID 3
8+
/*
9+
* Parse build id from the note segment. This logic can be shared between
10+
* 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
11+
* identical.
12+
*/
13+
static inline int parse_build_id(void *page_addr,
14+
unsigned char *build_id,
15+
void *note_start,
16+
Elf32_Word note_size)
17+
{
18+
Elf32_Word note_offs = 0, new_offs;
19+
20+
/* check for overflow */
21+
if (note_start < page_addr || note_start + note_size < note_start)
22+
return -EINVAL;
23+
24+
/* only supports note that fits in the first page */
25+
if (note_start + note_size > page_addr + PAGE_SIZE)
26+
return -EINVAL;
27+
28+
while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
29+
Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
30+
31+
if (nhdr->n_type == BUILD_ID &&
32+
nhdr->n_namesz == sizeof("GNU") &&
33+
nhdr->n_descsz > 0 &&
34+
nhdr->n_descsz <= BUILD_ID_SIZE_MAX) {
35+
memcpy(build_id,
36+
note_start + note_offs +
37+
ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr),
38+
nhdr->n_descsz);
39+
memset(build_id + nhdr->n_descsz, 0,
40+
BUILD_ID_SIZE_MAX - nhdr->n_descsz);
41+
return 0;
42+
}
43+
new_offs = note_offs + sizeof(Elf32_Nhdr) +
44+
ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
45+
if (new_offs <= note_offs) /* overflow */
46+
break;
47+
note_offs = new_offs;
48+
}
49+
return -EINVAL;
50+
}
51+
52+
/* Parse build ID from 32-bit ELF */
53+
static int get_build_id_32(void *page_addr, unsigned char *build_id)
54+
{
55+
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr;
56+
Elf32_Phdr *phdr;
57+
int i;
58+
59+
/* only supports phdr that fits in one page */
60+
if (ehdr->e_phnum >
61+
(PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))
62+
return -EINVAL;
63+
64+
phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr));
65+
66+
for (i = 0; i < ehdr->e_phnum; ++i) {
67+
if (phdr[i].p_type == PT_NOTE &&
68+
!parse_build_id(page_addr, build_id,
69+
page_addr + phdr[i].p_offset,
70+
phdr[i].p_filesz))
71+
return 0;
72+
}
73+
return -EINVAL;
74+
}
75+
76+
/* Parse build ID from 64-bit ELF */
77+
static int get_build_id_64(void *page_addr, unsigned char *build_id)
78+
{
79+
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr;
80+
Elf64_Phdr *phdr;
81+
int i;
82+
83+
/* only supports phdr that fits in one page */
84+
if (ehdr->e_phnum >
85+
(PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))
86+
return -EINVAL;
87+
88+
phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_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,
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 of ELF file mapped to vma */
101+
int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id)
102+
{
103+
Elf32_Ehdr *ehdr;
104+
struct page *page;
105+
void *page_addr;
106+
int ret;
107+
108+
/* only works for page backed storage */
109+
if (!vma->vm_file)
110+
return -EINVAL;
111+
112+
page = find_get_page(vma->vm_file->f_mapping, 0);
113+
if (!page)
114+
return -EFAULT; /* page not mapped */
115+
116+
ret = -EINVAL;
117+
page_addr = kmap_atomic(page);
118+
ehdr = (Elf32_Ehdr *)page_addr;
119+
120+
/* compare magic x7f "ELF" */
121+
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
122+
goto out;
123+
124+
/* only support executable file and shared object file */
125+
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
126+
goto out;
127+
128+
if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
129+
ret = get_build_id_32(page_addr, build_id);
130+
else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
131+
ret = get_build_id_64(page_addr, build_id);
132+
out:
133+
kunmap_atomic(page_addr);
134+
put_page(page);
135+
return ret;
136+
}

0 commit comments

Comments
 (0)