Commit 263ae152 authored by Joanne Koong's avatar Joanne Koong Committed by Andrii Nakryiko
Browse files

bpf: Add bpf_dynptr_from_mem for local dynptrs



This patch adds a new api bpf_dynptr_from_mem:

long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr);

which initializes a dynptr to point to a bpf program's local memory. For now
only local memory that is of reg type PTR_TO_MAP_VALUE is supported.

Signed-off-by: default avatarJoanne Koong <joannelkoong@gmail.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20220523210712.3641569-3-joannelkoong@gmail.com
parent 97e03f52
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -5178,6 +5178,17 @@ union bpf_attr {
 *		Dynamically cast a *sk* pointer to a *mptcp_sock* pointer.
 *	Return
 *		*sk* if casting is valid, or **NULL** otherwise.
 *
 * long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr)
 *	Description
 *		Get a dynptr to local memory *data*.
 *
 *		*data* must be a ptr to a map value.
 *		The maximum *size* supported is DYNPTR_MAX_SIZE.
 *		*flags* is currently unused.
 *	Return
 *		0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE,
 *		-EINVAL if flags is not 0.
 */
#define __BPF_FUNC_MAPPER(FN)		\
	FN(unspec),			\
@@ -5377,6 +5388,7 @@ union bpf_attr {
	FN(kptr_xchg),			\
	FN(map_lookup_percpu_elem),     \
	FN(skc_to_mptcp_sock),		\
	FN(dynptr_from_mem),		\
	/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
+65 −0
Original line number Diff line number Diff line
@@ -1412,6 +1412,69 @@ const struct bpf_func_proto bpf_kptr_xchg_proto = {
	.arg2_btf_id  = BPF_PTR_POISON,
};

/* Since the upper 8 bits of dynptr->size is reserved, the
 * maximum supported size is 2^24 - 1.
 */
#define DYNPTR_MAX_SIZE	((1UL << 24) - 1)
#define DYNPTR_TYPE_SHIFT	28

static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_type type)
{
	ptr->size |= type << DYNPTR_TYPE_SHIFT;
}

static int bpf_dynptr_check_size(u32 size)
{
	return size > DYNPTR_MAX_SIZE ? -E2BIG : 0;
}

static void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data,
			    enum bpf_dynptr_type type, u32 offset, u32 size)
{
	ptr->data = data;
	ptr->offset = offset;
	ptr->size = size;
	bpf_dynptr_set_type(ptr, type);
}

static void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr)
{
	memset(ptr, 0, sizeof(*ptr));
}

BPF_CALL_4(bpf_dynptr_from_mem, void *, data, u32, size, u64, flags, struct bpf_dynptr_kern *, ptr)
{
	int err;

	err = bpf_dynptr_check_size(size);
	if (err)
		goto error;

	/* flags is currently unsupported */
	if (flags) {
		err = -EINVAL;
		goto error;
	}

	bpf_dynptr_init(ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0, size);

	return 0;

error:
	bpf_dynptr_set_null(ptr);
	return err;
}

const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
	.func		= bpf_dynptr_from_mem,
	.gpl_only	= false,
	.ret_type	= RET_INTEGER,
	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
	.arg3_type	= ARG_ANYTHING,
	.arg4_type	= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
};

const struct bpf_func_proto bpf_get_current_task_proto __weak;
const struct bpf_func_proto bpf_get_current_task_btf_proto __weak;
const struct bpf_func_proto bpf_probe_read_user_proto __weak;
@@ -1466,6 +1529,8 @@ bpf_base_func_proto(enum bpf_func_id func_id)
		return &bpf_loop_proto;
	case BPF_FUNC_strncmp:
		return &bpf_strncmp_proto;
	case BPF_FUNC_dynptr_from_mem:
		return &bpf_dynptr_from_mem_proto;
	default:
		break;
	}
+6 −0
Original line number Diff line number Diff line
@@ -7204,6 +7204,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
		err = __check_func_call(env, insn, insn_idx_p, meta.subprogno,
					set_loop_callback_state);
		break;
	case BPF_FUNC_dynptr_from_mem:
		if (regs[BPF_REG_1].type != PTR_TO_MAP_VALUE) {
			verbose(env, "Unsupported reg type %s for bpf_dynptr_from_mem data\n",
				reg_type_str(env, regs[BPF_REG_1].type));
			return -EACCES;
		}
	}

	if (err)
+12 −0
Original line number Diff line number Diff line
@@ -5178,6 +5178,17 @@ union bpf_attr {
 *		Dynamically cast a *sk* pointer to a *mptcp_sock* pointer.
 *	Return
 *		*sk* if casting is valid, or **NULL** otherwise.
 *
 * long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr)
 *	Description
 *		Get a dynptr to local memory *data*.
 *
 *		*data* must be a ptr to a map value.
 *		The maximum *size* supported is DYNPTR_MAX_SIZE.
 *		*flags* is currently unused.
 *	Return
 *		0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE,
 *		-EINVAL if flags is not 0.
 */
#define __BPF_FUNC_MAPPER(FN)		\
	FN(unspec),			\
@@ -5377,6 +5388,7 @@ union bpf_attr {
	FN(kptr_xchg),			\
	FN(map_lookup_percpu_elem),     \
	FN(skc_to_mptcp_sock),		\
	FN(dynptr_from_mem),		\
	/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper