FAILED: patch "[PATCH] tracing/probes: Fix BTF kflag check for anonymous struct" failed to apply to 6.18-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x 47e93045a2db80d24f5fef65adecc6b2b32efa23
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090849-jawed-juggling-59e4@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 47e93045a2db80d24f5fef65adecc6b2b32efa23 Mon Sep 17 00:00:00 2001
From: "Masami Hiramatsu (Google)" <[email protected]>
Date: Tue, 1 Sep 2026 23:21:49 +0900
Subject: [PATCH] tracing/probes: Fix BTF kflag check for anonymous struct
member access
btf_find_struct_member() traverses into nested anonymous structures and unions to find a struct member. However, get_bitoffset_of_field() in trace_probe.c checked btf_type_kflag(type) using the outer parent type instead of the actual anonymous structure/union that directly contains the found member.
If the parent structure and anonymous structure have mismatched kflags (e.g., the parent has kflag=0 while the anonymous structure has kflag=1 because it contains bitfields), the bitfield size encoded in the upper 8 bits of member->offset is erroneously treated as part of the byte/bit offset, corrupting the resolved offset and failing to set last_bitsize. Similarly, btf_find_struct_member() pushed anonymous member offsets onto anon_stack without masking BTF_MEMBER_BIT_OFFSET() when kflag is set.
To fix this problem, update btf_find_struct_member() to return actual containing structure/union type via member_type, use appropriate __btf_member_bit_offset() to get bit offset, and use member_type for btf_type_kflag() in get_bitoffset_of_field().
kernel/trace/trace_btf.c +11 -8
@@ -61,16 +61,17 @@ struct btf_anon_stack {/* * Find a member of data structure/union by name and return it. -* Return NULL if not found, or -EINVAL if parameter is invalid. -* If the member is an member of anonymous union/structure, the offset -* of that anonymous union/structure is stored into @anon_offset. Caller -* can calculate the correct offset from the root data structure by -* adding anon_offset to the member's offset. +* Return NULL if not found, or ERR_PTR(-EINVAL) if parameter is invalid. +* If the member is a member of an anonymous union/structure, the bit offset +* of that anonymous union/structure is stored into @anon_offset. +* If @member_type is non-NULL, the actual containing structure/union type +* of the found member is stored into @member_type. */ const struct btf_member *btf_find_struct_member (struct btf *btf,const struct btf_type *type,const char *member_name, -u32 *anon_offset) +u32 *anon_offset, +const struct btf_type **member_type) {struct btf_anon_stack *anon_stack;const struct btf_member *member;
@@ -94,14 +95,16 @@ const struct btf_member *btf_find_struct_member(struct btf *btf,if (mtype &&btf_type_is_struct (mtype) && top <BTF_ANON_STACK_MAX ) { anon_stack[top].tid = tid; - anon_stack[top++].offset = - cur_offset + member->offset; + anon_stack[top++].offset = cur_offset + +__btf_member_bit_offset (type, member); } }else { name =btf_name_by_offset (btf, member->name_off);if (name && !strcmp (member_name, name)) {if (anon_offset) *anon_offset = cur_offset; +if (member_type) + *member_type = type; goto out; } }
kernel/trace/trace_btf.h +2 -1
@@ -8,4 +8,5 @@ const struct btf_param *btf_get_func_param(const struct btf_type *func_proto,const struct btf_member *btf_find_struct_member (struct btf *btf,const struct btf_type *type,const char *member_name, -u32 *anon_offset); +u32 *anon_offset, +const struct btf_type **member_type);
kernel/trace/trace_probe.c +3 -2
@@ -625,6 +625,7 @@ static int get_bitoffset_of_field(char **pfieldname, const struct btf_type **pty {const struct btf_type *type = *ptype;const struct btf_member *field; +const struct btf_type *mtype;struct btf *btf =ctx_btf (ctx);char *fieldname = *pfieldname;int bitoffs =0 ;
@@ -640,7 +641,7 @@ static int get_bitoffset_of_field(char **pfieldname, const struct btf_type **pty anon_offs =0 ; field =btf_find_struct_member (btf, type, fieldname, - &anon_offs); + &anon_offs, &mtype);if (IS_ERR (field)) {trace_probe_log_err (ctx->offset,BAD_BTF_TID );return PTR_ERR (field);
@@ -653,7 +654,7 @@ static int get_bitoffset_of_field(char **pfieldname, const struct btf_type **pty bitoffs += anon_offs;/* Accumulate the bit-offsets of the dot-connected fields */ -if (btf_type_kflag (type)) { +if (btf_type_kflag (mtype)) { bitoffs +=BTF_MEMBER_BIT_OFFSET (field->offset); ctx->last_bitsize =BTF_MEMBER_BITFIELD_SIZE (field->offset); }else {
Sasha Levin
maintainerPATCH 1/2 tracing/probes: ignore id update from btf_type_skip_modifiers
From: Martin Kaiser <[email protected]>
[ Upstream commit 823b37855829bc328d46102a56e4d0b2f7a3d0d1 ]
We can pass NULL as id pointer to btf_type_skip_modifiers if we do not need the id of the returned btf_type.
Stable-dep-of: 47e93045a2db ("tracing/probes: Fix BTF kflag check for anonymous struct member access")
--- kernel/trace/trace_probe.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
kernel/trace/trace_probe.c +5 -8
@@ -355,9 +355,8 @@ static bool btf_type_is_char_ptr(struct btf *btf, const struct btf_type *type) {const struct btf_type *real_type;u32 intdata; -s32 tid; - real_type =btf_type_skip_modifiers (btf, type->type, &tid); + real_type =btf_type_skip_modifiers (btf, type->type,NULL );if (!real_type)return false;
@@ -374,14 +373,13 @@ static bool btf_type_is_char_array(struct btf *btf, const struct btf_type *type)const struct btf_type *real_type;const struct btf_array *array;u32 intdata; -s32 tid;if (BTF_INFO_KIND (type->info) !=BTF_KIND_ARRAY )return false; array = (const struct btf_array *)(type +1 ); - real_type =btf_type_skip_modifiers (btf, array->type, &tid); + real_type =btf_type_skip_modifiers (btf, array->type,NULL ); intdata =btf_type_int (real_type);return !(BTF_INT_ENCODING (intdata) &BTF_INT_SIGNED )
@@ -584,7 +582,6 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type,struct btf *btf =ctx_btf (ctx);char *next;int is_ptr; -s32 tid; do { if (!is_struct) {
@@ -595,7 +592,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, }/* Convert a struct pointer type to a struct type */ - type =btf_type_skip_modifiers (btf, type->type, &tid); + type =btf_type_skip_modifiers (btf, type->type,NULL );if (!type) {trace_probe_log_err (ctx->offset,BAD_BTF_TID );return -EINVAL ;
@@ -635,7 +632,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, ctx->last_bitsize =0 ; } - type =btf_type_skip_modifiers (btf, field->type, &tid); + type =btf_type_skip_modifiers (btf, field->type,NULL );if (!type) {trace_probe_log_err (ctx->offset,BAD_BTF_TID );return -EINVAL ;
@@ -754,7 +751,7 @@ static int parse_btf_arg(char *varname,return -ENOENT ; found: - type =btf_type_skip_modifiers (ctx->btf, tid, &tid); + type =btf_type_skip_modifiers (ctx->btf, tid,NULL ); found_type:if (!type) {trace_probe_log_err (ctx->offset,BAD_BTF_TID );
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 tracing/probes: Fix BTF kflag check for anonymous struct member access
From: "Masami Hiramatsu (Google)" <[email protected]>
[ Upstream commit 47e93045a2db80d24f5fef65adecc6b2b32efa23 ]
btf_find_struct_member() traverses into nested anonymous structures and unions to find a struct member. However, get_bitoffset_of_field() in trace_probe.c checked btf_type_kflag(type) using the outer parent type instead of the actual anonymous structure/union that directly contains the found member.
If the parent structure and anonymous structure have mismatched kflags (e.g., the parent has kflag=0 while the anonymous structure has kflag=1 because it contains bitfields), the bitfield size encoded in the upper 8 bits of member->offset is erroneously treated as part of the byte/bit offset, corrupting the resolved offset and failing to set last_bitsize. Similarly, btf_find_struct_member() pushed anonymous member offsets onto anon_stack without masking BTF_MEMBER_BIT_OFFSET() when kflag is set.
To fix this problem, update btf_find_struct_member() to return actual containing structure/union type via member_type, use appropriate __btf_member_bit_offset() to get bit offset, and use member_type for btf_type_kflag() in get_bitoffset_of_field().
--- kernel/trace/trace_btf.c | 19 +++++++++++-------- kernel/trace/trace_btf.h | 3 ++- kernel/trace/trace_probe.c | 5 +++-- 3 files changed, 16 insertions(+), 11 deletions(-)
kernel/trace/trace_btf.c +11 -8
@@ -61,16 +61,17 @@ struct btf_anon_stack {/* * Find a member of data structure/union by name and return it. -* Return NULL if not found, or -EINVAL if parameter is invalid. -* If the member is an member of anonymous union/structure, the offset -* of that anonymous union/structure is stored into @anon_offset. Caller -* can calculate the correct offset from the root data structure by -* adding anon_offset to the member's offset. +* Return NULL if not found, or ERR_PTR(-EINVAL) if parameter is invalid. +* If the member is a member of an anonymous union/structure, the bit offset +* of that anonymous union/structure is stored into @anon_offset. +* If @member_type is non-NULL, the actual containing structure/union type +* of the found member is stored into @member_type. */ const struct btf_member *btf_find_struct_member (struct btf *btf,const struct btf_type *type,const char *member_name, -u32 *anon_offset) +u32 *anon_offset, +const struct btf_type **member_type) {struct btf_anon_stack *anon_stack;const struct btf_member *member;
@@ -94,14 +95,16 @@ const struct btf_member *btf_find_struct_member(struct btf *btf,if (btf_type_skip_modifiers (btf, member->type, &tid) && top <BTF_ANON_STACK_MAX ) { anon_stack[top].tid = tid; - anon_stack[top++].offset = - cur_offset + member->offset; + anon_stack[top++].offset = cur_offset + +__btf_member_bit_offset (type, member); } }else { name =btf_name_by_offset (btf, member->name_off);if (name && !strcmp (member_name, name)) {if (anon_offset) *anon_offset = cur_offset; +if (member_type) + *member_type = type; goto out; } }
kernel/trace/trace_btf.h +2 -1
@@ -8,4 +8,5 @@ const struct btf_param *btf_get_func_param(const struct btf_type *func_proto,const struct btf_member *btf_find_struct_member (struct btf *btf,const struct btf_type *type,const char *member_name, -u32 *anon_offset); +u32 *anon_offset, +const struct btf_type **member_type);
kernel/trace/trace_probe.c +3 -2
@@ -577,6 +577,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, {struct fetch_insn *code = *pcode;const struct btf_member *field; +const struct btf_type *mtype;u32 bitoffs, anon_offs;bool is_struct = ctx->struct_btf !=NULL ;struct btf *btf =ctx_btf (ctx);
@@ -611,7 +612,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, anon_offs =0 ; field =btf_find_struct_member (btf, type, fieldname, - &anon_offs); + &anon_offs, &mtype);if (IS_ERR (field)) {trace_probe_log_err (ctx->offset,BAD_BTF_TID );return PTR_ERR (field);
@@ -624,7 +625,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, bitoffs += anon_offs;/* Accumulate the bit-offsets of the dot-connected fields */ -if (btf_type_kflag (type)) { +if (btf_type_kflag (mtype)) { bitoffs +=BTF_MEMBER_BIT_OFFSET (field->offset); ctx->last_bitsize =BTF_MEMBER_BITFIELD_SIZE (field->offset); }else {
Signature · 1 line
2.53.0