Context |
Check |
Description |
bpf/vmtest-bpf-next-VM_Test-5 |
success
|
Logs for aarch64-gcc / build-release
|
bpf/vmtest-bpf-next-VM_Test-2 |
success
|
Logs for Unittests
|
bpf/vmtest-bpf-next-VM_Test-3 |
success
|
Logs for Validate matrix.py
|
bpf/vmtest-bpf-next-VM_Test-0 |
success
|
Logs for Lint
|
bpf/vmtest-bpf-next-VM_Test-1 |
success
|
Logs for ShellCheck
|
bpf/vmtest-bpf-next-VM_Test-4 |
success
|
Logs for aarch64-gcc / build / build for aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-6 |
success
|
Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-9 |
success
|
Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-10 |
success
|
Logs for aarch64-gcc / veristat-kernel
|
bpf/vmtest-bpf-next-VM_Test-11 |
success
|
Logs for aarch64-gcc / veristat-meta
|
bpf/vmtest-bpf-next-VM_Test-12 |
success
|
Logs for s390x-gcc / build / build for s390x with gcc
|
bpf/vmtest-bpf-next-VM_Test-13 |
success
|
Logs for s390x-gcc / build-release
|
bpf/vmtest-bpf-next-VM_Test-16 |
success
|
Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
|
bpf/vmtest-bpf-next-VM_Test-17 |
success
|
Logs for s390x-gcc / veristat-kernel
|
bpf/vmtest-bpf-next-VM_Test-18 |
success
|
Logs for s390x-gcc / veristat-meta
|
bpf/vmtest-bpf-next-VM_Test-19 |
success
|
Logs for set-matrix
|
bpf/vmtest-bpf-next-VM_Test-20 |
fail
|
Logs for x86_64-gcc / build / build for x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-21 |
success
|
Logs for x86_64-gcc / build-release
|
bpf/vmtest-bpf-next-VM_Test-22 |
success
|
Logs for x86_64-gcc / test
|
bpf/vmtest-bpf-next-VM_Test-23 |
success
|
Logs for x86_64-gcc / veristat-kernel
|
bpf/vmtest-bpf-next-VM_Test-24 |
success
|
Logs for x86_64-gcc / veristat-meta
|
bpf/vmtest-bpf-next-VM_Test-25 |
fail
|
Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
|
bpf/vmtest-bpf-next-VM_Test-26 |
fail
|
Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
|
bpf/vmtest-bpf-next-VM_Test-27 |
success
|
Logs for x86_64-llvm-17 / test
|
bpf/vmtest-bpf-next-VM_Test-28 |
success
|
Logs for x86_64-llvm-17 / veristat-kernel
|
bpf/vmtest-bpf-next-VM_Test-29 |
success
|
Logs for x86_64-llvm-17 / veristat-meta
|
bpf/vmtest-bpf-next-VM_Test-30 |
fail
|
Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
|
bpf/vmtest-bpf-next-VM_Test-31 |
fail
|
Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
|
bpf/vmtest-bpf-next-VM_Test-32 |
success
|
Logs for x86_64-llvm-18 / test
|
bpf/vmtest-bpf-next-VM_Test-33 |
success
|
Logs for x86_64-llvm-18 / veristat-kernel
|
bpf/vmtest-bpf-next-VM_Test-34 |
success
|
Logs for x86_64-llvm-18 / veristat-meta
|
bpf/vmtest-bpf-next-PR |
fail
|
PR summary
|
bpf/vmtest-bpf-next-VM_Test-7 |
success
|
Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-8 |
success
|
Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-14 |
success
|
Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
|
bpf/vmtest-bpf-next-VM_Test-15 |
success
|
Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
|
netdev/series_format |
fail
|
Series longer than 15 patches
|
netdev/tree_selection |
success
|
Clearly marked for bpf-next, async
|
netdev/ynl |
success
|
Generated files up to date;
no warnings/errors;
no diff in generated;
|
netdev/fixes_present |
success
|
Fixes tag not required for -next series
|
netdev/header_inline |
success
|
No static functions without inline keyword in header files
|
netdev/build_32bit |
success
|
Errors and warnings before: 0 this patch: 0
|
netdev/build_tools |
success
|
No tools touched, skip
|
netdev/cc_maintainers |
success
|
CCed 13 of 13 maintainers
|
netdev/build_clang |
success
|
Errors and warnings before: 109 this patch: 109
|
netdev/verify_signedoff |
success
|
Signed-off-by tag matches author and committer
|
netdev/deprecated_api |
success
|
None detected
|
netdev/check_selftest |
success
|
No net selftest shell script
|
netdev/verify_fixes |
success
|
No Fixes tag
|
netdev/build_allmodconfig_warn |
success
|
Errors and warnings before: 10 this patch: 10
|
netdev/checkpatch |
warning
|
WARNING: line length of 100 exceeds 80 columns
WARNING: line length of 81 exceeds 80 columns
WARNING: line length of 83 exceeds 80 columns
WARNING: line length of 86 exceeds 80 columns
WARNING: line length of 87 exceeds 80 columns
WARNING: line length of 89 exceeds 80 columns
WARNING: line length of 91 exceeds 80 columns
WARNING: line length of 92 exceeds 80 columns
WARNING: line length of 93 exceeds 80 columns
WARNING: line length of 94 exceeds 80 columns
WARNING: line length of 95 exceeds 80 columns
WARNING: line length of 96 exceeds 80 columns
WARNING: line length of 98 exceeds 80 columns
WARNING: line length of 99 exceeds 80 columns
|
netdev/build_clang_rust |
success
|
No Rust files in patch. Skipping build
|
netdev/kdoc |
success
|
Errors and warnings before: 0 this patch: 0
|
netdev/source_inline |
success
|
Was 0 now: 0
|
@@ -7705,9 +7705,90 @@ static int allow_uninitialized_stack_range(struct bpf_verifier_env *env, int reg
return 1;
}
+struct dynptr_key_state {
+ const struct btf_record *rec;
+ const struct btf_field *cur_dynptr;
+ bool valid_dynptr_id;
+ int cur_dynptr_id;
+};
+
+static int init_dynptr_key_state(struct bpf_verifier_env *env, const struct btf_record *rec,
+ struct dynptr_key_state *state)
+{
+ unsigned int i;
+
+ /* Find the first dynptr in the dynptr-key */
+ for (i = 0; i < rec->cnt; i++) {
+ if (rec->fields[i].type == BPF_DYNPTR)
+ break;
+ }
+ if (i >= rec->cnt) {
+ verbose(env, "verifier bug: dynptr not found\n");
+ return -EFAULT;
+ }
+
+ state->rec = rec;
+ state->cur_dynptr = &rec->fields[i];
+ state->valid_dynptr_id = false;
+
+ return 0;
+}
+
+static int check_dynptr_key_access(struct bpf_verifier_env *env, struct dynptr_key_state *state,
+ struct bpf_reg_state *reg, u8 stype, int offset)
+{
+ const struct btf_field *dynptr = state->cur_dynptr;
+
+ /* Non-dynptr part before a dynptr or non-dynptr part after
+ * the last dynptr.
+ */
+ if (offset < dynptr->offset || offset >= dynptr->offset + dynptr->size) {
+ if (stype == STACK_DYNPTR) {
+ verbose(env,
+ "dynptr-key expects non-dynptr at offset %d cur_dynptr_offset %u\n",
+ offset, dynptr->offset);
+ return -EACCES;
+ }
+ } else {
+ if (stype != STACK_DYNPTR) {
+ verbose(env,
+ "dynptr-key expects dynptr at offset %d cur_dynptr_offset %u\n",
+ offset, dynptr->offset);
+ return -EACCES;
+ }
+
+ /* A dynptr is composed of parts from two dynptrs */
+ if (state->valid_dynptr_id && reg->id != state->cur_dynptr_id) {
+ verbose(env, "malformed dynptr-key at offset %d cur_dynptr_offset %u\n",
+ offset, dynptr->offset);
+ return -EACCES;
+ }
+ if (!state->valid_dynptr_id) {
+ state->valid_dynptr_id = true;
+ state->cur_dynptr_id = reg->id;
+ }
+
+ if (offset == dynptr->offset + dynptr->size - 1) {
+ const struct btf_record *rec = state->rec;
+ unsigned int i;
+
+ for (i = dynptr - rec->fields + 1; i < rec->cnt; i++) {
+ if (rec->fields[i].type == BPF_DYNPTR) {
+ state->cur_dynptr = &rec->fields[i];
+ state->valid_dynptr_id = false;
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
static int check_stack_range_initialized(struct bpf_verifier_env *env, int regno,
int min_off, int max_off, int access_size,
- enum bpf_access_type type)
+ enum bpf_access_type type,
+ struct dynptr_key_state *dynkey)
{
struct bpf_reg_state *reg = reg_state(env, regno);
struct bpf_func_state *state = func(env, reg);
@@ -7730,6 +7811,8 @@ static int check_stack_range_initialized(struct bpf_verifier_env *env, int regno
stype = &state->stack[spi].slot_type[slot % BPF_REG_SIZE];
if (*stype == STACK_MISC)
goto mark;
+ if (dynkey && *stype == STACK_DYNPTR)
+ goto mark;
if ((*stype == STACK_ZERO) ||
(*stype == STACK_INVALID && env->allow_uninit_stack)) {
if (clobber) {
@@ -7762,6 +7845,15 @@ static int check_stack_range_initialized(struct bpf_verifier_env *env, int regno
}
return -EACCES;
mark:
+ if (dynkey) {
+ int err = check_dynptr_key_access(env, dynkey,
+ &state->stack[spi].spilled_ptr,
+ *stype, i - min_off);
+
+ if (err)
+ return err;
+ }
+
/* reading any byte out of 8-byte 'spill_slot' will cause
* the whole slot to be marked as 'read'
*
@@ -7813,7 +7905,60 @@ static int check_stack_range_access(struct bpf_verifier_env *env, int regno, int
if (err > 0)
return 0;
- return check_stack_range_initialized(env, regno, min_off, max_off, access_size, type);
+ return check_stack_range_initialized(env, regno, min_off, max_off, access_size, type, NULL);
+}
+
+static int check_dynkey_stack_access_offset(struct bpf_verifier_env *env, int regno, int off)
+{
+ struct bpf_reg_state *reg = reg_state(env, regno);
+
+ if (!tnum_is_const(reg->var_off)) {
+ verbose(env, "R%d variable offset prohibited for dynptr-key\n", regno);
+ return -EACCES;
+ }
+
+ off = reg->var_off.value + off;
+ if (off % BPF_REG_SIZE) {
+ verbose(env, "R%d misaligned offset %d for dynptr-key\n", regno, off);
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+/* It is almost the same as check_stack_range_access(), except the following
+ * things:
+ * (1) no need to check whether access_size is zero (due to non-zero key_size)
+ * (2) disallow uninitialized stack range
+ * (3) need BPF_REG_SIZE-aligned access with fixed-size offset
+ * (4) need to check whether the layout of bpf_dynptr part and non-bpf_dynptr
+ * part in the stack range is the same as the layout of dynptr key
+ */
+static int check_dynkey_stack_range_access(struct bpf_verifier_env *env, int regno, int off,
+ int access_size, struct bpf_call_arg_meta *meta)
+{
+ enum bpf_access_type type = BPF_READ;
+ struct dynptr_key_state dynkey;
+ int err, min_off, max_off;
+
+ err = check_stack_access_within_bounds(env, regno, off, access_size, type);
+ if (err)
+ return err;
+
+ err = check_dynkey_stack_access_offset(env, regno, off);
+ if (err)
+ return err;
+
+ err = get_stack_access_range(env, regno, off, &min_off, &max_off);
+ if (err)
+ return err;
+
+ err = init_dynptr_key_state(env, meta->map_ptr->key_record, &dynkey);
+ if (err)
+ return err;
+
+ return check_stack_range_initialized(env, regno, min_off, max_off, access_size, type,
+ &dynkey);
}
static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
@@ -9383,13 +9528,26 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
verbose(env, "invalid map_ptr to access map->key\n");
return -EACCES;
}
+
key_size = meta->map_ptr->key_size;
- err = check_helper_mem_access(env, regno, key_size, BPF_READ, false, NULL);
+ /* Only allow PTR_TO_STACK for dynptr-key */
+ if (bpf_map_has_dynptr_key(meta->map_ptr)) {
+ if (base_type(reg->type) != PTR_TO_STACK) {
+ verbose(env, "map dynptr-key requires stack ptr but got %s\n",
+ reg_type_str(env, reg->type));
+ return -EACCES;
+ }
+ err = check_dynkey_stack_range_access(env, regno, reg->off, key_size, meta);
+ } else {
+ err = check_helper_mem_access(env, regno, key_size, BPF_READ, false, NULL);
+ if (!err) {
+ meta->const_map_key = get_constant_map_key(env, reg, key_size);
+ if (meta->const_map_key < 0 && meta->const_map_key != -EOPNOTSUPP)
+ err = meta->const_map_key;
+ }
+ }
if (err)
return err;
- meta->const_map_key = get_constant_map_key(env, reg, key_size);
- if (meta->const_map_key < 0 && meta->const_map_key != -EOPNOTSUPP)
- return meta->const_map_key;
break;
case ARG_PTR_TO_MAP_VALUE:
if (type_may_be_null(arg_type) && register_is_null(reg))