mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: bot+bpf-ci@kernel.org
To: florent.revest@linux.dev,bpf@vger.kernel.org,ast@kernel.org,daniel@iogearbox.net,andrii@kernel.org
Cc: florent.revest@linux.dev,martin.lau@linux.dev,eddyz87@gmail.com,memxor@gmail.com,song@kernel.org,yonghong.song@linux.dev,jolsa@kernel.org,kpsingh@kernel.org,john.fastabend@gmail.com,leon.hwang@linux.dev,zirajs7@gmail.com,rhkrqnwk98@gmail.com,puranjay@kernel.org,xukuohai@huaweicloud.com,iii@linux.ibm.com,hbathini@linux.ibm.com,chleroy@kernel.org,naveen@kernel.org,bjorn@kernel.org,pulehui@huawei.com,yangtiezhu@loongson.cn,hengqi.chen@gmail.com,linux-kernel@vger.kernel.org,ast@kernel.org,andrii@kernel.org,daniel@iogearbox.net,martin.lau@kernel.org,eddyz87@gmail.com,yonghong.song@linux.dev,mason@kernel.org,ihor.solodrai@linux.dev
Subject: Re: [PATCH bpf v3 3/3] selftests/bpf: Detach a trampoline prog while a task sleeps before it
Date: Thu, 24 Sep 2026 17:53:34 +0000 (UTC)	[thread overview]
Message-ID: <9ff9f911b980da0e9100578ccf6dba5c7a5414e0b0075922e750161220370554@mail.kernel.org> (raw)
In-Reply-To: <20260924170543.1017048-4-florent.revest@linux.dev>

[-- Attachment #1: Type: text/plain, Size: 5064 bytes --]

> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c b/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c
> index ecc3d47919ad..f8497e764beb 100644
> --- a/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c
> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c

[ ... ]

> diff --git a/tools/testing/selftests/bpf/prog_tests/tramp_prog_detach.c b/tools/testing/selftests/bpf/prog_tests/tramp_prog_detach.c
> new file mode 100644
> index 000000000000..002eb4920c91
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/tramp_prog_detach.c

[ ... ]

> +static void test_detach(bool sleepable_fexit, bool victim_fexit)
> +{
> +	struct tramp_prog_detach *sleepable = NULL, *victim = NULL;
> +	struct pollfd pfd = { .events = POLLIN };
> +	struct uffdio_copy uffd_copy = {};
> +	struct uffd_msg uffd_msg;
> +	void *fault_page, *src_page = MAP_FAILED;
> +	long page_size = getpagesize();
> +	bool started = false;
> +	void *thread_ret;
> +	pthread_t thread;
> +	int uffd = -1;

[ ... ]

> +	sleepable_prog = pick_prog(sleepable, sleepable_fexit, true);
> +
> +	/* Not armed yet so this doesn't block, make sure sleepable runs first */
> +	if (!ASSERT_OK((long)run_sleepable(NULL), "dry run"))
> +		goto out;
> +	if (!ASSERT_LT(sleepable->bss->ts, victim->bss->ts, "prog order"))
> +		goto out;
> +
> +	uffd = uffd_block_page(fault_page);
> +	if (!ASSERT_GE(uffd, 0, "userfaultfd open + register address"))
> +		goto out;

A subsystem pattern flags this as potentially concerning: uffd_block_page()
returns -errno when syscall(__NR_userfaultfd, O_CLOEXEC) fails. On a kernel
without CONFIG_USERFAULTFD that is -ENOSYS, and the test then fails through
ASSERT_GE() instead of calling test__skip() with a message saying userfaultfd
is not available. While tools/testing/selftests/bpf/config sets
CONFIG_USERFAULTFD=y so the BPF CI kernel always has it, and the same
ASSERT_GE pattern already exists in bpf_mod_race.c (serial_test_bpf_mod_race)
from before this commit, is this the intended behavior for environments
without userfaultfd support?

> +	sleepable->bss->fault_addr = fault_page;
> +
> +	if (!ASSERT_OK(pthread_create(&thread, NULL, run_sleepable, NULL),
> +		       "pthread_create"))
> +		goto out;
> +	started = true;
> +
> +	/* Wait for the thread to sleep in bpf_copy_from_user() */
> +	pfd.fd = uffd;
> +	if (!ASSERT_EQ(poll(&pfd, 1, 10000), 1, "poll uffd"))
> +		goto out;
> +	if (!ASSERT_EQ(read(uffd, &uffd_msg, sizeof(uffd_msg)), sizeof(uffd_msg),
> +		       "read uffd"))
> +		goto out;
> +	if (!ASSERT_EQ(uffd_msg.event, UFFD_EVENT_PAGEFAULT, "uffd pagefault"))
> +		goto out;
> +
> +	/* Detach and unload the victim prog, and make sure it is gone */
> +	tramp_prog_detach__destroy(victim);
> +	victim = NULL;
> +	kern_sync_rcu();
> +	usleep(100 * 1000);
> +	kern_sync_rcu();

Does this wait actually ensure the victim prog is gone before the task
resumes?

The test only catches the use-after-free if the victim prog has actually been
freed before UFFDIO_COPY releases the sleeping task. The wait here does not
guarantee that, and on the kernel this series produces it most likely is not
freed yet.

Commit 1c2316cf73ba ("bpf: Wait for an RCU tasks grace period before freeing
trampoline progs") changed __bpf_prog_put_noref() so that a tramp_linked
prog is freed through call_rcu_tasks(&prog->aux->rcu, __bpf_prog_put_rcu_tasks),
then call_rcu(), then bpf_prog_free(), which calls schedule_work() for the
final vfree.

RCU Tasks callbacks are lazy. call_rcu_tasks_generic() only sets needwake
for wakeme_after_rcu (a synchronous waiter) or when the queue reaches
rcu_task_lazy_lim. Otherwise it arms lazy_timer with rcu_tasks.lazy_jiffies
= DIV_ROUND_UP(HZ, 4) (kernel/rcu/tasks.h:145), which is about 250ms by
default.

Nothing on the detach path forces a synchronous RCU Tasks wait. Detaching
the victim while the sleepable prog stays attached goes through
modify_ftrace_direct(), and its tmp_ops is static, so it is not
FTRACE_OPS_FL_DYNAMIC and ftrace_shutdown() does not call
synchronize_rcu_tasks().

The test waits only kern_sync_rcu() + 100ms + kern_sync_rcu().
kern_sync_rcu() is membarrier(MEMBARRIER_CMD_SHARED), which is
synchronize_rcu() on SMP and a no-op with one CPU online. That is well short
of 250ms lazy delay + RCU Tasks GP + RCU GP + workqueue.

So when the thread resumes in the old image, the victim's bpf_prog and JIT
image are usually still allocated. On a kernel that has 1c2316cf73ba but
lacks 2ece3357872c (or breaks it later), the thread would run the victim
prog without a KASAN report and the test would pass.

Consider waiting well beyond the RCU Tasks lazy period (for example about 1s,
or polling until the victim prog ID is no longer returned by
bpf_prog_get_next_id()/bpf_prog_get_fd_by_id()) before releasing the thread.

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/36034251810

  reply	other threads:[~2026-09-24 17:53 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-24 17:05 [PATCH bpf v3 0/3] bpf: Fix use-after-free of progs detached from busy trampolines Florent Revest (Anthropic)
2026-09-24 17:05 ` [PATCH bpf v3 1/3] bpf: Wait for an RCU tasks grace period before freeing trampoline progs Florent Revest (Anthropic)
2026-09-24 17:05 ` [PATCH bpf v3 2/3] bpf: Skip the progs of trampoline images that are being freed Florent Revest (Anthropic)
2026-09-24 18:07   ` bot+bpf-ci
2026-09-25  9:52     ` Florent Revest
2026-09-25  0:35   ` Alexei Starovoitov
2026-09-25  9:23     ` Florent Revest
2026-09-24 17:05 ` [PATCH bpf v3 3/3] selftests/bpf: Detach a trampoline prog while a task sleeps before it Florent Revest (Anthropic)
2026-09-24 17:53   ` bot+bpf-ci [this message]
2026-09-25  9:59     ` Florent Revest

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=9ff9f911b980da0e9100578ccf6dba5c7a5414e0b0075922e750161220370554@mail.kernel.org \
    --to=bot+bpf-ci@kernel.org \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bjorn@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=chleroy@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=florent.revest@linux.dev \
    --cc=hbathini@linux.ibm.com \
    --cc=hengqi.chen@gmail.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=iii@linux.ibm.com \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kpsingh@kernel.org \
    --cc=leon.hwang@linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=martin.lau@kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=mason@kernel.org \
    --cc=memxor@gmail.com \
    --cc=naveen@kernel.org \
    --cc=pulehui@huawei.com \
    --cc=puranjay@kernel.org \
    --cc=rhkrqnwk98@gmail.com \
    --cc=song@kernel.org \
    --cc=xukuohai@huaweicloud.com \
    --cc=yangtiezhu@loongson.cn \
    --cc=yonghong.song@linux.dev \
    --cc=zirajs7@gmail.com \
    /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®