From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Alan Maguire <alan.maguire@oracle.com>
Cc: Jiri Olsa <jolsa@kernel.org>,
Clark Williams <williams@redhat.com>,
dwarves@vger.kernel.org, bpf@vger.kernel.org,
Andrii Nakryiko <andrii@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: [PATCH 25/31] pahole: Guard pipe_seek() against negative offsets
Date: Wed, 29 Jul 2026 16:07:25 -0300 [thread overview]
Message-ID: <20260729190733.72876-26-acme@kernel.org> (raw)
In-Reply-To: <20260729190733.72876-1-acme@kernel.org>
From: Arnaldo Carvalho de Melo <acme@redhat.com>
pipe_seek() simulates forward seeking on non-seekable streams by
reading and discarding chunks into a 4096-byte stack buffer. When
called with a negative offset, 'chunk' gets a negative value that is
implicitly cast to a huge size_t by fread(), causing a stack buffer
overflow.
This can happen when a user passes a negative --seek_bytes value:
fseeko() fails (SEEK_SET rejects negatives), then the fallback calls
pipe_seek() with the unchecked negative value.
Guard against this by rejecting negative offsets at the top of
pipe_seek(), and short-circuit zero offsets as a no-op.
Before:
$ echo | pahole --seek_bytes -1 --prettify - -C task_struct vmlinux
(stack buffer overflow / crash)
After:
$ echo | pahole --seek_bytes -1 --prettify - -C task_struct vmlinux
Couldn't --seek_bytes -1 (18446744073709551615)
Uncovered during code coverage analysis work.
Fixes: fe284221448c950d ("pahole: Introduce --seek_bytes")
Reported-by: Sashiko:gemini-3.1-pro-preview
Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
pahole.c | 58 ++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 44 insertions(+), 14 deletions(-)
diff --git a/pahole.c b/pahole.c
index cceaf9030d442248..5cf92833e6e84df9 100644
--- a/pahole.c
+++ b/pahole.c
@@ -18,6 +18,7 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <bpf/btf.h>
#include "bpf/libbpf.h"
@@ -2371,6 +2372,13 @@ static int pipe_seek(FILE *fp, off_t offset)
char bf[4096];
int chunk = sizeof(bf);
+ /* Negative offset would wrap chunk to a huge size_t in fread() */
+ if (offset < 0)
+ return -1;
+
+ if (offset == 0)
+ return 0;
+
if (chunk > offset)
chunk = offset;
@@ -2605,16 +2613,22 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
uint64_t size_bytes = ULLONG_MAX;
uint32_t count = 0;
uint32_t skip = conf.skip;
+ /* Bytes consumed from input so far, for absolute→relative seek on pipes */
+ off_t consumed = 0;
+ int64_t header_bytes;
if (instance == NULL)
return -ENOMEM;
+ /* Keep consumed in sync with bytes actually fread'd from input */
errno = 0;
- if (type__instance_read_once(header, input) < 0) {
+ header_bytes = type__instance_read_once(header, input);
+ if (header_bytes < 0) {
printed = errno ? -errno : -EIO;
fprintf(stderr, "pahole: --header (%s) type couldn't be read\n", conf.header_type);
goto out;
}
+ consumed = header_bytes;
if (conf.range || prototype->range) {
off_t seek_bytes;
@@ -2662,21 +2676,25 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
* for non-seekable streams (stdin, pipes).
*/
if (fseeko(input, seek_bytes, SEEK_SET) != 0) {
- off_t total_read_bytes = ftell(input);
-
- if (seek_bytes < total_read_bytes) {
- fprintf(stderr, "pahole: can't seek backward in non-seekable input, already read %" PRIu64 " bytes, target %#" PRIx64 "\n",
- total_read_bytes, seek_bytes);
+ if (seek_bytes < consumed) {
+ fprintf(stderr, "pahole: can't seek backward in non-seekable input, already read %" PRId64 " bytes, target %#" PRIx64 "\n",
+ (int64_t)consumed, seek_bytes);
printed = -ESPIPE;
goto out;
}
- seek_bytes -= total_read_bytes;
-
errno = 0;
- if (pipe_seek(input, seek_bytes) < 0) {
+ if (pipe_seek(input, seek_bytes - consumed) < 0) {
printed = errno ? -errno : -EIO;
- fprintf(stderr, "Couldn't seek to offset %" PRIu64 " for range=%s\n", seek_bytes, range);
+ fprintf(stderr, "Couldn't seek to offset %" PRId64 " for range=%s\n", (int64_t)seek_bytes, range);
+ goto out;
+ }
+ } else {
+ struct stat sb;
+ if (fstat(fileno(input), &sb) == 0 && S_ISREG(sb.st_mode) && seek_bytes >= sb.st_size) {
+ fprintf(stderr, "pahole: seek offset %" PRId64 " is beyond file size %" PRId64 " for range=%s\n",
+ (int64_t)seek_bytes, (int64_t)sb.st_size, range);
+ printed = -EINVAL;
goto out;
}
}
@@ -2750,13 +2768,25 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
* forward-reading pipe_seek() for pipes/stdin.
*/
if (fseeko(input, seek_bytes, SEEK_SET) != 0) {
- if (header)
- seek_bytes -= ftell(input);
+ if (seek_bytes < consumed) {
+ fprintf(stderr, "pahole: can't seek backward in non-seekable input, already read %" PRId64 " bytes, target %#" PRIx64 "\n",
+ (int64_t)consumed, seek_bytes);
+ printed = -ESPIPE;
+ goto out;
+ }
errno = 0;
- if (pipe_seek(input, seek_bytes) < 0) {
+ if (pipe_seek(input, seek_bytes - consumed) < 0) {
printed = errno ? -errno : -EIO;
- fprintf(stderr, "Couldn't --seek_bytes %s (%" PRIu64 ")\n", conf.seek_bytes, seek_bytes);
+ fprintf(stderr, "Couldn't --seek_bytes %s (%" PRId64 ")\n", conf.seek_bytes, (int64_t)seek_bytes);
+ goto out;
+ }
+ } else {
+ struct stat sb;
+ if (fstat(fileno(input), &sb) == 0 && S_ISREG(sb.st_mode) && seek_bytes >= sb.st_size) {
+ fprintf(stderr, "pahole: --seek_bytes %" PRId64 " is beyond file size %" PRId64 "\n",
+ (int64_t)seek_bytes, (int64_t)sb.st_size);
+ printed = -EINVAL;
goto out;
}
}
--
2.55.0
next prev parent reply other threads:[~2026-07-29 19:08 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-29 19:07 [PATCHES 00/31] pahole: Bug fixes and small improvements Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 01/31] cmake: Update minimum required version from 3.5 to 3.10 Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 02/31] Fix -Wsign-compare warnings across the codebase Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 03/31] btf_encoder: Fix interior pointer free and missing NULL check Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 04/31] dwarves: Fix missing list head initialization in type__clone_members Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 05/31] pahole: Fix instance memory leak on early returns in prototype__stdio_fprintf_value Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 06/31] ctf_loader, libctf: Fix error path resource leaks Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 07/31] dwarves: Don't search for holes before member byte sizes are cached Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 08/31] dwarf_loader: Allocate type_dcu via dwarf_cu__new to fix dangling stack pointer Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 09/31] dwarf_loader: Fix annotation failure leaks in variable and typedef creation Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 10/31] btf_encoder: Use btf_encoder__tag_type() for all type ID computations Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 11/31] pahole: Fix --errno typo that decrements instead of negating Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 12/31] dwarves: Fix heap buffer overflow in languages__parse realloc Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 13/31] btf_encoder: Fix early cleanup crashes in btf_encoder__new/delete Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 14/31] btf_encoder, libctf: Add elf_strptr NULL checks and fix kfunc bounds Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 15/31] dwarf_loader: Fix --fixup_silly_bitfields condition check Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 16/31] dwarf_loader: Skip libdw__lock when elfutils is built thread-safe Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 17/31] dwarf_loader: Fix data race in tag__init() decl_file string cache Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 18/31] pahole: Fix parse_btf_features("all") being a silent no-op Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 19/31] dwarves: Fix variable shadowing in __cus__find_struct_by_name() Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 20/31] dutil: Add exec_objcopy() shell-injection-safe helper Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 21/31] btf_encoder: Fall back to objcopy when llvm-objcopy is not available Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 22/31] dwarf_loader, btf_loader: Replace stale FIXME/XXX comments with explanations Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 23/31] pahole: Skip inline expansions during BTF encoding Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 24/31] pahole: Use fseek for seekable files in --prettify and --seek_bytes Arnaldo Carvalho de Melo
2026-07-29 19:07 ` Arnaldo Carvalho de Melo [this message]
2026-07-29 19:07 ` [PATCH 26/31] gobuffer: Remove 5 dead functions found via coverage analysis Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 27/31] dwarves: Remove 6 " Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 28/31] pfunct, dwarves_fprintf: Mark file-local functions as static Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 29/31] btf_encoder: Fix multi-dimensional array encoding Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 30/31] btf_loader: Fix multi-dimensional array loading Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 31/31] btfdiff: Remove --flat_arrays now that pahole encodes multi dim arrays in BTF Arnaldo Carvalho de Melo
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=20260729190733.72876-26-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=dwarves@vger.kernel.org \
--cc=jolsa@kernel.org \
--cc=williams@redhat.com \
--cc=yonghong.song@linux.dev \
/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