From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
To: Steven Rostedt <rostedt@goodmis.org>,
Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org
Subject: [PATCH 03/12] tracing/probes: Fix BTF bitfield parsing and out-of-bounds buffer write
Date: Mon, 9 Nov 2026 09:28:32 +0900 [thread overview]
Message-ID: <179418411197.227715.5577722703946865281.stgit@devnote2> (raw)
In-Reply-To: <179418408457.227715.1485179201014819821.stgit@devnote2>
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
BTF bitfield parsing in trace_probe.c assumes a 64-bit (8-byte) container
when computing FETCH_OP_MOD_BF shift amounts and basesize, whereas the
preceding store instruction only allocates and writes the field's fetch
type size (which may be 1, 2, or 4 bytes when kflag=1). At runtime,
fetch_apply_bitfield() performs an 8-byte read-modify-write on the
smaller ring buffer slot, corrupting adjacent ring buffer data or writing
past the end of the event record.
In addition, signed bitfields with bit widths other than 8/16/32/64 fail
to resolve a fetch type, bitfields whose width is a multiple of 8 inside
a larger integer or spanning a byte boundary fail to emit FETCH_OP_MOD_BF
or select a container wide enough for bitoffs + bitsize, and kflag=0
bitfield offsets >= 8 bits are not folded into the byte offset.
Compute the bitfield byte and bit offsets consistently during field
lookup, select the smallest unsigned fetch type that covers the bit
offset and bit width, and calculate the FETCH_OP_MOD_BF parameters from
the selected fetch type size.
Fixes: c440adfbe302 ("tracing/probes: Support BTF based data structure field access")
Cc: stable@vger.kernel.org
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
kernel/trace/trace_probe.c | 55 +++++++++++++++++++++++++++++++++-----------
1 file changed, 41 insertions(+), 14 deletions(-)
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index a880a90642d7..26e02929f1ff 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -486,6 +486,18 @@ static const char *fetch_type_from_btf_type(struct btf *btf,
{
u32 intdata;
+ if (ctx->last_bitsize) {
+ u32 bits = ctx->last_bitsize + ctx->last_bitoffs;
+
+ if (bits <= 8)
+ return "u8";
+ if (bits <= 16)
+ return "u16";
+ if (bits <= 32)
+ return "u32";
+ return "u64";
+ }
+
/* TODO: const char * could be converted as a string */
switch (BTF_INFO_KIND(type->info)) {
case BTF_KIND_ENUM:
@@ -520,10 +532,6 @@ static const char *fetch_type_from_btf_type(struct btf *btf,
case 64:
return "u64";
}
- /* bitfield, size is encoded in the type */
- ctx->last_bitsize = BTF_INT_BITS(intdata);
- ctx->last_bitoffs += BTF_INT_OFFSET(intdata);
- return "u64";
}
}
/* TODO: support other types */
@@ -653,6 +661,12 @@ static int get_bitoffset_of_field(char **pfieldname, const struct btf_type **pty
/* Add anonymous structure/union offset */
bitoffs += anon_offs;
+ type = btf_type_skip_modifiers(btf, field->type, NULL);
+ if (!type) {
+ trace_probe_log_err(ctx->offset, BAD_BTF_TID);
+ return -EINVAL;
+ }
+
/* Accumulate the bit-offsets of the dot-connected fields */
if (btf_type_kflag(container_type)) {
bitoffs += BTF_MEMBER_BIT_OFFSET(field->offset);
@@ -660,12 +674,15 @@ static int get_bitoffset_of_field(char **pfieldname, const struct btf_type **pty
} else {
bitoffs += field->offset;
ctx->last_bitsize = 0;
- }
+ if (BTF_INFO_KIND(type->info) == BTF_KIND_INT) {
+ u32 intdata = btf_type_int(type);
- type = btf_type_skip_modifiers(btf, field->type, NULL);
- if (!type) {
- trace_probe_log_err(ctx->offset, BAD_BTF_TID);
- return -EINVAL;
+ if (BTF_INT_OFFSET(intdata) ||
+ BTF_INT_BITS(intdata) != BYTES_TO_BITS(type->size)) {
+ bitoffs += BTF_INT_OFFSET(intdata);
+ ctx->last_bitsize = BTF_INT_BITS(intdata);
+ }
+ }
}
if (next)
@@ -858,13 +875,22 @@ static const struct fetch_type *find_fetch_type_from_btf_type(
}
static int parse_btf_bitfield(struct fetch_insn **pcode,
+ const struct fetch_type *t,
struct traceprobe_parse_context *ctx)
{
struct fetch_insn *code = *pcode;
- if ((ctx->last_bitsize % 8 == 0) && ctx->last_bitoffs == 0)
+ if ((ctx->last_bitsize == 0 ||
+ ctx->last_bitsize == BYTES_TO_BITS(t->size)) &&
+ ctx->last_bitoffs == 0)
return 0;
+ if (ctx->last_bitsize == 0 ||
+ BYTES_TO_BITS(t->size) < (ctx->last_bitsize + ctx->last_bitoffs)) {
+ trace_probe_log_err(ctx->offset, BAD_BITFIELD);
+ return -EINVAL;
+ }
+
code++;
if (code->op != FETCH_OP_NOP) {
trace_probe_log_err(ctx->offset, TOO_MANY_OPS);
@@ -873,9 +899,9 @@ static int parse_btf_bitfield(struct fetch_insn **pcode,
*pcode = code;
code->op = FETCH_OP_MOD_BF;
- code->lshift = 64 - (ctx->last_bitsize + ctx->last_bitoffs);
- code->rshift = 64 - ctx->last_bitsize;
- code->basesize = 64 / 8;
+ code->lshift = BYTES_TO_BITS(t->size) - (ctx->last_bitsize + ctx->last_bitoffs);
+ code->rshift = BYTES_TO_BITS(t->size) - ctx->last_bitsize;
+ code->basesize = t->size;
return 0;
}
@@ -1085,6 +1111,7 @@ static int parse_btf_arg(char *varname,
}
static int parse_btf_bitfield(struct fetch_insn **pcode,
+ const struct fetch_type *t,
struct traceprobe_parse_context *ctx)
{
trace_probe_log_err(ctx->offset, NOSUP_BTFARG);
@@ -1995,7 +2022,7 @@ static int finalize_fetch_insn(struct fetch_insn *code,
} else if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) &&
ctx->last_type) {
/* If user not specified the type, try parsing BTF bitfield. */
- ret = parse_btf_bitfield(&code, ctx);
+ ret = parse_btf_bitfield(&code, parg->type, ctx);
if (ret)
return ret;
}
next prev parent reply other threads:[~2026-11-09 0:28 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 0:28 [PATCH 00/12] tracing/probes: Fix various bugs in dynamic probe events Masami Hiramatsu (Google)
2026-11-09 0:28 ` [PATCH 01/12] tracing/probes: Check enabled and busy state before unlinking sibling probes Masami Hiramatsu (Google)
2026-11-09 0:28 ` [PATCH 02/12] tracing/probes: Enable newly appended probe when target event is enabled Masami Hiramatsu (Google)
2026-11-09 0:28 ` Masami Hiramatsu (Google) [this message]
2026-11-09 0:28 ` [PATCH 04/12] tracing/probes: Fix missing BTF kind checks in char pointer/array helpers Masami Hiramatsu (Google)
2026-11-09 0:28 ` [PATCH 05/12] tracing/eprobe: Fix 1-byte signed field fetch in get_event_field() Masami Hiramatsu (Google)
2026-11-09 0:28 ` [PATCH 06/12] tracing/eprobe: Disallow attaching eprobes to fprobe events Masami Hiramatsu (Google)
2026-11-09 0:29 ` [PATCH 07/12] tracing/probes: Fix user-space dereference string array store type Masami Hiramatsu (Google)
2026-11-09 0:29 ` [PATCH 08/12] tracing/probes: Reject array count on non-dereference string sources Masami Hiramatsu (Google)
2026-11-09 0:29 ` [PATCH 09/12] tracing/probes: Allow symstr type for function entry arguments in return probes Masami Hiramatsu (Google)
2026-11-09 0:29 ` [PATCH 10/12] tracing/probes: Reject empty fetch expression for %pd and %pD Masami Hiramatsu (Google)
2026-11-09 0:29 ` [PATCH 11/12] tracing/probes: Validate command prefix in kprobe, uprobe, and eprobe Masami Hiramatsu (Google)
2026-11-09 0:29 ` [PATCH 12/12] tracing/probes: Propagate error codes in eprobe and fprobe creation Masami Hiramatsu (Google)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=179418411197.227715.5577722703946865281.stgit@devnote2 \
--to=mhiramat@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®