Public bug reported:
[Impact]
vmhgfs-fuse, the HGFS client that mounts VMware shared folders, keeps its own
attribute cache with a one-second TTL (CACHE_TIMEOUT / HGFS_DEFAULT_TTL). Every
callback that modifies a file refreshes or invalidates that cache —
hgfs_unlink(), hgfs_rmdir(), hgfs_rename() and hgfs_write() call
HgfsInvalidateAttrCache(), hgfs_truncate() calls HgfsSetAttrCache() — except
hgfs_open(). An open with O_TRUNC is handled entirely inside hgfs_open()
(HgfsGetOpenFlags() maps it to HGFS_OPEN_EMPTY / HGFS_OPEN_CREATE_EMPTY), so the
server truncates the file while the client keeps reporting the pre-truncate size
for up to a second.
Any process that truncates a file and then appends to it within that window gets
a corrupted file: lseek(SEEK_END) returns the stale size, the write lands past
the end of the truncated file, and the beginning is a hole of NUL bytes.
git fetch does exactly this on every run — it truncates .git/FETCH_HEAD at the
start and appends to it from a child process about 1.5 s later. FETCH_HEAD ends
up starting with NUL bytes and doubling in size on every fetch, and git pull
fails with:
Your configuration specifies to merge with the ref 'refs/heads/master'
from the remote, but no such ref was fetched.
Every git repository kept on a VMware shared folder is affected. The failure
looks intermittent only because repositories whose fetches take longer than the
one-second TTL happen to escape the window.
This is the root cause behind the long-standing LP: #1579544 ("vmhgfs-fuse
inconsistencies cause Git index corruption and Bus Error crashes", 2016). Part
of what was reported there — the missing invalidation in hgfs_rename() and the
hardcoded five-second cache timeout — was fixed upstream in 2017 (commit
159ff344); the O_TRUNC path is what remains.
Upstream bug (open since 2016):
https://github.com/vmware/open-vm-tools/issues/90
Upstream fix submitted: https://github.com/vmware/open-vm-tools/pull/801
Affected: resolute (2:13.0.10-1ubuntu1) and stonking (2:13.0.10-1ubuntu5).
vmhgfs-fuse is unchanged upstream in stable-13.1.0, so newer releases are
affected as well.
[Test Plan]
On a VM with a VMware shared folder mounted (e.g. /mnt/hgfs/share or an fstab
entry using vmhgfs-fuse), run:
python3 - <<'PY'
import os
p = '/mnt/hgfs/share/probe'
open(p, 'wb').write(b'A' * 236)
os.stat(p) # warm the attribute cache
fd = os.open(p, os.O_WRONLY | os.O_TRUNC); os.close(fd)
fd = os.open(p, os.O_WRONLY | os.O_APPEND)
print(os.lseek(fd, 0, os.SEEK_END)) # 236 = broken, 0 = fixed
os.unlink(p)
PY
Broken: prints 236. Fixed: prints 0. On a local filesystem it always
prints 0.
End-to-end check with git, in a repository on the shared folder:
for i in 1 2 3 4 5; do git fetch -q origin; stat -c%s .git/FETCH_HEAD; done
git pull
Broken: FETCH_HEAD grows 236 -> 472 -> 708 -> 944 -> 1180 bytes and git pull
fails with the message above. Fixed: FETCH_HEAD stays at its natural size and
git pull works repeatedly.
After installing the fixed package the shared folders must be remounted (or the
VM rebooted): running vmhgfs-fuse processes keep the old code.
[Where problems could occur]
The change adds one HgfsInvalidateAttrCache() call on the O_TRUNC path of
hgfs_open(). The only cost is one extra attribute round-trip to the host after
such an open, so a workload that repeatedly truncates files on a shared folder
could see marginally more HGFS traffic. No other code path is touched, and the
call is the same one already used by unlink, rmdir, rename and write. If the
change were wrong, the visible effect would be limited to attribute freshness on
shared folders — no data path, no other filesystems, no other packages.
[Other Info]
Verified on Ubuntu 26.04 (resolute), kernel 7.0.0-29, VMware Workstation host,
by rebuilding 2:13.0.10-1ubuntu1 with the patch and installing it: the
reproducer prints 0, five consecutive fetches keep FETCH_HEAD at 236 bytes, and
git pull succeeds three times in a row.
Note for the resolute upload: the stock 2:13.0.10-1ubuntu1 no longer builds in
resolute, because glib 2.88 turned g_free() and friends into function-like
macros and lib/rpcChannel/glib_stubs.c defines them as plain functions
(LP: #2160197). The attached SRU debdiff therefore also cherry-picks
glib_stubs-undef-g_free.patch from 2:13.0.10-1ubuntu3 in stonking; without it
the build fails before reaching the actual fix.
Two debdiffs are attached:
* ovt-hgfs-stonking.debdiff — 2:13.0.10-1ubuntu5 -> 2:13.0.10-1ubuntu6
(devel)
* ovt-hgfs-resolute-sru.debdiff — 2:13.0.10-1ubuntu1 -> 2:13.0.10-1ubuntu1.1
(SRU)
** Affects: open-vm-tools (Ubuntu)
Importance: Undecided
Status: New
** Tags: patch
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2164929
Title:
vmhgfs-fuse: stale attribute cache after open(O_TRUNC) breaks git pull
on shared folders
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/open-vm-tools/+bug/2164929/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs