From 735e2aa65b25e24743c4a60f763633bcba982b72 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 12 Jul 2020 13:35:37 +0200 Subject: [PATCH] v2api: fix Mkdir crash when using plaintextnames --- internal/fusefrontend/node_dir_ops.go | 96 +++++++++++++++------------ tests/test_helpers/helpers.go | 2 +- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/internal/fusefrontend/node_dir_ops.go b/internal/fusefrontend/node_dir_ops.go index 5cf58ea..8cc158d 100644 --- a/internal/fusefrontend/node_dir_ops.go +++ b/internal/fusefrontend/node_dir_ops.go @@ -68,66 +68,76 @@ func (n *Node) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.En if rn.args.PreserveOwner { caller, _ = fuse.FromContext(ctx) } + + var st syscall.Stat_t + if rn.args.PlaintextNames { err = syscallcompat.MkdiratUser(dirfd, cName, mode, caller) - return nil, fs.ToErrno(err) - } - - // We need write and execute permissions to create gocryptfs.diriv. - // Also, we need read permissions to open the directory (to avoid - // race-conditions between getting and setting the mode). - origMode := mode - mode = mode | 0700 - - // Handle long file name - if nametransform.IsLongContent(cName) { - // Create ".name" - err = rn.nameTransform.WriteLongNameAt(dirfd, cName, newPath) if err != nil { return nil, fs.ToErrno(err) } - - // Create directory - err = rn.mkdirWithIv(dirfd, cName, mode, caller) + var ust unix.Stat_t + err = syscallcompat.Fstatat(dirfd, cName, &ust, unix.AT_SYMLINK_NOFOLLOW) if err != nil { - nametransform.DeleteLongNameAt(dirfd, cName) return nil, fs.ToErrno(err) } + st = syscallcompat.Unix2syscall(ust) } else { - err = rn.mkdirWithIv(dirfd, cName, mode, caller) + // We need write and execute permissions to create gocryptfs.diriv. + // Also, we need read permissions to open the directory (to avoid + // race-conditions between getting and setting the mode). + origMode := mode + mode = mode | 0700 + + // Handle long file name + if nametransform.IsLongContent(cName) { + // Create ".name" + err = rn.nameTransform.WriteLongNameAt(dirfd, cName, newPath) + if err != nil { + return nil, fs.ToErrno(err) + } + + // Create directory + err = rn.mkdirWithIv(dirfd, cName, mode, caller) + if err != nil { + nametransform.DeleteLongNameAt(dirfd, cName) + return nil, fs.ToErrno(err) + } + } else { + err = rn.mkdirWithIv(dirfd, cName, mode, caller) + if err != nil { + return nil, fs.ToErrno(err) + } + } + + fd, err := syscallcompat.Openat(dirfd, cName, + syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) if err != nil { + tlog.Warn.Printf("Mkdir %q: Openat failed: %v", cName, err) return nil, fs.ToErrno(err) } + defer syscall.Close(fd) + + err = syscall.Fstat(fd, &st) + if err != nil { + tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err) + return nil, fs.ToErrno(err) + } + + // Fix permissions + if origMode != mode { + // Preserve SGID bit if it was set due to inheritance. + origMode = uint32(st.Mode&^0777) | origMode + err = syscall.Fchmod(fd, origMode) + if err != nil { + tlog.Warn.Printf("Mkdir %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err) + } + } } - fd, err := syscallcompat.Openat(dirfd, cName, - syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) - if err != nil { - tlog.Warn.Printf("Mkdir %q: Openat failed: %v", cName, err) - return nil, fs.ToErrno(err) - } - defer syscall.Close(fd) - - // Get unique inode number - var st syscall.Stat_t - err = syscall.Fstat(fd, &st) - if err != nil { - tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err) - return nil, fs.ToErrno(err) - } // Create child node ch := n.newChild(ctx, &st, out) - // Set mode - if origMode != mode { - // Preserve SGID bit if it was set due to inheritance. - origMode = uint32(st.Mode&^0777) | origMode - err = syscall.Fchmod(fd, origMode) - if err != nil { - tlog.Warn.Printf("Mkdir %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err) - } - } - return ch, 0 } diff --git a/tests/test_helpers/helpers.go b/tests/test_helpers/helpers.go index 2d23586..37c82c1 100644 --- a/tests/test_helpers/helpers.go +++ b/tests/test_helpers/helpers.go @@ -280,7 +280,7 @@ func TestRename(t *testing.T, plainDir string) { } err = syscall.Rename(file1, file2) if err != nil { - t.Error(err) + t.Errorf("Rename: %v", err) return } syscall.Unlink(file2)