Skip to content

Commit 263ae15

Browse files
joannekoonganakryiko
authored andcommitted
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: Joanne Koong <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 97e03f5 commit 263ae15

File tree

4 files changed

+95
-0
lines changed

4 files changed

+95
-0
lines changed

include/uapi/linux/bpf.h

+12
Original file line numberDiff line numberDiff line change
@@ -5178,6 +5178,17 @@ union bpf_attr {
51785178
* Dynamically cast a *sk* pointer to a *mptcp_sock* pointer.
51795179
* Return
51805180
* *sk* if casting is valid, or **NULL** otherwise.
5181+
*
5182+
* long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr)
5183+
* Description
5184+
* Get a dynptr to local memory *data*.
5185+
*
5186+
* *data* must be a ptr to a map value.
5187+
* The maximum *size* supported is DYNPTR_MAX_SIZE.
5188+
* *flags* is currently unused.
5189+
* Return
5190+
* 0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE,
5191+
* -EINVAL if flags is not 0.
51815192
*/
51825193
#define __BPF_FUNC_MAPPER(FN) \
51835194
FN(unspec), \
@@ -5377,6 +5388,7 @@ union bpf_attr {
53775388
FN(kptr_xchg), \
53785389
FN(map_lookup_percpu_elem), \
53795390
FN(skc_to_mptcp_sock), \
5391+
FN(dynptr_from_mem), \
53805392
/* */
53815393

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

kernel/bpf/helpers.c

+65
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,69 @@ const struct bpf_func_proto bpf_kptr_xchg_proto = {
14121412
.arg2_btf_id = BPF_PTR_POISON,
14131413
};
14141414

1415+
/* Since the upper 8 bits of dynptr->size is reserved, the
1416+
* maximum supported size is 2^24 - 1.
1417+
*/
1418+
#define DYNPTR_MAX_SIZE ((1UL << 24) - 1)
1419+
#define DYNPTR_TYPE_SHIFT 28
1420+
1421+
static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_type type)
1422+
{
1423+
ptr->size |= type << DYNPTR_TYPE_SHIFT;
1424+
}
1425+
1426+
static int bpf_dynptr_check_size(u32 size)
1427+
{
1428+
return size > DYNPTR_MAX_SIZE ? -E2BIG : 0;
1429+
}
1430+
1431+
static void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data,
1432+
enum bpf_dynptr_type type, u32 offset, u32 size)
1433+
{
1434+
ptr->data = data;
1435+
ptr->offset = offset;
1436+
ptr->size = size;
1437+
bpf_dynptr_set_type(ptr, type);
1438+
}
1439+
1440+
static void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr)
1441+
{
1442+
memset(ptr, 0, sizeof(*ptr));
1443+
}
1444+
1445+
BPF_CALL_4(bpf_dynptr_from_mem, void *, data, u32, size, u64, flags, struct bpf_dynptr_kern *, ptr)
1446+
{
1447+
int err;
1448+
1449+
err = bpf_dynptr_check_size(size);
1450+
if (err)
1451+
goto error;
1452+
1453+
/* flags is currently unsupported */
1454+
if (flags) {
1455+
err = -EINVAL;
1456+
goto error;
1457+
}
1458+
1459+
bpf_dynptr_init(ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0, size);
1460+
1461+
return 0;
1462+
1463+
error:
1464+
bpf_dynptr_set_null(ptr);
1465+
return err;
1466+
}
1467+
1468+
const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
1469+
.func = bpf_dynptr_from_mem,
1470+
.gpl_only = false,
1471+
.ret_type = RET_INTEGER,
1472+
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
1473+
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
1474+
.arg3_type = ARG_ANYTHING,
1475+
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
1476+
};
1477+
14151478
const struct bpf_func_proto bpf_get_current_task_proto __weak;
14161479
const struct bpf_func_proto bpf_get_current_task_btf_proto __weak;
14171480
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)
14661529
return &bpf_loop_proto;
14671530
case BPF_FUNC_strncmp:
14681531
return &bpf_strncmp_proto;
1532+
case BPF_FUNC_dynptr_from_mem:
1533+
return &bpf_dynptr_from_mem_proto;
14691534
default:
14701535
break;
14711536
}

kernel/bpf/verifier.c

+6
Original file line numberDiff line numberDiff line change
@@ -7204,6 +7204,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
72047204
err = __check_func_call(env, insn, insn_idx_p, meta.subprogno,
72057205
set_loop_callback_state);
72067206
break;
7207+
case BPF_FUNC_dynptr_from_mem:
7208+
if (regs[BPF_REG_1].type != PTR_TO_MAP_VALUE) {
7209+
verbose(env, "Unsupported reg type %s for bpf_dynptr_from_mem data\n",
7210+
reg_type_str(env, regs[BPF_REG_1].type));
7211+
return -EACCES;
7212+
}
72077213
}
72087214

72097215
if (err)

tools/include/uapi/linux/bpf.h

+12
Original file line numberDiff line numberDiff line change
@@ -5178,6 +5178,17 @@ union bpf_attr {
51785178
* Dynamically cast a *sk* pointer to a *mptcp_sock* pointer.
51795179
* Return
51805180
* *sk* if casting is valid, or **NULL** otherwise.
5181+
*
5182+
* long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr)
5183+
* Description
5184+
* Get a dynptr to local memory *data*.
5185+
*
5186+
* *data* must be a ptr to a map value.
5187+
* The maximum *size* supported is DYNPTR_MAX_SIZE.
5188+
* *flags* is currently unused.
5189+
* Return
5190+
* 0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE,
5191+
* -EINVAL if flags is not 0.
51815192
*/
51825193
#define __BPF_FUNC_MAPPER(FN) \
51835194
FN(unspec), \
@@ -5377,6 +5388,7 @@ union bpf_attr {
53775388
FN(kptr_xchg), \
53785389
FN(map_lookup_percpu_elem), \
53795390
FN(skc_to_mptcp_sock), \
5391+
FN(dynptr_from_mem), \
53805392
/* */
53815393

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

0 commit comments

Comments
 (0)