From: sashiko-bot@kernel.org
To: "Alexis Lothoré (eBPF Foundation)" <alexis.lothore@bootlin.com>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next 1/2] selftests/bpf: add helpers to manipulate ftrace
Date: Fri, 30 Oct 2026 19:02:05 +0000 [thread overview]
Message-ID: <sashiko-outbox-191429@kernel.org> (raw)
In-Reply-To: <20261030-ftrace_in_test_progs-v1-1-aa50c5dd1ccc@bootlin.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Medium] selftests/bpf: unchecked realloc() in tracefs_read() causes NULL deref
- [Medium] selftests/bpf: tracefs_ctl_update() fails to truncate filter on first write
- [Medium] selftests/bpf: tracefs_ctl_update() ignores tracefs_read() failure
- [Medium] selftests/bpf: tracefs_write() drops multi-token filters on short write
- [Medium] selftests/bpf: tracefs helpers return -1 instead of -errno on syscall error
--
commit 569748d9037859f0dfb26ca03c10fd22fc3a99b9
Author: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
selftests/bpf: add helpers to manipulate ftrace
This commit adds tracefs control helpers to tools/testing/selftests/bpf/
so tests can modify ftrace settings and filters and automatically restore
their original state upon completion.
> diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
> index 6d7a4b8c4ab8c..1f26a057a810a 100644
> --- a/tools/testing/selftests/bpf/trace_helpers.c
> +++ b/tools/testing/selftests/bpf/trace_helpers.c
[ ... ]
> @@ -557,6 +561,245 @@ void read_trace_pipe(void)
> read_trace_pipe_iter(trace_pipe_cb, NULL, 0);
> }
>
[ ... ]
> +static int tracefs_read(int fd, char **content)
> +{
> + size_t len = 0;
> + char tmp[CHUNK_SIZE];
> + char *buf = NULL;
> + ssize_t n;
> + int ret;
> +
> + ret = lseek(fd, 0, SEEK_SET);
> + if (ret < 0)
> + return ret;
> +
> + do {
> + n = read(fd, tmp, CHUNK_SIZE);
> + if (n < 0) {
> + if (buf)
> + free(buf);
> + return n;
> + }
> + if (!n)
> + break;
> + buf = realloc(buf, len + n + 1);
> + memcpy(buf + len, tmp, n);
[Severity: Medium]
What happens in tracefs_read() if realloc() fails while reading chunks from
the tracefs file? Assigning the return value directly to buf loses the
existing buf allocation and then dereferences NULL + len in memcpy().
> + len += n;
> + } while (1);
> +
> + /* No data read at all, file was empty */
> + if (!buf) {
> + buf = malloc(1);
> + if (!buf)
> + return -ENOMEM;
> + }
> + buf[len] = '\0';
> + *content = buf;
> + return 0;
> +}
> +
> +static int tracefs_write(int fd, const char *str)
> +{
> + ssize_t ret;
> +
> + ret = lseek(fd, 0, SEEK_SET);
> + if (ret < 0)
> + return ret;
> +
> + ret = write(fd, str, strlen(str));
> + if (ret < 0)
> + return ret;
> + return 0;
> +}
[Severity: Medium]
Can a single write() call in tracefs_write() drop patterns when writing to
ftrace filter files?
In kernel/trace/ftrace.c, ftrace_regex_write() (for set_ftrace_filter and
set_ftrace_notrace) and ftrace_graph_write() (for set_graph_function and
set_graph_notrace) parse user input with trace_get_user(), which stops at
the first whitespace character and returns the byte count consumed for only
that single token.
When a caller passes multiple space-separated patterns (or a function with
a module suffix like "func [mod]\n" during tracefs_restore_file()), write()
returns a short byte count for the first token and tracefs_write() returns 0
without looping to write the remaining tokens.
In addition, if a pattern does not end with whitespace or a newline,
trace_get_user() marks the parser as a continuation (parser->cont = true)
and defers regex evaluation until close(), where release errors are not
reported back to close(fd).
> +
> +static int tracefs_write_file(const char *path, const char *str)
> +{
> + int fd, err;
> +
> + fd = open(path, O_CLOEXEC | O_WRONLY | (*str ? 0 : O_TRUNC));
> + if (fd < 0)
> + return fd;
> +
> + err = tracefs_write(fd, str);
> + close(fd);
> + return err;
> +}
[ ... ]
> +static int tracefs_ctl_update(struct tracefs_ctl *ctl, const char *file,
> + const char *str, enum tracefs_ctl_kind kind)
> +{
> + struct tracefs_ctl_entry *entry, *tmp;
> + char path[PATH_MAX];
> + char *old = NULL;
> + bool recorded = false;
> + size_t i;
> + int fd, err;
> +
> + if (!ctl)
> + return -EINVAL;
> +
> + err = tracefs_path(path, sizeof(path), file);
> + if (err)
> + return err;
> +
> + for (i = 0; i < ctl->cnt; i++) {
> + if (strcmp(ctl->entries[i].path, path))
> + continue;
> + if (ctl->entries[i].kind != kind)
> + return -EINVAL;
> + /* Already altered, keep the value read on the first write. */
> + return tracefs_write_file(ctl->entries[i].path, str);
> + }
> +
> + fd = open(path, O_CLOEXEC | O_RDWR);
> + if (fd < 0)
> + return fd;
> +
> + err = tracefs_read(fd, &old);
> + if (!err) {
> + tmp = realloc(ctl->entries, (ctl->cnt + 1) * sizeof(*tmp));
> + if (!tmp) {
> + free(old);
> + close(fd);
> + return -ENOMEM;
> + }
> + ctl->entries = tmp;
> + entry = &ctl->entries[ctl->cnt];
> + strcpy(entry->path, path);
> + entry->old = old;
> + entry->kind = kind;
> + recorded = true;
> + }
> +
> + err = tracefs_write(fd, str);
> + close(fd);
[Severity: Medium]
Should tracefs_ctl_update() bail out when tracefs_read() returns an error?
Right now, if tracefs_read() fails, execution skips recording the entry in
ctl->entries and proceeds to tracefs_write(fd, str), which modifies the
tracefs file without saving its original value for tracefs_ctl_restore().
Also, when the first operation on a tracefs file passes an empty string ""
to clear it (such as clearing set_ftrace_filter or set_graph_notrace), does
calling tracefs_write(fd, str) on the O_RDWR descriptor actually clear the
filter?
In kernel/trace/ftrace.c (ftrace_regex_open() and __ftrace_graph_open()) and
kernel/trace/trace.c (tracing_open()), clearing a filter or trace file
requires opening it with O_TRUNC, whereas a 0-byte write() to a descriptor
opened without O_TRUNC is a no-op. Unlike tracefs_write_file(), which opens
with O_TRUNC when *str is empty, the first update in tracefs_ctl_update()
writes to the descriptor opened with open(path, O_CLOEXEC | O_RDWR). Should
tracefs_ctl_update() close fd after tracefs_read() and use
tracefs_write_file(path, str) instead?
[ ... ]
> +void tracefs_ctl_restore(struct tracefs_ctl *ctl)
> +{
> + size_t i;
> + int err;
> +
> + if (!ctl)
> + return;
> +
> + for (i = ctl->cnt; i > 0; i--) {
> + struct tracefs_ctl_entry *entry = &ctl->entries[i - 1];
> +
> + err = tracefs_restore_file(entry);
> + if (err)
> + fprintf(stderr, "Failed to restore %s: %s\n",
> + entry->path, strerror(-err));
[Severity: Medium]
In tracefs_ctl_restore(), strerror(-err) expects negative errno values,
which matches internal errors like -ENOMEM, -EINVAL, and -ENAMETOOLONG.
However, when open(), lseek(), read(), or write() fails in tracefs_read(),
tracefs_write(), tracefs_write_file(), or tracefs_ctl_update(), those
functions return -1 rather than -errno. Won't any syscall failure during
tracefs_restore_file() cause strerror(-err) to evaluate strerror(1) (EPERM)
instead of the real errno?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261030-ftrace_in_test_progs-v1-0-aa50c5dd1ccc@bootlin.com?part=1
next prev parent reply other threads:[~2026-10-30 19:02 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 18:50 [PATCH bpf-next 0/2] selftests/bpf: port test_ftrace.sh into test_progs Alexis Lothoré (eBPF Foundation)
2026-10-30 18:50 ` [PATCH bpf-next 1/2] selftests/bpf: add helpers to manipulate ftrace Alexis Lothoré (eBPF Foundation)
2026-10-30 19:02 ` sashiko-bot [this message]
2026-10-30 19:34 ` bot+bpf-ci
2026-10-30 18:50 ` [PATCH bpf-next 2/2] selftests/bpf: port test_ftrace.sh to test_progs Alexis Lothoré (eBPF Foundation)
2026-10-30 19:05 ` sashiko-bot
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=sashiko-outbox-191429@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=alexis.lothore@bootlin.com \
--cc=bpf@vger.kernel.org \
--cc=sashiko-reviews@lists.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