Compare the fixed btf_record header and each btf_field explicitly instead of memcmp'ing the whole allocation at once. This is necessary for the follow-on patches which extend record contents with data outside fields but part of the record that can't be compared meaningfully. The comment is updated to reflect individual field comparison, and retain useful information about zeroing behavior, while referencing auxiliary data attached to records as a reason for the individual field comparison. The reference to auxiliary data attached to the record will be relevant with the next patches. Signed-off-by: Justin Suess --- kernel/bpf/syscall.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 3b1f0ba02f61..2caafce00f24 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -760,7 +760,8 @@ struct btf_record *btf_record_dup(const struct btf_record *rec) bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *rec_b) { bool a_has_fields = !IS_ERR_OR_NULL(rec_a), b_has_fields = !IS_ERR_OR_NULL(rec_b); - int size; + size_t size; + int i; if (!a_has_fields && !b_has_fields) return true; @@ -768,7 +769,6 @@ bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *r return false; if (rec_a->cnt != rec_b->cnt) return false; - size = struct_size(rec_a, fields, rec_a->cnt); /* btf_parse_fields uses kzalloc to allocate a btf_record, so unused * members are zeroed out. So memcmp is safe to do without worrying * about padding/unused fields. @@ -780,10 +780,24 @@ bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *r * * So while by default, we don't rely on the map BTF (which the records * were parsed from) matching for both records, which is not backwards - * compatible, in case list_head is part of it, we implicitly rely on - * that by way of depending on memcmp succeeding for it. + * compatible; in case list_head is part of a record, we implicitly + * rely on that by way of depending on memcmp succeeding for each + * individual field. + * + * Comparing the whole record may be incorrect due to auxiliary data + * attached to the record. */ - return !memcmp(rec_a, rec_b, size); + size = offsetof(struct btf_record, fields); + if (memcmp(rec_a, rec_b, size)) + return false; + + for (i = 0; i < rec_a->cnt; i++) { + if (memcmp(&rec_a->fields[i], &rec_b->fields[i], + sizeof(rec_a->fields[i]))) + return false; + } + + return true; } void bpf_obj_free_timer(const struct btf_record *rec, void *obj) -- 2.53.0