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.
This commit is contained in:
Antonio S. Musumeci
2026-04-18 13:47:23 -05:00
committed by trapexit
parent 0c17492c78
commit f5d9a60b9d
2 changed files with 24 additions and 8 deletions
+12 -4
View File
@@ -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_);
}
+12 -4
View File
@@ -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,