Commit 65ab5ac4 authored by Jordan Rome's avatar Jordan Rome Committed by Alexei Starovoitov
Browse files

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: default avatarJordan Rome <linux@jordanrome.com>
Link: https://lore.kernel.org/r/20240823195101.3621028-1-linux@jordanrome.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 5772c345
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -7513,4 +7513,13 @@ struct bpf_iter_num {
	__u64 __opaque[1];
} __attribute__((aligned(8)));

/*
 * Flags to control BPF kfunc behaviour.
 *     - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
 *       helper documentation for details.)
 */
enum bpf_kfunc_flags {
	BPF_F_PAD_ZEROS = (1ULL << 0),
};

#endif /* _UAPI__LINUX_BPF_H__ */
+42 −0
Original line number Diff line number Diff line
@@ -2962,6 +2962,47 @@ __bpf_kfunc void bpf_iter_bits_destroy(struct bpf_iter_bits *it)
	bpf_mem_free(&bpf_global_ma, kit->bits);
}

/**
 * bpf_copy_from_user_str() - Copy a string from an unsafe user address
 * @dst:             Destination address, in kernel space.  This buffer must be
 *                   at least @dst__sz bytes long.
 * @dst__sz:         Maximum number of bytes to copy, includes the trailing NUL.
 * @unsafe_ptr__ign: Source address, in user space.
 * @flags:           The only supported flag is BPF_F_PAD_ZEROS
 *
 * Copies a NUL-terminated string from userspace to BPF space. If user string is
 * too long this will still ensure zero termination in the dst buffer unless
 * buffer size is 0.
 *
 * If BPF_F_PAD_ZEROS flag is set, memset the tail of @dst to 0 on success and
 * memset all of @dst on failure.
 */
__bpf_kfunc int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void __user *unsafe_ptr__ign, u64 flags)
{
	int ret;

	if (unlikely(flags & ~BPF_F_PAD_ZEROS))
		return -EINVAL;

	if (unlikely(!dst__sz))
		return 0;

	ret = strncpy_from_user(dst, unsafe_ptr__ign, dst__sz - 1);
	if (ret < 0) {
		if (flags & BPF_F_PAD_ZEROS)
			memset((char *)dst, 0, dst__sz);

		return ret;
	}

	if (flags & BPF_F_PAD_ZEROS)
		memset((char *)dst + ret, 0, dst__sz - ret);
	else
		((char *)dst)[ret] = '\0';

	return ret + 1;
}

__bpf_kfunc_end_defs();

BTF_KFUNCS_START(generic_btf_ids)
@@ -3047,6 +3088,7 @@ BTF_ID_FLAGS(func, bpf_preempt_enable)
BTF_ID_FLAGS(func, bpf_iter_bits_new, KF_ITER_NEW)
BTF_ID_FLAGS(func, bpf_iter_bits_next, KF_ITER_NEXT | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_iter_bits_destroy, KF_ITER_DESTROY)
BTF_ID_FLAGS(func, bpf_copy_from_user_str, KF_SLEEPABLE)
BTF_KFUNCS_END(common_btf_ids)

static const struct btf_kfunc_id_set common_kfunc_set = {
+9 −0
Original line number Diff line number Diff line
@@ -7512,4 +7512,13 @@ struct bpf_iter_num {
	__u64 __opaque[1];
} __attribute__((aligned(8)));

/*
 * Flags to control BPF kfunc behaviour.
 *     - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
 *       helper documentation for details.)
 */
enum bpf_kfunc_flags {
	BPF_F_PAD_ZEROS = (1ULL << 0),
};

#endif /* _UAPI__LINUX_BPF_H__ */