KFunc bpf_copy_from_user_str
This function copies a string from an unsafe user address.
Definition
Copies a NULL
-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
.
Parameters
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 NULL
.
unsafe_ptr__ign
: Source address, in user space.
flags
: The only supported flag is BPF_F_PAD_ZEROS
Flags
If BPF_F_PAD_ZEROS
flag is set, memset
the tail of dst
to 0
on success and memset
all of @dst on failure.
Returns
0 on success, or a negative error code on failure.
Signature
int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr__ign, u64 flags)
Note
This function may sleep, and therefore can only be used from sleepable programs.
Usage
Docs could be improved
This part of the docs is incomplete, contributions are very welcome
Program types
The following program types can make use of this kfunc:
BPF_PROG_TYPE_CGROUP_DEVICE
v6.12 -BPF_PROG_TYPE_CGROUP_SKB
BPF_PROG_TYPE_CGROUP_SOCK
v6.12 -BPF_PROG_TYPE_CGROUP_SOCKOPT
v6.12 -BPF_PROG_TYPE_CGROUP_SOCK_ADDR
v6.7 -BPF_PROG_TYPE_CGROUP_SYSCTL
v6.12 -BPF_PROG_TYPE_LSM
BPF_PROG_TYPE_LWT_IN
BPF_PROG_TYPE_LWT_OUT
BPF_PROG_TYPE_LWT_SEG6LOCAL
BPF_PROG_TYPE_LWT_XMIT
BPF_PROG_TYPE_NETFILTER
BPF_PROG_TYPE_SCHED_ACT
BPF_PROG_TYPE_SCHED_CLS
BPF_PROG_TYPE_SK_SKB
BPF_PROG_TYPE_SOCKET_FILTER
BPF_PROG_TYPE_STRUCT_OPS
BPF_PROG_TYPE_SYSCALL
BPF_PROG_TYPE_TRACING
BPF_PROG_TYPE_XDP
Example
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017 Facebook
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include <errno.h>
#include "bpf_misc.h"
u32 dynamic_sz = 1;
int uprobe_byname3_str_sleepable_res = 0;
void *user_ptr = 0;
int bpf_copy_from_user_str(void *dst, u32, const void *, u64) __weak __ksym;
static __always_inline bool verify_sleepable_user_copy_str(void)
{
int ret;
char data_long[20];
char data_long_pad[20];
char data_long_err[20];
char data_short[4];
char data_short_pad[4];
ret = bpf_copy_from_user_str(data_short, sizeof(data_short), user_ptr, 0);
if (bpf_strncmp(data_short, 4, "tes\0") != 0 || ret != 4)
return false;
ret = bpf_copy_from_user_str(data_short_pad, sizeof(data_short_pad), user_ptr, BPF_F_PAD_ZEROS);
if (bpf_strncmp(data_short, 4, "tes\0") != 0 || ret != 4)
return false;
/* Make sure this passes the verifier */
ret = bpf_copy_from_user_str(data_long, dynamic_sz & sizeof(data_long), user_ptr, 0);
if (ret != 0)
return false;
ret = bpf_copy_from_user_str(data_long, sizeof(data_long), user_ptr, 0);
if (bpf_strncmp(data_long, 10, "test_data\0") != 0 || ret != 10)
return false;
ret = bpf_copy_from_user_str(data_long_pad, sizeof(data_long_pad), user_ptr, BPF_F_PAD_ZEROS);
if (bpf_strncmp(data_long_pad, 10, "test_data\0") != 0 || ret != 10 || data_long_pad[19] != '\0')
return false;
ret = bpf_copy_from_user_str(data_long_err, sizeof(data_long_err), (void *)data_long, BPF_F_PAD_ZEROS);
if (ret > 0 || data_long_err[19] != '\0')
return false;
ret = bpf_copy_from_user_str(data_long, sizeof(data_long), user_ptr, 2);
if (ret != -EINVAL)
return false;
return true;
}
SEC("uprobe.s//proc/self/exe:trigger_func3")
int handle_uprobe_byname3_sleepable(struct pt_regs *ctx)
{
if (verify_sleepable_user_copy_str())
uprobe_byname3_str_sleepable_res = 10;
return 0;
}