diff options
author | Sebastian Lackner | 2017-11-28 01:02:11 +0100 |
---|---|---|
committer | rfjakob | 2017-11-28 09:28:06 +0100 |
commit | ad2720e0f939ce82605549bdb8c8479c285cb7df (patch) | |
tree | 2679efe7be372be510405b4e1f97147a988a8afb /internal/fusefrontend | |
parent | 5a56810603ff9608c98d71cbfb8a6454da4c2261 (diff) |
fusefrontend: allow_other: close race between symlink and chown
Fixes the same problem as described in 72b975867a3b9bdf53fc2da62e2ba4a328d7e4ab,
except for symlinks instead of device nodes.
Diffstat (limited to 'internal/fusefrontend')
-rw-r--r-- | internal/fusefrontend/fs.go | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go index 60d43f0..bb8e1cf 100644 --- a/internal/fusefrontend/fs.go +++ b/internal/fusefrontend/fs.go @@ -427,22 +427,20 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co if err != nil { return fuse.ToStatus(err) } + dirfd, err := os.Open(filepath.Dir(cPath)) + if err != nil { + return fuse.ToStatus(err) + } + defer dirfd.Close() var cTarget string = target if !fs.args.PlaintextNames { // Symlinks are encrypted like file contents (GCM) and base64-encoded cBinTarget := fs.contentEnc.EncryptBlock([]byte(target), 0, nil) cTarget = fs.nameTransform.B64.EncodeToString(cBinTarget) } - // Handle long file name + // Create ".name" file to store long file name (except in PlaintextNames mode) cName := filepath.Base(cPath) if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) { - var dirfd *os.File - dirfd, err = os.Open(filepath.Dir(cPath)) - if err != nil { - return fuse.ToStatus(err) - } - defer dirfd.Close() - // Create ".name" file err = fs.nameTransform.WriteLongName(dirfd, cName, linkName) if err != nil { return fuse.ToStatus(err) @@ -454,16 +452,17 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co } } else { // Create symlink - err = os.Symlink(cTarget, cPath) + err = syscallcompat.Symlinkat(cTarget, int(dirfd.Fd()), cName) } if err != nil { return fuse.ToStatus(err) } // Set owner if fs.args.PreserveOwner { - err = os.Lchown(cPath, int(context.Owner.Uid), int(context.Owner.Gid)) + err = syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(context.Owner.Uid), + int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW) if err != nil { - tlog.Warn.Printf("Mknod: Lchown failed: %v", err) + tlog.Warn.Printf("Symlink: Fchownat failed: %v", err) } } return fuse.OK |