diff options
| -rw-r--r-- | internal/configfile/config_file.go | 8 | ||||
| -rw-r--r-- | internal/fido2/fido2.go | 2 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node_helpers.go | 14 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node_xattr_freebsd.go | 34 | ||||
| -rw-r--r-- | internal/syscallcompat/asuser_freebsd.go | 14 | ||||
| -rw-r--r-- | internal/syscallcompat/emulate.go | 2 | ||||
| -rw-r--r-- | internal/syscallcompat/emulate_test.go | 3 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_freebsd.go | 68 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_linux.go | 6 | ||||
| -rw-r--r-- | internal/syscallcompat/unix2syscall.go (renamed from internal/syscallcompat/unix2syscall_darwin.go) | 2 | ||||
| -rw-r--r-- | internal/syscallcompat/unix2syscall_freebsd.go | 28 | ||||
| -rw-r--r-- | tests/cluster/cluster_test.go | 4 | ||||
| -rw-r--r-- | tests/example_filesystems/example_test_helpers.go | 12 | ||||
| -rw-r--r-- | tests/matrix/atime_darwin+freebsd.go (renamed from tests/matrix/atime_darwin.go) | 2 | ||||
| -rw-r--r-- | tests/matrix/atime_freebsd.go | 9 |
15 files changed, 57 insertions, 151 deletions
diff --git a/internal/configfile/config_file.go b/internal/configfile/config_file.go index 28a1ca5..ebd818e 100644 --- a/internal/configfile/config_file.go +++ b/internal/configfile/config_file.go @@ -31,7 +31,7 @@ type FIDO2Params struct { // FIDO2 credential CredentialID []byte // FIDO2 hmac-secret salt - HMACSalt []byte + HMACSalt []byte AssertOptions []string } @@ -118,9 +118,9 @@ func Create(args *CreateArgs) error { if len(args.Fido2CredentialID) > 0 { cf.setFeatureFlag(FlagFIDO2) cf.FIDO2 = &FIDO2Params{ - CredentialID: args.Fido2CredentialID, - HMACSalt: args.Fido2HmacSalt, - AssertOptions: args.Fido2AssertOptions, + CredentialID: args.Fido2CredentialID, + HMACSalt: args.Fido2HmacSalt, + AssertOptions: args.Fido2AssertOptions, } } // Catch bugs and invalid cli flag combinations early diff --git a/internal/fido2/fido2.go b/internal/fido2/fido2.go index e08e589..f47795b 100644 --- a/internal/fido2/fido2.go +++ b/internal/fido2/fido2.go @@ -44,7 +44,7 @@ func callFidoCommand(command fidoCommand, assertOptions []string, device string, var args []string args = append(args, "-G") args = append(args, "-h") - for i := range assertOptions{ + for i := range assertOptions { args = append(args, "-t") args = append(args, assertOptions[i]) } diff --git a/internal/fusefrontend_reverse/node_helpers.go b/internal/fusefrontend_reverse/node_helpers.go index f733689..dc8d928 100644 --- a/internal/fusefrontend_reverse/node_helpers.go +++ b/internal/fusefrontend_reverse/node_helpers.go @@ -17,13 +17,13 @@ import ( ) const ( - // File names are padded to 16-byte multiples, encrypted and - // base64-encoded. We can encode at most 176 bytes to stay below the 255 - // bytes limit: - // * base64(176 bytes) = 235 bytes - // * base64(192 bytes) = 256 bytes (over 255!) - // But the PKCS#7 padding is at least one byte. This means we can only use - // 175 bytes for the file name. +// File names are padded to 16-byte multiples, encrypted and +// base64-encoded. We can encode at most 176 bytes to stay below the 255 +// bytes limit: +// * base64(176 bytes) = 235 bytes +// * base64(192 bytes) = 256 bytes (over 255!) +// But the PKCS#7 padding is at least one byte. This means we can only use +// 175 bytes for the file name. ) // translateSize translates the ciphertext size in `out` into plaintext size. diff --git a/internal/fusefrontend_reverse/node_xattr_freebsd.go b/internal/fusefrontend_reverse/node_xattr_freebsd.go index 0577521..949cf15 100644 --- a/internal/fusefrontend_reverse/node_xattr_freebsd.go +++ b/internal/fusefrontend_reverse/node_xattr_freebsd.go @@ -1,43 +1,17 @@ package fusefrontend_reverse import ( - "fmt" - "golang.org/x/sys/unix" - - "github.com/hanwen/go-fuse/v2/fs" - - "github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" ) const noSuchAttributeError = unix.ENOATTR func (n *Node) getXAttr(cAttr string) (out []byte, errno unix.Errno) { - d, errno := n.prepareAtSyscall("") - if errno != 0 { - return - } - defer unix.Close(d.dirfd) - - procPath := fmt.Sprintf("/proc/self/fd/%d/%s", d.dirfd, d.pName) - pData, err := syscallcompat.Lgetxattr(procPath, cAttr) - if err != nil { - return nil, fs.ToErrno(err) - } - return pData, 0 + // TODO + return nil, unix.EOPNOTSUPP } func (n *Node) listXAttr() (out []string, errno unix.Errno) { - d, errno := n.prepareAtSyscall("") - if errno != 0 { - return - } - defer unix.Close(d.dirfd) - - procPath := fmt.Sprintf("/proc/self/fd/%d/%s", d.dirfd, d.pName) - pNames, err := syscallcompat.Llistxattr(procPath) - if err != nil { - return nil, fs.ToErrno(err) - } - return pNames, 0 + // TODO + return nil, unix.EOPNOTSUPP } diff --git a/internal/syscallcompat/asuser_freebsd.go b/internal/syscallcompat/asuser_freebsd.go index 34ad41f..dfa8e18 100644 --- a/internal/syscallcompat/asuser_freebsd.go +++ b/internal/syscallcompat/asuser_freebsd.go @@ -1,7 +1,11 @@ package syscallcompat import ( + "golang.org/x/sys/unix" + "github.com/hanwen/go-fuse/v2/fuse" + + "github.com/rfjakob/gocryptfs/v2/internal/tlog" ) // asUser runs `f()` under the effective uid, gid, groups specified @@ -9,8 +13,12 @@ import ( // // If `context` is nil, `f()` is executed directly without switching user id. // -// WARNING this function is not complete, and always runs f() as if context is nil. -// FreeBSD does not support changing uid/gid per thread. +// FreeBSD does not support changing uid/gid per thread. If context is not nil, +// an error is returned. func asUser(f func() (int, error), context *fuse.Context) (int, error) { - return f() + if context == nil { + return f() + } + tlog.Warn.Printf("asUser: error, only nil context is supported\n") + return 0, unix.EOPNOTSUPP } diff --git a/internal/syscallcompat/emulate.go b/internal/syscallcompat/emulate.go index cdc4d12..435c579 100644 --- a/internal/syscallcompat/emulate.go +++ b/internal/syscallcompat/emulate.go @@ -1,4 +1,4 @@ -//go:build darwin +//go:build !freebsd package syscallcompat diff --git a/internal/syscallcompat/emulate_test.go b/internal/syscallcompat/emulate_test.go index 37889dc..907ba3a 100644 --- a/internal/syscallcompat/emulate_test.go +++ b/internal/syscallcompat/emulate_test.go @@ -1,4 +1,5 @@ -//go:build darwin +//go:build !freebsd + package syscallcompat import ( diff --git a/internal/syscallcompat/sys_freebsd.go b/internal/syscallcompat/sys_freebsd.go index 874e920..d88b1cf 100644 --- a/internal/syscallcompat/sys_freebsd.go +++ b/internal/syscallcompat/sys_freebsd.go @@ -2,13 +2,13 @@ package syscallcompat import ( - "errors" - "fmt" "time" "golang.org/x/sys/unix" "github.com/hanwen/go-fuse/v2/fuse" + + "github.com/rfjakob/gocryptfs/v2/internal/tlog" ) const ( @@ -29,6 +29,9 @@ const ( // On FreeBSD, we only have O_NOFOLLOW. OpenatFlagNofollowSymlink = unix.O_NOFOLLOW + + // For the utimensat syscall on FreeBSD + AT_EMPTY_PATH = 0x4000 ) // EnospcPrealloc is supposed to preallocate ciphertext space without @@ -45,7 +48,8 @@ func EnospcPrealloc(fd int, off int64, len int64) (err error) { // Fallocate returns an error if mode is not 0 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { if mode != 0 { - return errors.New("fallocate unsupported mode") + tlog.Warn.Printf("Fallocate: unsupported mode\n") + return unix.EOPNOTSUPP } _, _, err = unix.Syscall(unix.SYS_POSIX_FALLOCATE, uintptr(fd), uintptr(off), uintptr(len)) return err @@ -63,37 +67,8 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { } // FchmodatNofollow is like Fchmodat but never follows symlinks. -// -// This should be handled by the AT_SYMLINK_NOFOLLOW flag, but Linux -// does not implement it, so we have to perform an elaborate dance -// with O_PATH and /proc/self/fd. -// -// See also: Qemu implemented the same logic as fchmodat_nofollow(): -// https://git.qemu.org/?p=qemu.git;a=blob;f=hw/9pfs/9p-local.c#l335 func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) { - // Open handle to the filename (but without opening the actual file). - // This succeeds even when we don't have read permissions to the file. - fd, err := unix.Openat(dirfd, path, unix.O_NOFOLLOW|O_PATH, 0) - if err != nil { - return err - } - defer unix.Close(fd) - - // Now we can check the type without the risk of race-conditions. - // Return syscall.ELOOP if it is a symlink. - var st unix.Stat_t - err = unix.Fstat(fd, &st) - if err != nil { - return err - } - if st.Mode&unix.S_IFMT == unix.S_IFLNK { - return unix.ELOOP - } - - // Change mode of the actual file. Fchmod does not work with O_PATH, - // but Chmod via /proc/self/fd works. - procPath := fmt.Sprintf("/proc/self/fd/%d", fd) - return unix.Chmod(procPath, mode) + return unix.Fchmodat(dirfd, path, mode, unix.AT_SYMLINK_NOFOLLOW) } // LsetxattrUser runs the Lsetxattr syscall in the context of a different user. @@ -128,10 +103,7 @@ func timesToTimespec(a *time.Time, m *time.Time) []unix.Timespec { // FutimesNano syscall. func FutimesNano(fd int, a *time.Time, m *time.Time) (err error) { ts := timesToTimespec(a, m) - // To avoid introducing a separate syscall wrapper for futimens() - // (as done in go-fuse, for example), we instead use the /proc/self/fd trick. - procPath := fmt.Sprintf("/proc/self/fd/%d", fd) - return unix.UtimesNanoAt(unix.AT_FDCWD, procPath, ts, 0) + return unix.UtimesNanoAt(unix.AT_FDCWD, "", ts, AT_EMPTY_PATH) } // UtimesNanoAtNofollow is like UtimesNanoAt but never follows symlinks. @@ -156,8 +128,9 @@ func GetdentsSpecial(fd int) (entries []fuse.DirEntry, entriesSpecial []fuse.Dir return emulateGetdents(fd) } -// Renameat2 does not exist on Darwin, so we have to wrap it here. +// Renameat2 does not exist on FreeBSD, so we have to wrap it here. // Retries on EINTR. +// The RENAME_EXCHANGE and RENAME_WHITEOUT flags are not supported. func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { if flags&(RENAME_NOREPLACE|RENAME_EXCHANGE) == RENAME_NOREPLACE|RENAME_EXCHANGE { return unix.EINVAL @@ -177,24 +150,7 @@ func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags } } if flags&RENAME_EXCHANGE != 0 { - // Note that on Linux, RENAME_EXCHANGE can handle oldpath and - // newpath of different file types (e.g. directory and - // symbolic link). On FreeBSD the file types must be the same. - var stold, stnew unix.Stat_t - err = unix.Fstatat(olddirfd, oldpath, &stold, 0) - if err != nil { - // Assume file does not exist if we can't stat() it. - // On Linux, RENAME_EXCHANGE requires both oldpath - // and newpath exist. - return unix.ENOENT - } - err = unix.Fstatat(newdirfd, newpath, &stnew, 0) - if err != nil { - // Assume file does not exist if we can't stat() it. - // On Linux, RENAME_EXCHANGE requires both oldpath - // and newpath exist. - return unix.ENOENT - } + return unix.EINVAL } if flags&RENAME_WHITEOUT != 0 { return unix.EINVAL diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go index 4669d8a..a850ba1 100644 --- a/internal/syscallcompat/sys_linux.go +++ b/internal/syscallcompat/sys_linux.go @@ -29,12 +29,12 @@ const ( RENAME_WHITEOUT = unix.RENAME_WHITEOUT RENAME_EXCHANGE = unix.RENAME_EXCHANGE - // Only defined on Linux - ENODATA = unix.ENODATA - // On Darwin we use O_SYMLINK which allows opening a symlink itself. // On Linux, we only have O_NOFOLLOW. OpenatFlagNofollowSymlink = unix.O_NOFOLLOW + + // Only defined on Linux + ENODATA = unix.ENODATA ) var preallocWarn sync.Once diff --git a/internal/syscallcompat/unix2syscall_darwin.go b/internal/syscallcompat/unix2syscall.go index 5767a27..fa2e8c4 100644 --- a/internal/syscallcompat/unix2syscall_darwin.go +++ b/internal/syscallcompat/unix2syscall.go @@ -1,3 +1,5 @@ +//go:build darwin || freebsd + package syscallcompat import ( diff --git a/internal/syscallcompat/unix2syscall_freebsd.go b/internal/syscallcompat/unix2syscall_freebsd.go deleted file mode 100644 index fe85cf6..0000000 --- a/internal/syscallcompat/unix2syscall_freebsd.go +++ /dev/null @@ -1,28 +0,0 @@ -package syscallcompat - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -// Unix2syscall converts a unix.Stat_t struct to a syscall.Stat_t struct. -// A direct cast does not work because the padding is named differently in -// unix.Stat_t for some reason ("X__unused" in syscall, "_" in unix). -func Unix2syscall(u unix.Stat_t) syscall.Stat_t { - return syscall.Stat_t{ - Dev: u.Dev, - Ino: u.Ino, - Nlink: u.Nlink, - Mode: u.Mode, - Uid: u.Uid, - Gid: u.Gid, - Rdev: u.Rdev, - Size: u.Size, - Blksize: u.Blksize, - Blocks: u.Blocks, - Atimespec: syscall.NsecToTimespec(unix.TimespecToNsec(u.Atim)), - Mtimespec: syscall.NsecToTimespec(unix.TimespecToNsec(u.Mtim)), - Ctimespec: syscall.NsecToTimespec(unix.TimespecToNsec(u.Ctim)), - } -} diff --git a/tests/cluster/cluster_test.go b/tests/cluster/cluster_test.go index 2e969ce..af93bc4 100644 --- a/tests/cluster/cluster_test.go +++ b/tests/cluster/cluster_test.go @@ -27,8 +27,8 @@ import ( // > buffered read/write. // // See also: -// * https://lore.kernel.org/linux-xfs/20190325001044.GA23020@dastard/ -// Dave Chinner: XFS is the only linux filesystem that provides this behaviour. +// - https://lore.kernel.org/linux-xfs/20190325001044.GA23020@dastard/ +// Dave Chinner: XFS is the only linux filesystem that provides this behaviour. func TestClusterConcurrentRW(t *testing.T) { if os.Getenv("ENABLE_CLUSTER_TEST") != "1" { t.Skipf("This test is disabled by default because it fails unless on XFS.\n" + diff --git a/tests/example_filesystems/example_test_helpers.go b/tests/example_filesystems/example_test_helpers.go index 34e5786..5e38721 100644 --- a/tests/example_filesystems/example_test_helpers.go +++ b/tests/example_filesystems/example_test_helpers.go @@ -27,26 +27,26 @@ func checkExampleFS(t *testing.T, dir string, rw bool) { symlink := filepath.Join(dir, "rel") target, err := os.Readlink(symlink) if err != nil { - t.Error(err) + t.Errorf("relative symlink: Readlink: %v", err) return } if target != "status.txt" { - t.Errorf("Unexpected link target: %s\n", target) + t.Errorf("relative symlink: Unexpected link target: %s\n", target) } // Read absolute symlink symlink = filepath.Join(dir, "abs") target, err = os.Readlink(symlink) if err != nil { - t.Error(err) + t.Errorf("absolute symlink: Readlink: %v", err) return } if target != "/a/b/c/d" { - t.Errorf("Unexpected link target: %s\n", target) + t.Errorf("absolute symlink: Unexpected link target: %s\n", target) } if rw { // Test directory operations - test_helpers.TestRename(t, dir) - test_helpers.TestMkdirRmdir(t, dir) + t.Run("TestRename", func(t *testing.T) { test_helpers.TestRename(t, dir) }) + t.Run("TestMkdirRmdir", func(t *testing.T) { test_helpers.TestMkdirRmdir(t, dir) }) } } diff --git a/tests/matrix/atime_darwin.go b/tests/matrix/atime_darwin+freebsd.go index 5f89c69..43db0d5 100644 --- a/tests/matrix/atime_darwin.go +++ b/tests/matrix/atime_darwin+freebsd.go @@ -1,3 +1,5 @@ +//go:build darwin || freebsd + package matrix import ( diff --git a/tests/matrix/atime_freebsd.go b/tests/matrix/atime_freebsd.go deleted file mode 100644 index 5f89c69..0000000 --- a/tests/matrix/atime_freebsd.go +++ /dev/null @@ -1,9 +0,0 @@ -package matrix - -import ( - "syscall" -) - -func extractAtimeMtime(st syscall.Stat_t) [2]syscall.Timespec { - return [2]syscall.Timespec{st.Atimespec, st.Mtimespec} -} |
