Skip to content

Commit 10ca6ef

Browse files
joannekoongNobody
authored and
Nobody
committed
bpf: Add bpf_dynptr_read and bpf_dynptr_write
This patch adds two helper functions, bpf_dynptr_read and bpf_dynptr_write: long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset); long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len); The dynptr passed into these functions must be valid dynptrs that have been initialized. Signed-off-by: Joanne Koong <[email protected]>
1 parent ce79bc3 commit 10ca6ef

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

include/linux/bpf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,6 +2426,12 @@ enum bpf_dynptr_type {
24262426
#define DYNPTR_MAX_SIZE ((1UL << 28) - 1)
24272427
#define DYNPTR_SIZE_MASK 0xFFFFFFF
24282428
#define DYNPTR_TYPE_SHIFT 29
2429+
#define DYNPTR_RDONLY_BIT BIT(28)
2430+
2431+
static inline bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr)
2432+
{
2433+
return ptr->size & DYNPTR_RDONLY_BIT;
2434+
}
24292435

24302436
static inline enum bpf_dynptr_type bpf_dynptr_get_type(struct bpf_dynptr_kern *ptr)
24312437
{

include/uapi/linux/bpf.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,6 +5175,22 @@ union bpf_attr {
51755175
* After this operation, *ptr* will be an invalidated dynptr.
51765176
* Return
51775177
* Void.
5178+
*
5179+
* long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
5180+
* Description
5181+
* Read *len* bytes from *src* into *dst*, starting from *offset*
5182+
* into *dst*.
5183+
* Return
5184+
* 0 on success, -EINVAL if *offset* + *len* exceeds the length
5185+
* of *src*'s data or if *src* is an invalid dynptr.
5186+
*
5187+
* long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
5188+
* Description
5189+
* Write *len* bytes from *src* into *dst*, starting from *offset*
5190+
* into *dst*.
5191+
* Return
5192+
* 0 on success, -EINVAL if *offset* + *len* exceeds the length
5193+
* of *dst*'s data or if *dst* is not writeable.
51785194
*/
51795195
#define __BPF_FUNC_MAPPER(FN) \
51805196
FN(unspec), \
@@ -5374,6 +5390,8 @@ union bpf_attr {
53745390
FN(dynptr_from_mem), \
53755391
FN(malloc), \
53765392
FN(free), \
5393+
FN(dynptr_read), \
5394+
FN(dynptr_write), \
53775395
/* */
53785396

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

kernel/bpf/helpers.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,58 @@ const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
14121412
.arg3_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
14131413
};
14141414

1415+
BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, u32, offset)
1416+
{
1417+
int err;
1418+
1419+
if (!src->data)
1420+
return -EINVAL;
1421+
1422+
err = bpf_dynptr_check_off_len(src, offset, len);
1423+
if (err)
1424+
return err;
1425+
1426+
memcpy(dst, src->data + src->offset + offset, len);
1427+
1428+
return 0;
1429+
}
1430+
1431+
const struct bpf_func_proto bpf_dynptr_read_proto = {
1432+
.func = bpf_dynptr_read,
1433+
.gpl_only = false,
1434+
.ret_type = RET_INTEGER,
1435+
.arg1_type = ARG_PTR_TO_MEM_UNINIT,
1436+
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
1437+
.arg3_type = ARG_PTR_TO_DYNPTR,
1438+
.arg4_type = ARG_ANYTHING,
1439+
};
1440+
1441+
BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, u32, len)
1442+
{
1443+
int err;
1444+
1445+
if (!dst->data || bpf_dynptr_is_rdonly(dst))
1446+
return -EINVAL;
1447+
1448+
err = bpf_dynptr_check_off_len(dst, offset, len);
1449+
if (err)
1450+
return err;
1451+
1452+
memcpy(dst->data + dst->offset + offset, src, len);
1453+
1454+
return 0;
1455+
}
1456+
1457+
const struct bpf_func_proto bpf_dynptr_write_proto = {
1458+
.func = bpf_dynptr_write,
1459+
.gpl_only = false,
1460+
.ret_type = RET_INTEGER,
1461+
.arg1_type = ARG_PTR_TO_DYNPTR,
1462+
.arg2_type = ARG_ANYTHING,
1463+
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
1464+
.arg4_type = ARG_CONST_SIZE_OR_ZERO,
1465+
};
1466+
14151467
BPF_CALL_2(bpf_malloc, u32, size, struct bpf_dynptr_kern *, ptr)
14161468
{
14171469
void *data;
@@ -1514,6 +1566,10 @@ bpf_base_func_proto(enum bpf_func_id func_id)
15141566
return &bpf_malloc_proto;
15151567
case BPF_FUNC_free:
15161568
return &bpf_free_proto;
1569+
case BPF_FUNC_dynptr_read:
1570+
return &bpf_dynptr_read_proto;
1571+
case BPF_FUNC_dynptr_write:
1572+
return &bpf_dynptr_write_proto;
15171573
default:
15181574
break;
15191575
}

tools/include/uapi/linux/bpf.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,6 +5175,22 @@ union bpf_attr {
51755175
* After this operation, *ptr* will be an invalidated dynptr.
51765176
* Return
51775177
* Void.
5178+
*
5179+
* long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
5180+
* Description
5181+
* Read *len* bytes from *src* into *dst*, starting from *offset*
5182+
* into *dst*.
5183+
* Return
5184+
* 0 on success, -EINVAL if *offset* + *len* exceeds the length
5185+
* of *src*'s data or if *src* is an invalid dynptr.
5186+
*
5187+
* long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
5188+
* Description
5189+
* Write *len* bytes from *src* into *dst*, starting from *offset*
5190+
* into *dst*.
5191+
* Return
5192+
* 0 on success, -EINVAL if *offset* + *len* exceeds the length
5193+
* of *dst*'s data or if *dst* is not writeable.
51785194
*/
51795195
#define __BPF_FUNC_MAPPER(FN) \
51805196
FN(unspec), \
@@ -5374,6 +5390,8 @@ union bpf_attr {
53745390
FN(dynptr_from_mem), \
53755391
FN(malloc), \
53765392
FN(free), \
5393+
FN(dynptr_read), \
5394+
FN(dynptr_write), \
53775395
/* */
53785396

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

0 commit comments

Comments
 (0)