Strona główna / Blog / libfuse: build vs runtime remediation

Blog · analiza

libfuse 3.18.3: nowy header nie wystarcza — runtime <3.18.3 zeruje `kill_suidgid`, a custom IO stało się opt-in. Kiedy build-time i runtime tworzą dwa różne stany remediation

libfuse 3.18.3 (8 września 2026) zawiera rozbudowany zestaw security fixów na granicy unprivileged caller ↔ setuid-root fusermount3 ↔ kernel/filesystem process. Dwa elementy są wyjątkowo pouczające dla VE i oba pokazują, że build compliant ≠ runtime compliant.

custom IO opt-in: fuse_session_custom_io() działa tylko przy -Denable-custom-io=true; inaczej zwraca -ENOTSUP (peer może fałszować requesty parsowane bez bounds checks → crash/memory corruption).
kill_suidgid: nowe pole fuse_file_info::kill_suidgid (KILLPRIV_V2), ale FUSE_VERSION nie ma patch level — filesystem zbudowany na headerach 3.18.3, uruchomiony ze starszą libfuse.so 3.18, widzi je jako stale zero.
Reszta: symlink race w fusermount3, argument injection przy mount/umount, brak UMOUNT_NOFOLLOW, OOB read, pointer underflow w fuse.conf.

Najbezpieczniejszy fix: feature off by default

Zamiast „bezpieczniej sparsować” custom IO, projekt czyni je opt-in — dla default build attack path przestaje istnieć (affected source may exist / feature compiled off / reachable path absent). To idealny kandydat do build-aware affectedness.

SBOM nie wystarcza

Dwa artefakty z libfuse 3.18.3 w SBOM mogą mieć enable-custom-io=false i =true — zasadniczo różny attack surface. Potrzebny build provenance:

component: libfuse version: 3.18.3 build_options: { enable_custom_io: false }

„Wersja 3.18” nie wystarcza — runtime mismatch

kill_suidgid to privilege boundary: filesystem, który przejął czyszczenie suid/sgid, na O_TRUNC open i write nie dostawał sygnału — bity mogły przetrwać. Weryfikacja to nie „does field compile?”, lecz „does runtime library propagate killpriv semantics on every required operation?”. Wykrywanie mismatchu: ldd daemona, /proc/$PID/maps | grep libfuse — potwierdzenie działającego procesu, nie tylko package database. W kontenerach multi-stage: builder image z headerami 3.18.3 + runtime image z .so 3.18.2 to realny false positive.

fusermount3 setuid-root podnosi priorytet

Część release dotyczy fusermount3, które działa z podniesionymi uprawnieniami — atakujący lokalny nie musi przejmować procesu przez memory corruption; wystarczy skłonić root-owned helper do operacji na nieoczekiwanym obiekcie (symlink TOCTOU, argument confusion, brak O_NOFOLLOW). Checklist: runtime .so ≥ 3.18.3, restart daemonów, custom IO wyłączone (chyba że świadomie wymagane), fusermount3 z 3.18.3, brak build/runtime mismatch, przetestowane KILLPRIV_V2 dla write/O_TRUNC.

Wniosek

libfuse 3.18.3 pokazuje dwie klasy problemów: najbezpieczniejszy fix czasem polega na tym, że ryzykowna funkcja znika z default build; a poprawnie przebudowany artifact może nie być remediated, jeśli runtime ładuje starszą bibliotekę o tej samej major/minor. Closure = build provenance + runtime evidence.

Powiązane na blogu

Źródła

Nota redakcyjna: stan informacji 9 września 2026. libfuse 3.18.3 wyłącza custom IO domyślnie i dodaje kill_suidgid, którego stary runtime nie propaguje (FUSE_VERSION bez patch level). Artykuł koncentruje się na build provenance i runtime evidence jako warunkach closure.

Zapamiętaj jedno

Nawet poprawnie przebudowany artifact może nie być remediated, jeśli w runtime ładuje starszą bibliotekę o tej samej major/minor wersji. Closure wymaga nie tylko patch inventory, ale build provenance + runtime evidence.