Skip to content

Commit 65ab5ac

Browse files
Jordan RomeAlexei Starovoitov
authored andcommitted
bpf: Add bpf_copy_from_user_str kfunc
This adds a kfunc wrapper around strncpy_from_user, which can be called from sleepable BPF programs. This matches the non-sleepable 'bpf_probe_read_user_str' helper except it includes an additional 'flags' param, which allows consumers to clear the entire destination buffer on success or failure. Signed-off-by: Jordan Rome <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 5772c34 commit 65ab5ac

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

include/uapi/linux/bpf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7513,4 +7513,13 @@ struct bpf_iter_num {
75137513
__u64 __opaque[1];
75147514
} __attribute__((aligned(8)));
75157515

7516+
/*
7517+
* Flags to control BPF kfunc behaviour.
7518+
* - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
7519+
* helper documentation for details.)
7520+
*/
7521+
enum bpf_kfunc_flags {
7522+
BPF_F_PAD_ZEROS = (1ULL << 0),
7523+
};
7524+
75167525
#endif /* _UAPI__LINUX_BPF_H__ */

kernel/bpf/helpers.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2962,6 +2962,47 @@ __bpf_kfunc void bpf_iter_bits_destroy(struct bpf_iter_bits *it)
29622962
bpf_mem_free(&bpf_global_ma, kit->bits);
29632963
}
29642964

2965+
/**
2966+
* bpf_copy_from_user_str() - Copy a string from an unsafe user address
2967+
* @dst: Destination address, in kernel space. This buffer must be
2968+
* at least @dst__sz bytes long.
2969+
* @dst__sz: Maximum number of bytes to copy, includes the trailing NUL.
2970+
* @unsafe_ptr__ign: Source address, in user space.
2971+
* @flags: The only supported flag is BPF_F_PAD_ZEROS
2972+
*
2973+
* Copies a NUL-terminated string from userspace to BPF space. If user string is
2974+
* too long this will still ensure zero termination in the dst buffer unless
2975+
* buffer size is 0.
2976+
*
2977+
* If BPF_F_PAD_ZEROS flag is set, memset the tail of @dst to 0 on success and
2978+
* memset all of @dst on failure.
2979+
*/
2980+
__bpf_kfunc int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void __user *unsafe_ptr__ign, u64 flags)
2981+
{
2982+
int ret;
2983+
2984+
if (unlikely(flags & ~BPF_F_PAD_ZEROS))
2985+
return -EINVAL;
2986+
2987+
if (unlikely(!dst__sz))
2988+
return 0;
2989+
2990+
ret = strncpy_from_user(dst, unsafe_ptr__ign, dst__sz - 1);
2991+
if (ret < 0) {
2992+
if (flags & BPF_F_PAD_ZEROS)
2993+
memset((char *)dst, 0, dst__sz);
2994+
2995+
return ret;
2996+
}
2997+
2998+
if (flags & BPF_F_PAD_ZEROS)
2999+
memset((char *)dst + ret, 0, dst__sz - ret);
3000+
else
3001+
((char *)dst)[ret] = '\0';
3002+
3003+
return ret + 1;
3004+
}
3005+
29653006
__bpf_kfunc_end_defs();
29663007

29673008
BTF_KFUNCS_START(generic_btf_ids)
@@ -3047,6 +3088,7 @@ BTF_ID_FLAGS(func, bpf_preempt_enable)
30473088
BTF_ID_FLAGS(func, bpf_iter_bits_new, KF_ITER_NEW)
30483089
BTF_ID_FLAGS(func, bpf_iter_bits_next, KF_ITER_NEXT | KF_RET_NULL)
30493090
BTF_ID_FLAGS(func, bpf_iter_bits_destroy, KF_ITER_DESTROY)
3091+
BTF_ID_FLAGS(func, bpf_copy_from_user_str, KF_SLEEPABLE)
30503092
BTF_KFUNCS_END(common_btf_ids)
30513093

30523094
static const struct btf_kfunc_id_set common_kfunc_set = {

tools/include/uapi/linux/bpf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7512,4 +7512,13 @@ struct bpf_iter_num {
75127512
__u64 __opaque[1];
75137513
} __attribute__((aligned(8)));
75147514

7515+
/*
7516+
* Flags to control BPF kfunc behaviour.
7517+
* - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
7518+
* helper documentation for details.)
7519+
*/
7520+
enum bpf_kfunc_flags {
7521+
BPF_F_PAD_ZEROS = (1ULL << 0),
7522+
};
7523+
75157524
#endif /* _UAPI__LINUX_BPF_H__ */

0 commit comments

Comments
 (0)