/* not a flexible array, if not inside a struct or has non-zero size */ if (!acc->name || arr->nelems > 0) returnfalse;
/* has to be the last member of enclosing struct */
t = btf_type_by_id(btf, acc->type_id); return acc->idx == btf_vlen(t) - 1;
}
staticconstchar *core_relo_kind_str(enum bpf_core_relo_kind kind)
{ switch (kind) { case BPF_CORE_FIELD_BYTE_OFFSET: return"byte_off"; case BPF_CORE_FIELD_BYTE_SIZE: return"byte_sz"; case BPF_CORE_FIELD_EXISTS: return"field_exists"; case BPF_CORE_FIELD_SIGNED: return"signed"; case BPF_CORE_FIELD_LSHIFT_U64: return"lshift_u64"; case BPF_CORE_FIELD_RSHIFT_U64: return"rshift_u64"; case BPF_CORE_TYPE_ID_LOCAL: return"local_type_id"; case BPF_CORE_TYPE_ID_TARGET: return"target_type_id"; case BPF_CORE_TYPE_EXISTS: return"type_exists"; case BPF_CORE_TYPE_MATCHES: return"type_matches"; case BPF_CORE_TYPE_SIZE: return"type_size"; case BPF_CORE_ENUMVAL_EXISTS: return"enumval_exists"; case BPF_CORE_ENUMVAL_VALUE: return"enumval_value"; default: return"unknown";
}
}
staticbool core_relo_is_field_based(enum bpf_core_relo_kind kind)
{ switch (kind) { case BPF_CORE_FIELD_BYTE_OFFSET: case BPF_CORE_FIELD_BYTE_SIZE: case BPF_CORE_FIELD_EXISTS: case BPF_CORE_FIELD_SIGNED: case BPF_CORE_FIELD_LSHIFT_U64: case BPF_CORE_FIELD_RSHIFT_U64: returntrue; default: returnfalse;
}
}
staticbool core_relo_is_type_based(enum bpf_core_relo_kind kind)
{ switch (kind) { case BPF_CORE_TYPE_ID_LOCAL: case BPF_CORE_TYPE_ID_TARGET: case BPF_CORE_TYPE_EXISTS: case BPF_CORE_TYPE_MATCHES: case BPF_CORE_TYPE_SIZE: returntrue; default: returnfalse;
}
}
staticbool core_relo_is_enumval_based(enum bpf_core_relo_kind kind)
{ switch (kind) { case BPF_CORE_ENUMVAL_EXISTS: case BPF_CORE_ENUMVAL_VALUE: returntrue; default: returnfalse;
}
}
int __bpf_core_types_are_compat(conststruct btf *local_btf, __u32 local_id, conststruct btf *targ_btf, __u32 targ_id, int level)
{ conststruct btf_type *local_type, *targ_type; int depth = 32; /* max recursion depth */
/* caller made sure that names match (ignoring flavor suffix) */
local_type = btf_type_by_id(local_btf, local_id);
targ_type = btf_type_by_id(targ_btf, targ_id); if (!btf_kind_core_compat(local_type, targ_type)) return0;
/* type-based relocations don't have a field access string */ if (core_relo_is_type_based(relo->kind)) { if (strcmp(spec_str, "0")) return -EINVAL; return0;
}
/* parse spec_str="0:1:2:3:4" into array raw_spec=[0, 1, 2, 3, 4] */ while (*spec_str) { if (*spec_str == ':')
++spec_str; if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) return -EINVAL; if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) return -E2BIG;
spec_str += parsed_len;
spec->raw_spec[spec->raw_len++] = access_idx;
}
if (spec->raw_len == 0) return -EINVAL;
t = skip_mods_and_typedefs(btf, relo->type_id, &id); if (!t) return -EINVAL;
if (core_relo_is_enumval_based(relo->kind)) { if (!btf_is_any_enum(t) || spec->raw_len > 1 || access_idx >= btf_vlen(t)) return -EINVAL;
/* record enumerator name in a first accessor */
name_off = btf_is_enum(t) ? btf_enum(t)[access_idx].name_off
: btf_enum64(t)[access_idx].name_off;
acc->name = btf__name_by_offset(btf, name_off); return0;
}
if (!core_relo_is_field_based(relo->kind)) return -EINVAL;
if (btf_is_composite(local_type) && btf_is_composite(targ_type)) return1; if (!btf_kind_core_compat(local_type, targ_type)) return0;
switch (btf_kind(local_type)) { case BTF_KIND_PTR: case BTF_KIND_FLOAT: return1; case BTF_KIND_FWD: case BTF_KIND_ENUM64: case BTF_KIND_ENUM: { constchar *local_name, *targ_name;
size_t local_len, targ_len;
local_name = btf__name_by_offset(local_btf,
local_type->name_off);
targ_name = btf__name_by_offset(targ_btf, targ_type->name_off);
local_len = bpf_core_essential_name_len(local_name);
targ_len = bpf_core_essential_name_len(targ_name); /* one of them is anonymous or both w/ same flavor-less names */ return local_len == 0 || targ_len == 0 ||
(local_len == targ_len &&
strncmp(local_name, targ_name, local_len) == 0);
} case BTF_KIND_INT: /* just reject deprecated bitfield-like integers; all other *integersarebydefaultcompatiblebetweeneachother
*/ return btf_int_offset(local_type) == 0 &&
btf_int_offset(targ_type) == 0; case BTF_KIND_ARRAY:
local_id = btf_array(local_type)->type;
targ_id = btf_array(targ_type)->type; goto recur; default: return0;
}
}
n = btf_vlen(targ_type);
m = btf_members(targ_type); for (i = 0; i < n; i++, m++) {
__u32 bit_offset;
bit_offset = btf_member_bit_offset(targ_type, i);
/* too deep struct/union/array nesting */ if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) return -E2BIG;
/* speculate this member will be the good one */
spec->bit_offset += bit_offset;
spec->raw_spec[spec->raw_len++] = i;
targ_name = btf__name_by_offset(targ_btf, m->name_off); if (str_is_empty(targ_name)) { /* embedded struct/union, we need to go deeper */
found = bpf_core_match_member(local_btf, local_acc,
targ_btf, m->type,
spec, next_targ_id); if (found) /* either found or error */ return found;
} elseif (strcmp(local_name, targ_name) == 0) { /* matching named field */ struct bpf_core_accessor *targ_acc;
*next_targ_id = m->type;
found = bpf_core_fields_are_compat(local_btf,
local_member->type,
targ_btf, m->type); if (!found)
spec->len--; /* pop accessor */ return found;
} /* member turned out not to be what we looked for */
spec->bit_offset -= bit_offset;
spec->raw_len--;
}
for (i = 0; i < btf_vlen(targ_type); i++) { if (btf_is_enum(targ_type))
name_off = btf_enum(targ_type)[i].name_off; else
name_off = btf_enum64(targ_type)[i].name_off;
if (!core_relo_is_field_based(local_spec->relo_kind)) return -EINVAL;
for (i = 0; i < local_spec->len; i++, local_acc++, targ_acc++) {
targ_type = skip_mods_and_typedefs(targ_spec->btf, targ_id,
&targ_id); if (!targ_type) return -EINVAL;
if (local_acc->name) {
matched = bpf_core_match_member(local_spec->btf,
local_acc,
targ_btf, targ_id,
targ_spec, &targ_id); if (matched <= 0) return matched;
} else { /* for i=0, targ_id is already treated as array element *type(becauseit'stheoriginalstruct),forothers *weshouldfindarrayelementtypefirst
*/ if (i > 0) { conststruct btf_array *a; bool flex;
if (!btf_is_array(targ_type)) return0;
a = btf_array(targ_type);
flex = is_flex_arr(targ_btf, targ_acc - 1, a); if (!flex && local_acc->idx >= a->nelems) return0; if (!skip_mods_and_typedefs(targ_btf, a->type,
&targ_id)) return -EINVAL;
}
/* too deep struct/union/array nesting */ if (targ_spec->raw_len == BPF_CORE_SPEC_MAX_LEN) return -E2BIG;
bitfield = bit_sz > 0; if (bitfield) {
byte_sz = mt->size;
byte_off = bit_off / 8 / byte_sz * byte_sz; /* figure out smallest int size necessary for bitfield load */ while (bit_off + bit_sz - byte_off * 8 > byte_sz * 8) { if (byte_sz >= 8) { /* bitfield can't be read with 64-bit read */
pr_warn("prog '%s': relo %d at insn #%d can't be satisfied for bitfield\n",
prog_name, relo->kind, relo->insn_off / 8); return -E2BIG;
}
byte_sz *= 2;
byte_off = bit_off / 8 / byte_sz * byte_sz;
}
} else {
sz = btf__resolve_size(spec->btf, field_type_id); if (sz < 0) return -EINVAL;
byte_sz = sz;
byte_off = spec->bit_offset / 8;
bit_sz = byte_sz * 8;
}
/* for bitfields, all the relocatable aspects are ambiguous and we *mightdisagreewithcompiler,soturnoffvalidationofexpected *value,exceptforsignedness
*/ if (validate)
*validate = !bitfield;
switch (relo->kind) { case BPF_CORE_FIELD_BYTE_OFFSET:
*val = byte_off; if (!bitfield) { /* remember field size for load/store mem size; *note,forarrayswecareaboutindividualelement *sizes,nottheoverallarraysize
*/
t = skip_mods_and_typedefs(spec->btf, field_type_id, &elem_id); while (btf_is_array(t))
t = skip_mods_and_typedefs(spec->btf, btf_array(t)->type, &elem_id);
sz = btf__resolve_size(spec->btf, elem_id); if (sz < 0) return -EINVAL;
*field_sz = sz;
*type_id = field_type_id;
} break; case BPF_CORE_FIELD_BYTE_SIZE:
*val = byte_sz; break; case BPF_CORE_FIELD_SIGNED:
*val = (btf_is_any_enum(mt) && BTF_INFO_KFLAG(mt->info)) ||
(btf_is_int(mt) && (btf_int_encoding(mt) & BTF_INT_SIGNED)); if (validate)
*validate = true; /* signedness is never ambiguous */ break; case BPF_CORE_FIELD_LSHIFT_U64: #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
*val = 64 - (bit_off + bit_sz - byte_off * 8); #else
*val = (8 - byte_sz) * 8 + (bit_off - byte_off * 8); #endif break; case BPF_CORE_FIELD_RSHIFT_U64:
*val = 64 - bit_sz; if (validate)
*validate = true; /* right shift is never ambiguous */ break; case BPF_CORE_FIELD_EXISTS: default: return -EOPNOTSUPP;
}
/* by default, always check expected value in bpf_insn */ if (validate)
*validate = true;
/* type-based relos return zero when target type is not found */ if (!spec) {
*val = 0; return0;
}
switch (relo->kind) { case BPF_CORE_TYPE_ID_TARGET:
*val = spec->root_type_id; /* type ID, embedded in bpf_insn, might change during linking, *soenforcingitispointless
*/ if (validate)
*validate = false; break; case BPF_CORE_TYPE_EXISTS: case BPF_CORE_TYPE_MATCHES:
*val = 1; break; case BPF_CORE_TYPE_SIZE:
sz = btf__resolve_size(spec->btf, spec->root_type_id); if (sz < 0) return -EINVAL;
*val = sz; break; case BPF_CORE_TYPE_ID_LOCAL: /* BPF_CORE_TYPE_ID_LOCAL is handled specially and shouldn't get here */ default: return -EOPNOTSUPP;
}
/* There are two use cases in which it's safe to *adjustload/store'smemsize: *-readinga32-bitkernelpointer,whileonBPF *sizepointersarealways64-bit;inthiscase *it'ssafeto"downsize"instructionsizedueto *pointerbeingtreatedasunsignedintegerwith *zero-extendedupper32-bits; *-readingunsignedintegers,againdueto *zero-extensionispreservingthevaluecorrectly. * *Inallothercasesit'sincorrecttoattemptto *load/storefieldbecausereadvaluewillbe *incorrect,sowepoisonrelocatedinstruction.
*/ if (btf_is_ptr(orig_t) && btf_is_ptr(new_t)) goto done; if (btf_is_int(orig_t) && btf_is_int(new_t) &&
btf_int_encoding(orig_t) != BTF_INT_SIGNED &&
btf_int_encoding(new_t) != BTF_INT_SIGNED) goto done;
/* mark as invalid mem size adjustment, but this will *onlybecheckedforLDX/STX/STinsns
*/
res->fail_memsz_adjust = true;
}
} elseif (core_relo_is_type_based(relo->kind)) {
err = bpf_core_calc_type_relo(relo, local_spec, &res->orig_val, &res->validate);
err = err ?: bpf_core_calc_type_relo(relo, targ_spec, &res->new_val, NULL);
} elseif (core_relo_is_enumval_based(relo->kind)) {
err = bpf_core_calc_enumval_relo(relo, local_spec, &res->orig_val);
err = err ?: bpf_core_calc_enumval_relo(relo, targ_spec, &res->new_val);
}
done: if (err == -EUCLEAN) { /* EUCLEAN is used to signal instruction poisoning request */
res->poison = true;
err = 0;
} elseif (err == -EOPNOTSUPP) { /* EOPNOTSUPP means unknown/unsupported relocation */
pr_warn("prog '%s': relo #%d: unrecognized CO-RE relocation %s (%d) at insn #%d\n",
prog_name, relo_idx, core_relo_kind_str(relo->kind),
relo->kind, relo->insn_off / 8);
}
return err;
}
/* *TurninstructionforwhichCO_RErelocationfailedintoinvalidonewith *distinctsignature.
*/ staticvoid bpf_core_poison_insn(constchar *prog_name, int relo_idx, int insn_idx, struct bpf_insn *insn)
{
pr_debug("prog '%s': relo #%d: substituting insn #%d w/ invalid insn\n",
prog_name, relo_idx, insn_idx);
insn->code = BPF_JMP | BPF_CALL;
insn->dst_reg = 0;
insn->src_reg = 0;
insn->off = 0; /* if this instruction is reachable (not a dead code), *verifierwillcomplainwiththefollowingmessage: *invalidfuncunknown#195896080
*/
insn->imm = 195896080; /* => 0xbad2310 => "bad relo" */
}
staticint insn_bpf_size_to_bytes(struct bpf_insn *insn)
{ switch (BPF_SIZE(insn->code)) { case BPF_DW: return8; case BPF_W: return4; case BPF_H: return2; case BPF_B: return1; default: return -1;
}
}
if (res->poison) {
poison: /* poison second part of ldimm64 to avoid confusing error from *verifierabout"unknownopcode00"
*/ if (is_ldimm64_insn(insn))
bpf_core_poison_insn(prog_name, relo_idx, insn_idx + 1, insn + 1);
bpf_core_poison_insn(prog_name, relo_idx, insn_idx, insn); return0;
}
orig_val = res->orig_val;
new_val = res->new_val;
switch (class) { case BPF_ALU: case BPF_ALU64: if (BPF_SRC(insn->code) != BPF_K) return -EINVAL; if (res->validate && insn->imm != orig_val) {
pr_warn("prog '%s': relo #%d: unexpected insn #%d (ALU/ALU64) value: got %u, exp %llu -> %llu\n",
prog_name, relo_idx,
insn_idx, insn->imm, (unsignedlonglong)orig_val,
(unsignedlonglong)new_val); return -EINVAL;
}
orig_val = insn->imm;
insn->imm = new_val;
pr_debug("prog '%s': relo #%d: patched insn #%d (ALU/ALU64) imm %llu -> %llu\n",
prog_name, relo_idx, insn_idx,
(unsignedlonglong)orig_val, (unsignedlonglong)new_val); break; case BPF_LDX: case BPF_ST: case BPF_STX: if (res->validate && insn->off != orig_val) {
pr_warn("prog '%s': relo #%d: unexpected insn #%d (LDX/ST/STX) value: got %u, exp %llu -> %llu\n",
prog_name, relo_idx, insn_idx, insn->off, (unsignedlonglong)orig_val,
(unsignedlonglong)new_val); return -EINVAL;
} if (new_val > SHRT_MAX) {
pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) value too big: %llu\n",
prog_name, relo_idx, insn_idx, (unsignedlonglong)new_val); return -ERANGE;
} if (res->fail_memsz_adjust) {
pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) accesses field incorrectly. " "Make sure you are accessing pointers, unsigned integers, or fields of matching type and size.\n",
prog_name, relo_idx, insn_idx); goto poison;
}
if (core_relo_is_field_based(spec->relo_kind)) { for (i = 0; i < spec->len; i++) { if (spec->spec[i].name)
append_buf(".%s", spec->spec[i].name); elseif (i > 0 || spec->spec[i].idx > 0)
append_buf("[%u]", spec->spec[i].idx);
}
append_buf(" ("); for (i = 0; i < spec->raw_len; i++)
append_buf("%s%d", i == 0 ? "" : ":", spec->raw_spec[i]);
/* TYPE_ID_LOCAL relo is special and doesn't need candidate search */ if (relo->kind == BPF_CORE_TYPE_ID_LOCAL) { /* bpf_insn's imm value could get out of sync during linking */
memset(targ_res, 0, sizeof(*targ_res));
targ_res->validate = false;
targ_res->poison = false;
targ_res->orig_val = local_spec->root_type_id;
targ_res->new_val = local_spec->root_type_id; return0;
}
/* libbpf doesn't support candidate search for anonymous types */ if (str_is_empty(local_name)) {
pr_warn("prog '%s': relo #%d: <%s> (%d) relocation doesn't support anonymous types\n",
prog_name, relo_idx, core_relo_kind_str(relo->kind), relo->kind); return -EOPNOTSUPP;
}
for (i = 0, j = 0; i < cands->len; i++) {
err = bpf_core_spec_match(local_spec, cands->cands[i].btf,
cands->cands[i].id, cand_spec); if (err < 0) {
bpf_core_format_spec(spec_buf, sizeof(spec_buf), cand_spec);
pr_warn("prog '%s': relo #%d: error matching candidate #%d %s: %d\n",
prog_name, relo_idx, i, spec_buf, err); return err;
}
/* iterate over the local enum's variants and make sure each has *asymbolicnamecorrespondentinthetarget
*/ for (i = 0; i < local_vlen; i++) { bool matched = false;
__u32 local_n_off, targ_n_off;
/* check that all local members have a match in the target */ for (i = 0; i < local_vlen; i++, local_m++) { conststruct btf_member *targ_m = btf_members(targ_t); bool matched = false;
for (j = 0; j < targ_vlen; j++, targ_m++) { if (!bpf_core_names_match(local_btf, local_m->name_off,
targ_btf, targ_m->name_off)) continue;
/* While the name check happens after typedefs are skipped, root-level *typedefswouldstillbename-matchedasthat'sthecontractwith *callers.
*/ if (!bpf_core_names_match(local_btf, local_t->name_off, targ_btf, targ_t->name_off)) return0;
switch (local_k) { case BTF_KIND_UNKN: return local_k == targ_k; case BTF_KIND_FWD: { bool local_f = BTF_INFO_KFLAG(local_t->info);
if (behind_ptr) { if (local_k == targ_k) return local_f == BTF_INFO_KFLAG(targ_t->info);
/* for forward declarations kflag dictates whether the *targetisastruct(0)orunion(1)
*/ return (targ_k == BTF_KIND_STRUCT && !local_f) ||
(targ_k == BTF_KIND_UNION && local_f);
} else { if (local_k != targ_k) return0;
/* match if the forward declaration is for the same kind */ return local_f == BTF_INFO_KFLAG(targ_t->info);
}
} case BTF_KIND_ENUM: case BTF_KIND_ENUM64: if (!btf_is_any_enum(targ_t)) return0;
return bpf_core_enums_match(local_btf, local_t, targ_btf, targ_t); case BTF_KIND_STRUCT: case BTF_KIND_UNION: if (behind_ptr) { bool targ_f = BTF_INFO_KFLAG(targ_t->info);
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.107Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.