diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-03-11 04:40:30 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-03-11 04:40:30 -0500 |
| commit | b3f1ba196c384e3d96f84862a1e6cf21311a9cef (patch) | |
| tree | 7a06ae86873ad33c5df8c1bf243c5a18e8c006a4 /src | |
| parent | 8b0057aca5f80bf6eab15c898e7d373d4c003453 (diff) | |
Check CAP_SYS_ADMIN at runtime before negotiating FUSE passthrough
Negotiating passthrough without the capability caused Wine/Proton DLL
loading failures (SKSE plugins returning error 0x36). Now checks the
process's effective capability set via libcap before telling the kernel
we want passthrough. Also adds qt.conf for AT_SECURE compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/src/vfs/mo2filesystem.cpp | 21 |
2 files changed, 23 insertions, 1 deletions
diff --git a/src/src/CMakeLists.txt b/src/src/CMakeLists.txt index d7a7642..fa5d658 100644 --- a/src/src/CMakeLists.txt +++ b/src/src/CMakeLists.txt @@ -10,6 +10,7 @@ find_package(Boost CONFIG REQUIRED COMPONENTS find_package(spdlog CONFIG REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(FUSE3 REQUIRED IMPORTED_TARGET fuse3) +pkg_check_modules(LIBCAP REQUIRED IMPORTED_TARGET libcap) find_package(Threads REQUIRED) qt_standard_project_setup() @@ -110,6 +111,8 @@ target_link_libraries(organizer PRIVATE spdlog::spdlog_header_only # FUSE3 (low-level API) PkgConfig::FUSE3 + # libcap (runtime capability check for passthrough) + PkgConfig::LIBCAP # Linux system libs dl) diff --git a/src/src/vfs/mo2filesystem.cpp b/src/src/vfs/mo2filesystem.cpp index 6c8cb87..908c5bb 100644 --- a/src/src/vfs/mo2filesystem.cpp +++ b/src/src/vfs/mo2filesystem.cpp @@ -2,6 +2,7 @@ #include <fcntl.h> #include <linux/fs.h> +#include <sys/capability.h> #include <sys/time.h> #include <unistd.h> @@ -573,11 +574,29 @@ void mo2_init(void* userdata, struct fuse_conn_info* conn) // Requires: kernel 6.9+, libfuse 3.16+, CAP_SYS_ADMIN on the binary. ctx->passthrough_active = false; if constexpr (FUSE_CAP_PASSTHROUGH != 0) { - if (ctx->passthrough_requested && + // Check if the process actually has CAP_SYS_ADMIN in its effective set. + // Without it, fuse_passthrough_open will fail with EPERM, and negotiating + // passthrough at the kernel level can break Wine/Proton DLL loading. + bool hasCap = false; + { + cap_t caps = cap_get_proc(); + if (caps) { + cap_flag_value_t val = CAP_CLEAR; + cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &val); + hasCap = (val == CAP_SET); + cap_free(caps); + } + } + + if (ctx->passthrough_requested && hasCap && (conn->capable & FUSE_CAP_PASSTHROUGH)) { conn->want |= FUSE_CAP_PASSTHROUGH; ctx->passthrough_active = true; std::fprintf(stderr, "[VFS] FUSE passthrough enabled (kernel supports it)\n"); + } else if (ctx->passthrough_requested && !hasCap) { + std::fprintf(stderr, + "[VFS] FUSE passthrough requested but process lacks " + "CAP_SYS_ADMIN. Falling back to userspace I/O.\n"); } else if (ctx->passthrough_requested) { std::fprintf(stderr, "[VFS] FUSE passthrough requested but NOT supported by kernel " |
