bpf: Add bpf_copy_from_user_task_str() kfunc

This new kfunc will be able to copy a zero-terminated C strings from
another task's address space. This is similar to `bpf_copy_from_user_str()`
but reads memory of specified task.

Signed-off-by: Jordan Rome <linux@jordanrome.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20250213152125.1837400-2-linux@jordanrome.com
This commit is contained in:
Jordan Rome 2025-02-13 07:21:24 -08:00 committed by Andrii Nakryiko
parent f0b79944e6
commit f0f8a5b58f

View File

@ -3067,6 +3067,50 @@ __bpf_kfunc int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void __user
return ret + 1;
}
/**
* bpf_copy_from_user_task_str() - Copy a string from an task's address space
* @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 the task's address space.
* @tsk: The task whose address space will be used
* @flags: The only supported flag is BPF_F_PAD_ZEROS
*
* Copies a NUL terminated string from a task's address space to @dst__sz
* buffer. If user string is too long this will still ensure zero termination
* in the @dst__sz buffer unless buffer size is 0.
*
* If BPF_F_PAD_ZEROS flag is set, memset the tail of @dst__sz to 0 on success
* and memset all of @dst__sz on failure.
*
* Return: The number of copied bytes on success including the NUL terminator.
* A negative error code on failure.
*/
__bpf_kfunc int bpf_copy_from_user_task_str(void *dst, u32 dst__sz,
const void __user *unsafe_ptr__ign,
struct task_struct *tsk, u64 flags)
{
int ret;
if (unlikely(flags & ~BPF_F_PAD_ZEROS))
return -EINVAL;
if (unlikely(dst__sz == 0))
return 0;
ret = copy_remote_vm_str(tsk, (unsigned long)unsafe_ptr__ign, dst, dst__sz, 0);
if (ret < 0) {
if (flags & BPF_F_PAD_ZEROS)
memset(dst, 0, dst__sz);
return ret;
}
if (flags & BPF_F_PAD_ZEROS)
memset(dst + ret, 0, dst__sz - ret);
return ret + 1;
}
/* Keep unsinged long in prototype so that kfunc is usable when emitted to
* vmlinux.h in BPF programs directly, but note that while in BPF prog, the
* unsigned long always points to 8-byte region on stack, the kernel may only
@ -3174,6 +3218,7 @@ 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_ID_FLAGS(func, bpf_copy_from_user_task_str, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_get_kmem_cache)
BTF_ID_FLAGS(func, bpf_iter_kmem_cache_new, KF_ITER_NEW | KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_iter_kmem_cache_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLEEPABLE)