From f5d9a60b9db3dd655b2bdb5cf43454211546379c Mon Sep 17 00:00:00 2001 From: "Antonio S. Musumeci" Date: Sat, 18 Apr 2026 00:57:31 -0400 Subject: [PATCH] fuse_getattr/statx: populate timeouts in fake_root and controlfile replies The fake-root and control-file fast paths returned a synthetic stat without touching the timeout struct. Callers that took those paths ended up sending whatever the timeout struct happened to hold, which is uninitialized memory for the control-file path and whatever a prior call left there for the fake-root path. Kernel behavior is undefined when the timeout is garbage. Pass timeout_ into both helpers and set entry/attr from the configured cache values. --- src/fuse_getattr.cpp | 16 ++++++++++++---- src/fuse_statx_supported.icpp | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/fuse_getattr.cpp b/src/fuse_getattr.cpp index dc3c932b..23174d3c 100644 --- a/src/fuse_getattr.cpp +++ b/src/fuse_getattr.cpp @@ -73,7 +73,8 @@ _set_stat_if_leads_to_reg(const fs::path &path_, static int -_getattr_fake_root(struct stat *st_) +_getattr_fake_root(struct stat *st_, + fuse_timeouts_t *timeout_) { st_->st_dev = 0; st_->st_ino = 0; @@ -89,12 +90,16 @@ _getattr_fake_root(struct stat *st_) st_->st_mtime = 0; st_->st_ctime = 0; + timeout_->entry = cfg.cache_entry; + timeout_->attr = cfg.cache_attr; + return 0; } static int -_getattr_controlfile(struct stat *st_) +_getattr_controlfile(struct stat *st_, + fuse_timeouts_t *timeout_) { static const uid_t uid = ::getuid(); static const gid_t gid = ::getgid(); @@ -114,6 +119,9 @@ _getattr_controlfile(struct stat *st_) st_->st_mtime = now; st_->st_ctime = now; + timeout_->entry = cfg.cache_entry; + timeout_->attr = cfg.cache_attr; + return 0; } @@ -189,7 +197,7 @@ _getattr(const fs::path &fusepath_, cfg.symlinkify_timeout, cfg.follow_symlinks); if((rv < 0) && Config::is_rootdir(fusepath_)) - return ::_getattr_fake_root(st_); + return ::_getattr_fake_root(st_,timeout_); timeout_->entry = ((rv >= 0) ? cfg.cache_entry : @@ -225,7 +233,7 @@ FUSE::getattr(const fs::path &fusepath_, fuse_timeouts_t *timeout_) { if(Config::is_ctrl_file(fusepath_)) - return ::_getattr_controlfile(st_); + return ::_getattr_controlfile(st_,timeout_); return ::_getattr(fusepath_,st_,timeout_); } diff --git a/src/fuse_statx_supported.icpp b/src/fuse_statx_supported.icpp index 32f8eb19..84a81018 100644 --- a/src/fuse_statx_supported.icpp +++ b/src/fuse_statx_supported.icpp @@ -75,7 +75,8 @@ _set_stat_if_leads_to_reg(const fs::path &path_, static int -_statx_fake_root(struct fuse_statx *st_) +_statx_fake_root(struct fuse_statx *st_, + fuse_timeouts_t *timeout_) { st_->ino = 0; st_->mode = (S_IFDIR|S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); @@ -88,12 +89,16 @@ _statx_fake_root(struct fuse_statx *st_) st_->mtime.tv_sec = 0; st_->ctime.tv_sec = 0; + timeout_->entry = cfg.cache_entry; + timeout_->attr = cfg.cache_attr; + return 0; } static int -_statx_controlfile(struct fuse_statx *st_) +_statx_controlfile(struct fuse_statx *st_, + fuse_timeouts_t *timeout_) { static const uid_t uid = ::getuid(); static const gid_t gid = ::getgid(); @@ -110,6 +115,9 @@ _statx_controlfile(struct fuse_statx *st_) st_->mtime.tv_sec = now; st_->ctime.tv_sec = now; + timeout_->entry = cfg.cache_entry; + timeout_->attr = cfg.cache_attr; + return 0; } @@ -192,7 +200,7 @@ _statx(const fs::path &fusepath_, cfg.symlinkify_timeout, cfg.follow_symlinks); if((rv < 0) && Config::is_rootdir(fusepath_)) - return ::_statx_fake_root(st_); + return ::_statx_fake_root(st_,timeout_); timeout_->entry = ((rv >= 0) ? cfg.cache_entry : @@ -237,7 +245,7 @@ FUSE::statx(const fuse_req_ctx_t *ctx_, const fs::path fusepath{fusepath_}; if(Config::is_ctrl_file(fusepath)) - return ::_statx_controlfile(st_); + return ::_statx_controlfile(st_,timeout_); return ::_statx(fusepath, flags_|AT_STATX_DONT_SYNC,