diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-03-11 04:02:27 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-03-11 04:02:27 -0500 |
| commit | eb8c20695643923598d0516e86b1fcef144f65fa (patch) | |
| tree | d2a4df0c6084bc9f112bd01b3e7ec35e01731aa3 /src | |
| parent | 983c9c04666bca79033766263094fe1d36588ec9 (diff) | |
Fix FUSE passthrough: use proper API, drop LD_LIBRARY_PATH, auto-apply cap
- Use fuse_passthrough_open/close API instead of raw fd assignment to
fi->backing_id, which caused EIO on every file open through the VFS
- Remove LD_LIBRARY_PATH from launcher script — DT_RPATH handles lib
resolution, and LD_LIBRARY_PATH triggers AT_SECURE which drops file
capabilities (cap_sys_admin) needed for passthrough
- Auto-detect missing cap_sys_admin at mount time and prompt via pkexec
to re-apply it (handles binary copy/update/extract losing the cap)
- Disable passthrough for session if fuse_passthrough_open fails, avoiding
"Operation not permitted" spam in terminal
- Fix Nix flake: tinyxml2 → tinyxml-2, xorg.lib* → top-level names
- CI: eliminate artifact zip round-trip for GitHub releases
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/src/organizercore.cpp | 42 | ||||
| -rw-r--r-- | src/src/vfs/mo2filesystem.cpp | 30 | ||||
| -rw-r--r-- | src/src/vfs/mo2filesystem.h | 1 |
3 files changed, 66 insertions, 7 deletions
diff --git a/src/src/organizercore.cpp b/src/src/organizercore.cpp index 3896039..b42c3ed 100644 --- a/src/src/organizercore.cpp +++ b/src/src/organizercore.cpp @@ -663,9 +663,49 @@ void OrganizerCore::prepareVFS() }
// FUSE passthrough: read the per-instance setting and pass it to the VFS.
+ // The binary needs CAP_SYS_ADMIN for passthrough to work — it can be lost
+ // when the binary is copied, updated, or extracted to a new location.
{
- const bool passthrough =
+ bool passthrough =
QSettings().value("fluorine/fuse_passthrough", false).toBool();
+
+ if (passthrough) {
+ // Check if the binary actually has cap_sys_admin right now.
+ const QString binary = QCoreApplication::applicationFilePath();
+ QProcess getcap;
+ getcap.setProgram("getcap");
+ getcap.setArguments({binary});
+ getcap.start();
+ getcap.waitForFinished(5000);
+ const QString caps = QString::fromUtf8(getcap.readAllStandardOutput());
+ const bool hasCap = caps.contains("cap_sys_admin");
+
+ if (!hasCap) {
+ std::fprintf(stderr,
+ "[VFS] passthrough enabled but binary lacks cap_sys_admin "
+ "— requesting via pkexec...\n");
+ QProcess setcap;
+ setcap.setProgram("pkexec");
+ setcap.setArguments({"setcap", "cap_sys_admin+ep", binary});
+ setcap.start();
+ setcap.waitForFinished(60000);
+
+ if (setcap.exitCode() != 0) {
+ std::fprintf(stderr,
+ "[VFS] failed to set cap_sys_admin — disabling passthrough\n");
+ passthrough = false;
+ } else {
+ // The capability is on the file now, but the running process won't
+ // have it until next exec. Disable passthrough for this session —
+ // it will work automatically on next launch.
+ std::fprintf(stderr,
+ "[VFS] cap_sys_admin applied to binary — passthrough "
+ "will activate on next launch\n");
+ passthrough = false;
+ }
+ }
+ }
+
m_USVFS.setPassthroughEnabled(passthrough);
}
#endif
diff --git a/src/src/vfs/mo2filesystem.cpp b/src/src/vfs/mo2filesystem.cpp index 42e90c0..6c8cb87 100644 --- a/src/src/vfs/mo2filesystem.cpp +++ b/src/src/vfs/mo2filesystem.cpp @@ -1056,12 +1056,25 @@ void mo2_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) ptFd = open(realPath.c_str(), O_RDONLY); } if (ptFd >= 0) { - fi->backing_id = static_cast<uint32_t>(ptFd); - // Store the fd so we can close it on release - std::scoped_lock lock(ctx->open_files_mutex); - auto it = ctx->open_files.find(fh); - if (it != ctx->open_files.end()) { - it->second.fd = ptFd; + int backingId = fuse_passthrough_open(req, ptFd); + if (backingId > 0) { + fi->backing_id = backingId; + // Store the fd so we can close it on release + std::scoped_lock lock(ctx->open_files_mutex); + auto it = ctx->open_files.find(fh); + if (it != ctx->open_files.end()) { + it->second.fd = ptFd; + it->second.backing_id = backingId; + } + } else { + // Passthrough registration failed (e.g. missing cap_sys_admin at + // runtime). Disable passthrough for the rest of this session to + // avoid spamming "Operation not permitted" on every open. + close(ptFd); + ctx->passthrough_active = false; + std::fprintf(stderr, + "[VFS] fuse_passthrough_open failed — disabling " + "passthrough for this session\n"); } } } @@ -1667,6 +1680,11 @@ void mo2_release(fuse_req_t req, fuse_ino_t /*ino*/, struct fuse_file_info* fi) std::scoped_lock lock(ctx->open_files_mutex); auto it = ctx->open_files.find(fi->fh); if (it != ctx->open_files.end()) { + if constexpr (FUSE_CAP_PASSTHROUGH != 0) { + if (it->second.backing_id > 0) { + fuse_passthrough_close(req, it->second.backing_id); + } + } if (it->second.fd >= 0) { close(it->second.fd); } diff --git a/src/src/vfs/mo2filesystem.h b/src/src/vfs/mo2filesystem.h index 2883a18..9b27d76 100644 --- a/src/src/vfs/mo2filesystem.h +++ b/src/src/vfs/mo2filesystem.h @@ -39,6 +39,7 @@ struct Mo2FsContext struct OpenFile { int fd = -1; + int backing_id = 0; // FUSE passthrough backing ID (0 = not using passthrough) std::string real_path; bool writable = false; bool is_backing = false; |
