rfjakob/gocryptfs

utime disallowed by user set with force_owner when not given direct FD on file

charles-dyfis-net opened this issue · 3 comments

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.

After inspecting with -fusedebug, it looks like force_owner behavior has changed between 1.7 and 2.1.

With gocryptfs 1.7, the response to a CREATE or a LOOKUP has the force_owner-specified UID.

With gocryptfs 2.1, the response to a CREATE or a LOOKUP has the underlying UID, ignoring the value specified for force_owner.

#610 fixes this issue, confirming that it is in fact caused by force_owner not being honored for LOOKUP and CREATE.

Test added ( 3b881b0 ) and patch merged ( 8ec872e ), thanks!