-
Notifications
You must be signed in to change notification settings - Fork 296
Description
With a file stored on gocryptfs 2.1, when force_owner is used to present the mount point as owned by a different (non-root) user, a process running as that non-root user can successfully run the following Python code to copy a file while preserving its timestamp:
#!/usr/bin/env python3
import os, sys, shutil
source_name, dest_name = sys.argv[1:3]
src_stat = os.lstat(source_name)
with open(source_name, 'rb') as infile:
with open(dest_name, 'wb') as outfile:
shutil.copyfileobj(infile, outfile)
outfile.flush()
os.utime(outfile.fileno(), (src_stat.st_atime, src_stat.st_mtime))...but cannot run the following, which differs only that it passes the utimensat syscall a path to the target file as opposed to an already-opened file handle:
#!/usr/bin/env python3
import os, sys, shutil
source_name, dest_name = sys.argv[1:3]
src_stat = os.lstat(source_name)
with open(source_name, 'rb') as infile:
with open(dest_name, 'wb') as outfile:
shutil.copyfileobj(infile, outfile)
os.utime(source_name, (src_stat.st_atime, src_stat.st_mtime))...which receives a PermissionError: [Errno 1] Operation not permitted
This issue did not exist in gocryptfs 1.7 -- and it impacts far more applications than just the reproducer above (for example, rsync passes utimensat a relative path to open and is subject to this bug).
In the environment where this is reproduced, the backing store for gocryptfs is owned by a special-purpose user that does nothing other than own this directory and run gocryptfs processes; the mount options include -force_owner with the uid and gid of the user running the above code (which is different from the account running gocryptfs itself), and -allow_other.