From: Benjamin Tissoires <bentiss@kernel.org>
To: Shi Lecun <shilc2025@mail.sustech.edu.cn>
Cc: linux-input <linux-input@vger.kernel.org>,
jikos <jikos@kernel.org>, bpf <bpf@vger.kernel.org>
Subject: Re: HID-BPF: CAP_BPF-only process can inject input into host session
Date: Tue, 13 Oct 2026 18:00:39 +0200 [thread overview]
Message-ID: <asyhxnfwslRJVvlr@beelink> (raw)
In-Reply-To: <tencent_3B9FD2455BEBDF351B2CD453@qq.com>
Hi,
On Oct 12 2026, Shi Lecun wrote:
> Hi,
>
> Granting a workload permission to manage eBPF can also grant it the
> ability to type on the host.
>
> A process that holds only CAP_BPF, running as a non-root user inside a
> container with no device nodes and no X11 or Wayland socket, can load a
> BPF_PROG_TYPE_SYSCALL program that calls hid_bpf_allocate_context() and
> hid_bpf_input_report(), run it through BPF_PROG_TEST_RUN, and inject
> keyboard reports into an already-authorized HID device. The reports
> travel the normal HID input path and reach the host's unlocked session
> (X11 desktop or text console) as if typed on the device, so the attacker
> executes commands as the logged-in user; on a server with a management
> controller, that session is the operator's console. Container platforms
> grant CAP_BPF to networking and observability workloads, so the
> capability holder is realistic rather than contrived.
Yes, this is expected, somehow. HID-BPF is required to fix devices. But
it relies on mechanisms primarily used by networking tools, and when you
allow networking tools to monitor the container, they effectively can
alter HID devices as well. I'm not sure we want another CAP_*.
>
> Detailed description:
>
> - Problem: the unattached syscall path can inject input with CAP_BPF
> alone. Attaching a struct_ops program to a device requires
> CAP_BPF+CAP_PERFMON, but a syscall program calling
> hid_bpf_input_report() needs only CAP_BPF and leaves no per-device
> record.
>
> - Reachability: a non-root container holding CAP_BPF, one
> already-authorized HID device, and an unlocked session. No malicious
> device, firmware, USB traffic, verifier flaw or memory-safety bug is
> involved.
>
> - Effect: arbitrary commands typed as the host user in the focused
> session, including a server's BMC virtual console. With CAP_PERFMON,
> the struct_ops path can in addition rewrite the report descriptor so
> an authorized mouse presents a keyboard collection.
>
> - Method and testing: a reproducer built against the struct_ops HID-BPF
> API, run in QEMU on Ubuntu 26.04 / kernel 7.0.0-28-generic
> (CONFIG_HID_BPF=y, BTF enabled) and on an Arch 7.1.5 host.
> Capability-restricted non-root runs with setpriv confirm the three
> cases above; 1000 of 1000 injections were accepted; commands landed in
The contrary would have been problematic: this just says that the code
is working deterministically, which is expected :)
> both an X session and a text console. Older, pre-struct_ops kernels
> are untested.
>
> - Possible fix: a capability check on the syscall path that reaches
> hid_bpf_input_report()/hid_bpf_try_input_report(), or a policy gate at
> program load. We implemented the latter as an LSM program on
> security_bpf_prog_load that denies a load calling any of the seven
> HID-BPF kfuncs; it stops the injector with -EPERM and costs about
> 24 us on a worst-case 4096-instruction load, with no input-path cost.
FWIW, Toke presented a policy for BPF at Plumbers last week[0]. Such
RBACd policy can allow a container to be restricted to use HID-BPF.
But the LSM might work just as well. I just don't want the module to
prevent HID-BPF from running on legitimate use case.
>
> My reading is that this is not a kernel vulnerability: the program is
> verifier-clean, no check is bypassed and nothing is memory-unsafe -- the
> malice is in the report data. The behavior also matches
> Documentation/hid/hid-bpf.rst, which documents hid_bpf_input_report()
> from syscall programs and already calls the tracing use case "god-mode".
> What I cannot settle myself is whether the capability split is what you
> intended.
There was nothing specifically intended for the split
CAP_BPF/CAP_PERFMON. But I don't really see why you are focusing on this
split when the report from above also mentions that CAP_PERFMON is also
used in conjunction with CAP_BPF to ease the injections of keys (without
needing to know in advance the report format).
I think the biggest issue IMO is that BPF was primarily introduced with
the network use case in mind, and CAP_BPF is probably too coarse.
That's where projects like RBACd and the LSM program you mentioned come
in handy.
>
> The one point I would like an answer on is the asymmetry itself: if the
> CAP_PERFMON requirement is about the attach/IRQ context rather than
> about input, then this is expected and I have no further concern.
struct_ops is classed as a perfmon program type because it has raw
kernel-memory access, independent of HID-BPF.
> If you
> would rather close it, I can post the LSM gate, though it is not the only
> possible fix.
I would be curious to see the LSM gate :)
>
> What I am asking for:
FWIW, the convention on the list is to just discuss inline, so it feels
weird to ask summary questions at the end.
>
> 1. Confirm or correct the reading above.
see above
> 2. If it is a bug: say so, and I will follow the security process
> instead.
I wouldn't call it a bug. But yes, hid_bpf_input_report is intentionally
callable from a CAP_BPF-only syscall program; that was a deliberate
choice so fixup tooling doesn't need tracing privileges, and gating it
further is a policy question better solved with RBACd/LSM than a new
CAP_*.
However, Alexei and the other folks from the bpf community might
disagree with me.
> 3. If it is intended: a short statement on this thread would help, and
> with your permission I would cite it as the maintainers' position. I
> am not asking for a CVE or for you to endorse the paper.
What kind of short statement are you asking for? To me, we all know that
there are way too many capabilities with BPF, and that's why the LSM
hook you used, and projects like RBACd [0] are useful.
>
> This comes from a paper we are preparing. It is not submitted yet and
> nothing will be published for some time, so there is no deadline here.
> The reproducer, logs and code are available on request, and I am happy to
> discuss everything on the list.
>
> Thanks,
> Shi Lecun <shilc2025@mail.sustech.edu.cn>
Cheers,
Benjamin
[0] https://lpc.events/event/20/contributions/2441/
prev parent reply other threads:[~2026-10-13 16:00 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-12 8:47 HID-BPF: CAP_BPF-only process can inject input into host session Shi Lecun
2026-10-13 16:00 ` Benjamin Tissoires [this message]
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=asyhxnfwslRJVvlr@beelink \
--to=bentiss@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=jikos@kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=shilc2025@mail.sustech.edu.cn \
/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