summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2025-10-27 19:56:28 +0300
committerAlexei Starovoitov <ast@kernel.org>2025-10-27 19:56:28 +0300
commitff880798de39251aa5e28ab389c16d294b7af658 (patch)
treefd8c51839c4790e65e3130c6d54c532b3496d472 /lib
parente7586577b75f811bd14c12f2dd70afc3ece4756b (diff)
parent784cdf931543805120aed1e1c43df8e6fa436a55 (diff)
downloadlinux-ff880798de39251aa5e28ab389c16d294b7af658.tar.xz
Merge branch 'bpf-introduce-file-dynptr'
Mykyta Yatsenko says: ==================== bpf: Introduce file dynptr From: Mykyta Yatsenko <yatsenko@meta.com> This series adds a new dynptr kind, file dynptr, which enables BPF programs to perform safe reads from files in a structured way. Initial motivations include: * Parsing the executable’s ELF to locate thread-local variable symbols * Capturing stack traces when frame pointers are disabled By leveraging the existing dynptr abstraction, we reuse the verifier’s lifetime/size checks and keep the API consistent with existing dynptr read helpers. Technical details: 1. Reuses the existing freader library to read files a folio at a time. 2. bpf_dynptr_slice() and bpf_dynptr_read() always copy data from folios into a program-provided buffer; zero-copy access is intentionally not supported to keep it simple. 3. Reads may sleep if the requested folios are not in the page cache. 4. Few verifier changes required: * Support dynptr destruction in kfuncs * Add kfunc address substitution based on whether the program runs in a sleepable or non-sleepable context. Testing: The final patch adds a selftest that validates BPF program reads the same data as userspace, page faults are enabled in sleepable context and disabled in non-sleepable. Changelog: --- v4 -> v5 v4: https://lore.kernel.org/all/20251021200334.220542-1-mykyta.yatsenko5@gmail.com/ * Inlined and removed kfunc_call_imm(), run overflow check for call_imm only if !bpf_jit_supports_far_kfunc_call(). v3 -> v4 v3: https://lore.kernel.org/bpf/20251020222538.932915-1-mykyta.yatsenko5@gmail.com/ * Remove ringbuf usage from selftests * bpf_dynptr_set_null(ptr) when discarding file dynptr * call kfunc_call_imm() in specialize_kfunc() only, removed call from add_kfunc_call() v2 -> v3 v2: https://lore.kernel.org/bpf/20251015161155.120148-1-mykyta.yatsenko5@gmail.com/ * Add negative tests * Rewrote tests to use LSM for bpf_get_task_exe_file() * Move call_imm overflow check into kfunc_call_imm() v1 -> v2 v1: https://lore.kernel.org/bpf/20251003160416.585080-1-mykyta.yatsenko5@gmail.com/ * Remove ELF parsing selftest * Expanded u32 -> u64 refactoring, changes in include/uapi/linux/bpf.h * Removed freader.{c,h}, instead move freader definitions into buildid.h. * Small refactoring of the multiple folios reading algorithm * Directly return error after unmark_stack_slots_dynptr(). * Make kfuncs receive trusted arguments. * Remove enum bpf_is_sleepable, use bool instead * Remove unnecessary sorting from specialize_kfunc() * Remove bool kfunc_in_sleepable_ctx; field from the struct bpf_insn_aux_data, rely on non_sleepable field introduced by Kumar * Refactor selftests, do madvise(...MADV_PAGEOUT) for all pages read by the test * Introduce the test for non-sleepable case, verify it fails with -EFAULT ==================== Link: https://lore.kernel.org/r/20251026203853.135105-1-mykyta.yatsenko5@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/buildid.c56
1 files changed, 20 insertions, 36 deletions
diff --git a/lib/buildid.c b/lib/buildid.c
index c4b0f376fb34..aaf61dfc0919 100644
--- a/lib/buildid.c
+++ b/lib/buildid.c
@@ -11,27 +11,8 @@
#define MAX_PHDR_CNT 256
-struct freader {
- void *buf;
- u32 buf_sz;
- int err;
- union {
- struct {
- struct file *file;
- struct folio *folio;
- void *addr;
- loff_t folio_off;
- bool may_fault;
- };
- struct {
- const char *data;
- u64 data_sz;
- };
- };
-};
-
-static void freader_init_from_file(struct freader *r, void *buf, u32 buf_sz,
- struct file *file, bool may_fault)
+void freader_init_from_file(struct freader *r, void *buf, u32 buf_sz,
+ struct file *file, bool may_fault)
{
memset(r, 0, sizeof(*r));
r->buf = buf;
@@ -40,7 +21,7 @@ static void freader_init_from_file(struct freader *r, void *buf, u32 buf_sz,
r->may_fault = may_fault;
}
-static void freader_init_from_mem(struct freader *r, const char *data, u64 data_sz)
+void freader_init_from_mem(struct freader *r, const char *data, u64 data_sz)
{
memset(r, 0, sizeof(*r));
r->data = data;
@@ -92,7 +73,7 @@ static int freader_get_folio(struct freader *r, loff_t file_off)
return 0;
}
-static const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz)
+const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz)
{
size_t folio_sz;
@@ -127,18 +108,21 @@ static const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz)
*/
folio_sz = folio_size(r->folio);
if (file_off + sz > r->folio_off + folio_sz) {
- int part_sz = r->folio_off + folio_sz - file_off;
-
- /* copy the part that resides in the current folio */
- memcpy(r->buf, r->addr + (file_off - r->folio_off), part_sz);
-
- /* fetch next folio */
- r->err = freader_get_folio(r, r->folio_off + folio_sz);
- if (r->err)
- return NULL;
-
- /* copy the rest of requested data */
- memcpy(r->buf + part_sz, r->addr, sz - part_sz);
+ u64 part_sz = r->folio_off + folio_sz - file_off, off;
+
+ memcpy(r->buf, r->addr + file_off - r->folio_off, part_sz);
+ off = part_sz;
+
+ while (off < sz) {
+ /* fetch next folio */
+ r->err = freader_get_folio(r, r->folio_off + folio_sz);
+ if (r->err)
+ return NULL;
+ folio_sz = folio_size(r->folio);
+ part_sz = min_t(u64, sz - off, folio_sz);
+ memcpy(r->buf + off, r->addr, part_sz);
+ off += part_sz;
+ }
return r->buf;
}
@@ -147,7 +131,7 @@ static const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz)
return r->addr + (file_off - r->folio_off);
}
-static void freader_cleanup(struct freader *r)
+void freader_cleanup(struct freader *r)
{
if (!r->buf)
return; /* non-file-backed mode */