All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.