BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Leon Hwang" <leon.hwang@linux.dev>, bpf@vger.kernel.org
Cc: linux-trace-kernel@vger.kernel.org
Subject: Re: [PATCH bpf-next 2/6] bpf: Add syscall common attrs support for xdp link_create
Date: Sat, 17 Oct 2026 14:48:30 +0000	[thread overview]
Message-ID: <sashiko-outbox-175566@kernel.org> (raw)
In-Reply-To: <20261017142649.51047-3-leon.hwang@linux.dev>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] bpf: NULL deref and format string bug in bpf_xdp_link_attach() via bpf_log()
- [Critical] bpf: prog refcount underflow in link_create() if bpf_log_attr_finalize() fails
- [Low] bpf: link failure in bpf_xdp_link_attach() when !CONFIG_BPF_SYSCALL
--

commit fa16fd00d8499a718392032e57d440248e048afc
Author: Leon Hwang <leon.hwang@linux.dev>

bpf: Add syscall common attrs support for xdp link_create

This commit passes the verifier log to bpf_xdp_link_attach() so that XDP
link creation can report target_ifindex and driver errors through BPF
syscall common attributes.

> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 252b479937a4d..e96d5f09486f5 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -5921,7 +5921,7 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr, struct bpf_common_a
>  		break;
>  #ifdef CONFIG_NET
>  	case BPF_PROG_TYPE_XDP:
> -		ret = bpf_xdp_link_attach(attr, prog);
> +		ret = bpf_xdp_link_attach(attr, prog, log);
>  		break;
>  	case BPF_PROG_TYPE_SCHED_CLS:
>  		if (attr->link_create.attach_type == BPF_TCX_INGRESS ||

[Severity: Critical]
Can the cleanup path in link_create() underflow prog's reference count if
bpf_log_attr_finalize() fails after bpf_xdp_link_attach() succeeds?

When bpf_xdp_link_attach() succeeds, bpf_link_init() transfers ownership of
prog's reference to link->link.prog and bpf_link_settle() installs the link
file descriptor, returning a non-negative fd in ret.

At the out label in link_create(), bpf_log_attr_finalize() writes
log_true_size to uattr_common even when nothing was logged:

kernel/bpf/log.c:bpf_log_attr_finalize() {
	...
	if (attr->offsetof_true_size &&
	    copy_to_bpfptr_offset(attr->uattr, attr->offsetof_true_size, &log_true_size,
				  sizeof(log_true_size)))
		return -EFAULT;
}

If uattr_common points to read-only memory, copy_from_bpfptr() in
__sys_bpf() succeeds, bpf_xdp_link_attach() attaches and settles the link,
and then bpf_log_attr_finalize() returns -EFAULT:

kernel/bpf/syscall.c:link_create() {
out:
	/* preserve original error even if log finalization is successful */
	err = bpf_log_attr_finalize(&attr_log, log);
	if (err)
		ret = err;

	kfree(log);

	if (ret < 0 && prog)
		bpf_prog_put(prog);
	return ret;
}

Overwriting ret with err causes link_create() to call bpf_prog_put(prog) on
a reference that is now owned by the settled bpf_link, leading to a
use-after-free of struct bpf_prog while the link remains attached in the
process fd table.

> diff --git a/net/core/dev.c b/net/core/dev.c
> index 18dc88990510a..fdc1de21f3589 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
[ ... ]
> @@ -10771,7 +10772,8 @@ static const struct bpf_link_ops bpf_xdp_link_lops = {
>  	.update_prog = bpf_xdp_link_update,
>  };
>  
> -int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
> +int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog,
> +			struct bpf_verifier_log *log)
>  {
>  	struct net *net = current->nsproxy->net_ns;
>  	struct bpf_link_primer link_primer;
> @@ -10784,6 +10786,7 @@ int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
>  	dev = dev_get_by_index(net, attr->link_create.target_ifindex);
>  	if (!dev) {
>  		rtnl_unlock();
> +		bpf_log(log, "Invalid target_ifindex.\n");
>  		return -EINVAL;
>  	}

[Severity: Low]
Will calling bpf_log() in bpf_xdp_link_attach() break linking when
CONFIG_NET=y and CONFIG_BPF_SYSCALL=n?

net/core/dev.c is compiled whenever CONFIG_NET=y, and bpf_xdp_link_attach()
is not guarded by CONFIG_BPF_SYSCALL. While helpers like bpf_link_init() and
bpf_link_prime() have static inline stubs in include/linux/bpf.h when
!CONFIG_BPF_SYSCALL, bpf_log() is only compiled via kernel/bpf/log.o when
CONFIG_BPF_SYSCALL=y and has no stub in include/linux/bpf_verifier.h.

>  
> @@ -10812,6 +10815,7 @@ int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
>  	if (err) {
>  		link->dev = NULL;
>  		bpf_link_cleanup(&link_primer);
> +		bpf_log(log, extack._msg);
>  		trace_bpf_xdp_link_attach_failed(extack._msg);
>  		goto out_put_dev;
>  	}

[Severity: Critical]
What happens here when dev_xdp_attach_link() fails without setting an extack
message, or when extack._msg contains format specifiers?

In bpf_xdp_link_attach(), extack is zero-initialized on the stack, so
extack._msg starts as NULL. Many failure paths under dev_xdp_attach_link() ->
dev_xdp_attach() -> dev_xdp_install() return an error without calling
NL_SET_ERR_MSG(), such as netif_xdp_propagate() when a device has no ndo_bpf
callback, or driver ndo_bpf callbacks like netkit_xdp() and veth_xdp()
returning -EOPNOTSUPP or -EINVAL.

When a user provides a log buffer via syscall common attributes and
extack._msg is NULL, bpf_log() passes fmt = NULL into
bpf_verifier_vlog() -> vscnprintf() -> vsnprintf(), which dereferences fmt
unconditionally and crashes the kernel.

Additionally, because bpf_log() is a printf-style function, passing
extack._msg directly as the format string rather than using a "%s\n" format
specifier allows any '%' characters in a formatted extack message (for
example from NL_SET_ERR_MSG_FMT() containing an interface name) to be
interpreted as format specifiers by vscnprintf(), and omits the trailing
newline. Should this be guarded with if (extack._msg) and logged with
bpf_log(log, "%s\n", extack._msg)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261017142649.51047-1-leon.hwang@linux.dev?part=2

  reply	other threads:[~2026-10-17 14:48 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-17 14:26 [PATCH bpf-next 0/6] bpf: Add syscall common attrs support for xdp link_create Leon Hwang
2026-10-17 14:26 ` [PATCH bpf-next 1/6] bpf: Add syscall common attrs support for link_create Leon Hwang
2026-10-17 14:39   ` sashiko-bot
2026-10-17 14:26 ` [PATCH bpf-next 2/6] bpf: Add syscall common attrs support for xdp link_create Leon Hwang
2026-10-17 14:48   ` sashiko-bot [this message]
2026-10-17 15:03   ` bot+bpf-ci
2026-10-17 14:26 ` [PATCH bpf-next 3/6] bpf: Retire tracepoint bpf_xdp_link_attach_failed Leon Hwang
2026-10-17 14:26 ` [PATCH bpf-next 4/6] libbpf: Factor out __bpf_sys_fd helper Leon Hwang
2026-10-17 14:53   ` bot+bpf-ci
2026-10-17 14:26 ` [PATCH bpf-next 5/6] libbpf: Add bpf_link_create_log API Leon Hwang
2026-10-17 14:43   ` sashiko-bot
2026-10-17 15:03   ` bot+bpf-ci
2026-10-17 14:26 ` [PATCH bpf-next 6/6] selftests/bpf: Add tests to verify link_create logs Leon Hwang
2026-10-17 15:02   ` bot+bpf-ci

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-175566@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=leon.hwang@linux.dev \
    --cc=linux-trace-kernel@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