Skip to content
This repository was archived by the owner on Sep 8, 2026. It is now read-only.

[pull] master from libfuse:master - #81

Merged
pull[bot] merged 5 commits into
BY-SOMMER:masterfrom
libfuse:master
Aug 30, 2026
Merged

pull[bot] merged 5 commits into
BY-SOMMER:masterfrom
libfuse:master

Conversation

@pull

@pull pull Bot commented Aug 30, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

bsbernd and others added 5 commits August 30, 2026 23:12
struct fuse_file_info reserves padding bits so new flags can be added
without an ABI break, but abidiff reports the resulting member insertion
and padding offset shift as a change and fails the check. Bound the
suppression to size-preserving changes so a real size change still fails.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
With FUSE_CAP_HANDLE_KILLPRIV_V2 the kernel stops clearing suid/sgid
itself and leaves that to the filesystem. Clearing them depends on
CAP_FSETID, held by the application that issued the syscall - the
filesystem's own privileges do not matter, and it cannot see the
application's, so the kernel signals the decision per request. Of the
three flags carrying it only FATTR_KILL_SUIDGID made it through, because
FUSE_SET_ATTR_KILL_SUID happens to be the same bit.
FUSE_OPEN_KILL_SUIDGID and FUSE_WRITE_KILL_SUIDGID were dropped, so a
server that negotiated KILLPRIV_V2 never saw the request on O_TRUNC open
and on write, and suid/sgid survived.

Decode both into a new fuse_file_info::kill_suidgid, taken from the
padding bits, in open, create, write and write_buf. Gate it on the
negotiated capability and not on proto_minor: a filesystem that did not
ask for KILLPRIV_V2 must never see fi->kill_suidgid set, and negotiating
KILLPRIV_V2 implies 7.31, so fuse_create_in::open_flags is there to
read.

Added by Bernd:

- fix the comment style for checkpatch
- drop the XXX markers for unhandled open_flags, this patch handles them
- replace the proto_minor guard with the capability check
- drop security.capability from the field's documentation

Signed-off-by: Robert Doebbelin <robert@quobyte.com>
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Nothing covered fi->kill_suidgid arriving in open, create, write and
write_buf.

test_setattr already asks whether the lowlevel layer passes the right
fuse_file_info to an operation, so the check goes there rather than into
a second binary. Its own case file though, to keep the
FUSE_CAP_HANDLE_KILLPRIV_V2 requirement off the setattr check.

Three runs:

- default: fi->kill_suidgid has to arrive set
- --write-buf: same, through the write_buf handler
- --no-killpriv: it has to arrive clear

The kernel sets FUSE_OPEN_KILL_SUIDGID and FUSE_WRITE_KILL_SUIDGID only
for a caller without CAP_FSETID, which a root test process gives up for
itself rather than skipping the case.

The --no-killpriv run is not idle. fuse_direct_io() sets
FUSE_WRITE_KILL_SUIDGID for any caller without CAP_FSETID and never
consults handle_killpriv_v2, so it reaches a filesystem that did not ask
for KILLPRIV_V2 unless libfuse gates on the negotiated capability.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
A write by a caller without CAP_FSETID has to clear setuid and setgid,
and nothing covered that for passthrough_hp. It is worth checking there
because the daemon writes to the backing file under its own credentials,
which normally hold CAP_FSETID, so the backing filesystem never clears
setuid/setgid - and in passthrough mode the daemon does not even see the
write. Only the FUSE kernel clears them.

Two cases, because opening a backing file needs CAP_SYS_ADMIN and so
passthrough mode is only reachable as root:

- passthrough-hp-suid, root only, covers the backing-file write path
- passthrough-hp-suid-nopassthrough, unprivileged, covers the write path
  the daemon serves

checks.py drops CAP_FSETID for the write, so one check serves both.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Without KILLPRIV_V2 the kernel never marks a FUSE inode S_NOSEC, so
every write syscall probes security.capability first - 20 writes to one
file cost 20 GETXATTR round trips and produced a single WRITE. Under
KILLPRIV_V2 the probe stops after the first write and the kernel hands
the CAP_FSETID decision to the filesystem instead, which costs one local
fstat per WRITE.

Not in passthrough mode: the kernel drops the suid/sgid clearing once
KILLPRIV_V2 is negotiated, and there the filesystem never sees the write
to clear them instead, so suid/sgid would survive.

fallocate needs the same care for a different reason. The kernel stops
clearing suid/sgid there too, but sends no flag for it - the protocol
has one for open, create, write and setattr only. sfs_fallocate() clears
them unconditionally, since nothing says whether the caller held
CAP_FSETID.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
@pull pull Bot locked and limited conversation to collaborators Aug 30, 2026
@pull pull Bot added the ⤵️ pull label Aug 30, 2026
@pull
pull Bot merged commit 32e73af into BY-SOMMER:master Aug 30, 2026
1 check passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants