Commit 13bbbfbea759 ("bpf: Add bpf_dynptr_read and bpf_dynptr_write") added the bpf_dynptr_write() and bpf_dynptr_read() APIs. However, it will be needed for some dynptr types to pass in flags as well (e.g. when writing to a skb, the user may like to invalidate the hash or recompute the checksum). This patch adds a "u64 flags" arg to the bpf_dynptr_read() and bpf_dynptr_write() APIs before their UAPI signature freezes where we then cannot change them anymore with a 5.19.x released kernel.
Unified · Split
| @@ -5222,22 +5222,25 @@ union bpf_attr { · 5221 unmodified lines | |||
| 5222 | * Return | 5222 | * Return |
| 5223 | * Nothing. Always succeeds. | 5223 | * Nothing. Always succeeds. |
| 5224 | * | 5224 | * |
| 5225 | * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset) | 5225 | * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags) |
| 5226 | * Description | 5226 | * Description |
| 5227 | * Read *len* bytes from *src* into *dst*, starting from *offset* | 5227 | * Read *len* bytes from *src* into *dst*, starting from *offset* |
| 5228 | * into *src*. | 5228 | * into *src*. |
| 5229 | * *flags* is currently unused. | ||
| 5229 | * Return | 5230 | * Return |
| 5230 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length | 5231 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length |
| 5231 | * of *src*'s data, -EINVAL if *src* is an invalid dynptr. | 5232 | * of *src*'s data, -EINVAL if *src* is an invalid dynptr or if |
| 5233 | * *flags* is not 0. | ||
| 5232 | * | 5234 | * |
| 5233 | * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len) | 5235 | * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags) |
| 5234 | * Description | 5236 | * Description |
| 5235 | * Write *len* bytes from *src* into *dst*, starting from *offset* | 5237 | * Write *len* bytes from *src* into *dst*, starting from *offset* |
| 5236 | * into *dst*. | 5238 | * into *dst*. |
| 5239 | * *flags* is currently unused. | ||
| 5237 | * Return | 5240 | * Return |
| 5238 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length | 5241 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length |
| 5239 | * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* | 5242 | * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* |
| 5240 | * is a read-only dynptr. | 5243 | * is a read-only dynptr or if *flags* is not 0. |
| 5241 | * | 5244 | * |
| 5242 | * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len) | 5245 | * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len) |
| 5243 | * Description | 5246 | * Description |
| @@ -1497,11 +1497,12 @@ const struct bpf_func_proto bpf_dynptr_from_mem_proto = { · 1496 unmodified lines | |||
| 1497 | .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT, | 1497 | .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT, |
| 1498 | }; | 1498 | }; |
| 1499 | 1499 | ||
| 1500 | BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, u32, offset) | 1500 | BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, |
| 1501 | u32, offset, u64, flags) | ||
| 1501 | { | 1502 | { |
| 1502 | int err; | 1503 | int err; |
| 1503 | 1504 | ||
| 1504 | if (!src->data) | 1505 | if (!src->data || flags) |
| 1505 | return -EINVAL; | 1506 | return -EINVAL; |
| 1506 | 1507 | ||
| 1507 | err = bpf_dynptr_check_off_len(src, offset, len); | 1508 | err = bpf_dynptr_check_off_len(src, offset, len); |
| @@ -1521,13 +1522,15 @@ const struct bpf_func_proto bpf_dynptr_read_proto = { · 13 unmodified lines | |||
| 1521 | .arg2_type = ARG_CONST_SIZE_OR_ZERO, | 1522 | .arg2_type = ARG_CONST_SIZE_OR_ZERO, |
| 1522 | .arg3_type = ARG_PTR_TO_DYNPTR, | 1523 | .arg3_type = ARG_PTR_TO_DYNPTR, |
| 1523 | .arg4_type = ARG_ANYTHING, | 1524 | .arg4_type = ARG_ANYTHING, |
| 1525 | .arg5_type = ARG_ANYTHING, | ||
| 1524 | }; | 1526 | }; |
| 1525 | 1527 | ||
| 1526 | BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, u32, len) | 1528 | BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, |
| 1529 | u32, len, u64, flags) | ||
| 1527 | { | 1530 | { |
| 1528 | int err; | 1531 | int err; |
| 1529 | 1532 | ||
| 1530 | if (!dst->data || bpf_dynptr_is_rdonly(dst)) | 1533 | if (!dst->data || flags || bpf_dynptr_is_rdonly(dst)) |
| 1531 | return -EINVAL; | 1534 | return -EINVAL; |
| 1532 | 1535 | ||
| 1533 | err = bpf_dynptr_check_off_len(dst, offset, len); | 1536 | err = bpf_dynptr_check_off_len(dst, offset, len); |
| @@ -1547,6 +1550,7 @@ const struct bpf_func_proto bpf_dynptr_write_proto = { · 13 unmodified lines | |||
| 1547 | .arg2_type = ARG_ANYTHING, | 1550 | .arg2_type = ARG_ANYTHING, |
| 1548 | .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, | 1551 | .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, |
| 1549 | .arg4_type = ARG_CONST_SIZE_OR_ZERO, | 1552 | .arg4_type = ARG_CONST_SIZE_OR_ZERO, |
| 1553 | .arg5_type = ARG_ANYTHING, | ||
| 1550 | }; | 1554 | }; |
| 1551 | 1555 | ||
| 1552 | BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len) | 1556 | BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len) |
| @@ -5222,22 +5222,25 @@ union bpf_attr { · 5221 unmodified lines | |||
| 5222 | * Return | 5222 | * Return |
| 5223 | * Nothing. Always succeeds. | 5223 | * Nothing. Always succeeds. |
| 5224 | * | 5224 | * |
| 5225 | * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset) | 5225 | * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags) |
| 5226 | * Description | 5226 | * Description |
| 5227 | * Read *len* bytes from *src* into *dst*, starting from *offset* | 5227 | * Read *len* bytes from *src* into *dst*, starting from *offset* |
| 5228 | * into *src*. | 5228 | * into *src*. |
| 5229 | * *flags* is currently unused. | ||
| 5229 | * Return | 5230 | * Return |
| 5230 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length | 5231 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length |
| 5231 | * of *src*'s data, -EINVAL if *src* is an invalid dynptr. | 5232 | * of *src*'s data, -EINVAL if *src* is an invalid dynptr or if |
| 5233 | * *flags* is not 0. | ||
| 5232 | * | 5234 | * |
| 5233 | * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len) | 5235 | * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags) |
| 5234 | * Description | 5236 | * Description |
| 5235 | * Write *len* bytes from *src* into *dst*, starting from *offset* | 5237 | * Write *len* bytes from *src* into *dst*, starting from *offset* |
| 5236 | * into *dst*. | 5238 | * into *dst*. |
| 5239 | * *flags* is currently unused. | ||
| 5237 | * Return | 5240 | * Return |
| 5238 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length | 5241 | * 0 on success, -E2BIG if *offset* + *len* exceeds the length |
| 5239 | * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* | 5242 | * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* |
| 5240 | * is a read-only dynptr. | 5243 | * is a read-only dynptr or if *flags* is not 0. |
| 5241 | * | 5244 | * |
| 5242 | * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len) | 5245 | * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len) |
| 5243 | * Description | 5246 | * Description |
| @@ -140,12 +140,12 @@ int use_after_invalid(void *ctx) · 139 unmodified lines | |||
| 140 | 140 | ||
| 141 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr); | 141 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr); |
| 142 | 142 | ||
| 143 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0); | 143 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
| 144 | 144 | ||
| 145 | bpf_ringbuf_submit_dynptr(&ptr, 0); | 145 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
| 146 | 146 | ||
| 147 | /* this should fail */ | 147 | /* this should fail */ |
| 148 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0); | 148 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
| 149 | 149 | ||
| 150 | return 0; | 150 | return 0; |
| 151 | } | 151 | } |
| @@ -338,7 +338,7 @@ int invalid_helper2(void *ctx) · 186 unmodified lines | |||
| 338 | get_map_val_dynptr(&ptr); | 338 | get_map_val_dynptr(&ptr); |
| 339 | 339 | ||
| 340 | /* this should fail */ | 340 | /* this should fail */ |
| 341 | bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0); | 341 | bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0); |
| 342 | 342 | ||
| 343 | return 0; | 343 | return 0; |
| 344 | } | 344 | } |
| @@ -377,7 +377,7 @@ int invalid_write2(void *ctx) · 32 unmodified lines | |||
| 377 | memcpy((void *)&ptr + 8, &x, sizeof(x)); | 377 | memcpy((void *)&ptr + 8, &x, sizeof(x)); |
| 378 | 378 | ||
| 379 | /* this should fail */ | 379 | /* this should fail */ |
| 380 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0); | 380 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
| 381 | 381 | ||
| 382 | bpf_ringbuf_submit_dynptr(&ptr, 0); | 382 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
| 383 | 383 | ||
| @@ -473,7 +473,7 @@ int invalid_read2(void *ctx) · 89 unmodified lines | |||
| 473 | get_map_val_dynptr(&ptr); | 473 | get_map_val_dynptr(&ptr); |
| 474 | 474 | ||
| 475 | /* this should fail */ | 475 | /* this should fail */ |
| 476 | bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0); | 476 | bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0); |
| 477 | 477 | ||
| 478 | return 0; | 478 | return 0; |
| 479 | } | 479 | } |
| @@ -43,10 +43,10 @@ int test_read_write(void *ctx) · 42 unmodified lines | |||
| 43 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); | 43 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); |
| 44 | 44 | ||
| 45 | /* Write data into the dynptr */ | 45 | /* Write data into the dynptr */ |
| 46 | err = err ?: bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data)); | 46 | err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); |
| 47 | 47 | ||
| 48 | /* Read the data that was written into the dynptr */ | 48 | /* Read the data that was written into the dynptr */ |
| 49 | err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0); | 49 | err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
| 50 | 50 | ||
| 51 | /* Ensure the data we read matches the data we wrote */ | 51 | /* Ensure the data we read matches the data we wrote */ |
| 52 | for (i = 0; i < sizeof(read_data); i++) { | 52 | for (i = 0; i < sizeof(read_data); i++) { |