Skip to content

Commit ff88079

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf-introduce-file-dynptr'
Mykyta Yatsenko says: ==================== bpf: Introduce file dynptr From: Mykyta Yatsenko <[email protected]> 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/[email protected]/ * 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/[email protected]/ * 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/[email protected]/ * 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/[email protected]/ * 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/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents e758657 + 784cdf9 commit ff88079

File tree

17 files changed

+649
-195
lines changed

17 files changed

+649
-195
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4648,6 +4648,7 @@ F: Documentation/userspace-api/ebpf/
46484648
F: arch/*/net/*
46494649
F: include/linux/bpf*
46504650
F: include/linux/btf*
4651+
F: include/linux/buildid.h
46514652
F: include/linux/filter.h
46524653
F: include/trace/events/xdp.h
46534654
F: include/uapi/linux/bpf*

include/linux/bpf.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,9 @@ static inline bool bpf_map_has_internal_structs(struct bpf_map *map)
670670

671671
void bpf_map_free_internal_structs(struct bpf_map *map, void *obj);
672672

673+
int bpf_dynptr_from_file_sleepable(struct file *file, u32 flags,
674+
struct bpf_dynptr *ptr__uninit);
675+
673676
extern const struct bpf_map_ops bpf_map_offload_ops;
674677

675678
/* bpf_type_flag contains a set of flags that are applicable to the values of
@@ -792,12 +795,15 @@ enum bpf_type_flag {
792795
/* DYNPTR points to skb_metadata_end()-skb_metadata_len() */
793796
DYNPTR_TYPE_SKB_META = BIT(19 + BPF_BASE_TYPE_BITS),
794797

798+
/* DYNPTR points to file */
799+
DYNPTR_TYPE_FILE = BIT(20 + BPF_BASE_TYPE_BITS),
800+
795801
__BPF_TYPE_FLAG_MAX,
796802
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
797803
};
798804

799805
#define DYNPTR_TYPE_FLAG_MASK (DYNPTR_TYPE_LOCAL | DYNPTR_TYPE_RINGBUF | DYNPTR_TYPE_SKB \
800-
| DYNPTR_TYPE_XDP | DYNPTR_TYPE_SKB_META)
806+
| DYNPTR_TYPE_XDP | DYNPTR_TYPE_SKB_META | DYNPTR_TYPE_FILE)
801807

802808
/* Max number of base types. */
803809
#define BPF_BASE_TYPE_LIMIT (1UL << BPF_BASE_TYPE_BITS)
@@ -1385,21 +1391,23 @@ enum bpf_dynptr_type {
13851391
BPF_DYNPTR_TYPE_XDP,
13861392
/* Points to skb_metadata_end()-skb_metadata_len() */
13871393
BPF_DYNPTR_TYPE_SKB_META,
1394+
/* Underlying data is a file */
1395+
BPF_DYNPTR_TYPE_FILE,
13881396
};
13891397

1390-
int bpf_dynptr_check_size(u32 size);
1391-
u32 __bpf_dynptr_size(const struct bpf_dynptr_kern *ptr);
1392-
const void *__bpf_dynptr_data(const struct bpf_dynptr_kern *ptr, u32 len);
1393-
void *__bpf_dynptr_data_rw(const struct bpf_dynptr_kern *ptr, u32 len);
1398+
int bpf_dynptr_check_size(u64 size);
1399+
u64 __bpf_dynptr_size(const struct bpf_dynptr_kern *ptr);
1400+
const void *__bpf_dynptr_data(const struct bpf_dynptr_kern *ptr, u64 len);
1401+
void *__bpf_dynptr_data_rw(const struct bpf_dynptr_kern *ptr, u64 len);
13941402
bool __bpf_dynptr_is_rdonly(const struct bpf_dynptr_kern *ptr);
1395-
int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u32 offset,
1396-
void *src, u32 len, u64 flags);
1397-
void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *p, u32 offset,
1398-
void *buffer__opt, u32 buffer__szk);
1403+
int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u64 offset,
1404+
void *src, u64 len, u64 flags);
1405+
void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *p, u64 offset,
1406+
void *buffer__opt, u64 buffer__szk);
13991407

1400-
static inline int bpf_dynptr_check_off_len(const struct bpf_dynptr_kern *ptr, u32 offset, u32 len)
1408+
static inline int bpf_dynptr_check_off_len(const struct bpf_dynptr_kern *ptr, u64 offset, u64 len)
14011409
{
1402-
u32 size = __bpf_dynptr_size(ptr);
1410+
u64 size = __bpf_dynptr_size(ptr);
14031411

14041412
if (len > size || offset > size - len)
14051413
return -E2BIG;

include/linux/buildid.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,29 @@ void init_vmlinux_build_id(void);
1818
static inline void init_vmlinux_build_id(void) { }
1919
#endif
2020

21+
struct freader {
22+
void *buf;
23+
u32 buf_sz;
24+
int err;
25+
union {
26+
struct {
27+
struct file *file;
28+
struct folio *folio;
29+
void *addr;
30+
loff_t folio_off;
31+
bool may_fault;
32+
};
33+
struct {
34+
const char *data;
35+
u64 data_sz;
36+
};
37+
};
38+
};
39+
40+
void freader_init_from_file(struct freader *r, void *buf, u32 buf_sz,
41+
struct file *file, bool may_fault);
42+
void freader_init_from_mem(struct freader *r, const char *data, u64 data_sz);
43+
const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz);
44+
void freader_cleanup(struct freader *r);
45+
2146
#endif

include/uapi/linux/bpf.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5618,7 +5618,7 @@ union bpf_attr {
56185618
* Return
56195619
* *sk* if casting is valid, or **NULL** otherwise.
56205620
*
5621-
* long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr)
5621+
* long bpf_dynptr_from_mem(void *data, u64 size, u64 flags, struct bpf_dynptr *ptr)
56225622
* Description
56235623
* Get a dynptr to local memory *data*.
56245624
*
@@ -5661,7 +5661,7 @@ union bpf_attr {
56615661
* Return
56625662
* Nothing. Always succeeds.
56635663
*
5664-
* long bpf_dynptr_read(void *dst, u32 len, const struct bpf_dynptr *src, u32 offset, u64 flags)
5664+
* long bpf_dynptr_read(void *dst, u64 len, const struct bpf_dynptr *src, u64 offset, u64 flags)
56655665
* Description
56665666
* Read *len* bytes from *src* into *dst*, starting from *offset*
56675667
* into *src*.
@@ -5671,7 +5671,7 @@ union bpf_attr {
56715671
* of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
56725672
* *flags* is not 0.
56735673
*
5674-
* long bpf_dynptr_write(const struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
5674+
* long bpf_dynptr_write(const struct bpf_dynptr *dst, u64 offset, void *src, u64 len, u64 flags)
56755675
* Description
56765676
* Write *len* bytes from *src* into *dst*, starting from *offset*
56775677
* into *dst*.
@@ -5692,7 +5692,7 @@ union bpf_attr {
56925692
* is a read-only dynptr or if *flags* is not correct. For skb-type dynptrs,
56935693
* other errors correspond to errors returned by **bpf_skb_store_bytes**\ ().
56945694
*
5695-
* void *bpf_dynptr_data(const struct bpf_dynptr *ptr, u32 offset, u32 len)
5695+
* void *bpf_dynptr_data(const struct bpf_dynptr *ptr, u64 offset, u64 len)
56965696
* Description
56975697
* Get a pointer to the underlying dynptr data.
56985698
*

0 commit comments

Comments
 (0)