aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/configfile/config_file.go8
-rw-r--r--internal/fido2/fido2.go2
-rw-r--r--internal/fusefrontend/node_xattr_freebsd.go33
-rw-r--r--internal/fusefrontend_reverse/node_helpers.go16
-rw-r--r--internal/fusefrontend_reverse/node_xattr_freebsd.go17
-rw-r--r--internal/fusefrontend_reverse/root_node.go4
-rwxr-xr-xinternal/siv_aead/benchmark.bash2
-rwxr-xr-xinternal/speed/benchmark.bash2
-rwxr-xr-xinternal/stupidgcm/benchmark.bash2
-rw-r--r--internal/syscallcompat/asuser_freebsd.go24
-rw-r--r--internal/syscallcompat/emulate.go2
-rw-r--r--internal/syscallcompat/emulate_test.go2
-rw-r--r--internal/syscallcompat/quirks_freebsd.go22
-rw-r--r--internal/syscallcompat/sys_common.go2
-rw-r--r--internal/syscallcompat/sys_darwin.go2
-rw-r--r--internal/syscallcompat/sys_freebsd.go160
-rw-r--r--internal/syscallcompat/sys_linux.go3
-rw-r--r--internal/syscallcompat/unix2syscall.go (renamed from internal/syscallcompat/unix2syscall_darwin.go)2
18 files changed, 287 insertions, 18 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/node_xattr_freebsd.go b/internal/fusefrontend/node_xattr_freebsd.go
new file mode 100644
index 0000000..9698283
--- /dev/null
+++ b/internal/fusefrontend/node_xattr_freebsd.go
@@ -0,0 +1,33 @@
+package fusefrontend
+
+import (
+ "golang.org/x/sys/unix"
+
+ "github.com/hanwen/go-fuse/v2/fuse"
+)
+
+const noSuchAttributeError = unix.ENOATTR
+
+func filterXattrSetFlags(flags int) int {
+ return flags
+}
+
+func (n *Node) getXAttr(cAttr string) (out []byte, errno unix.Errno) {
+ // TODO
+ return nil, unix.EOPNOTSUPP
+}
+
+func (n *Node) setXAttr(context *fuse.Context, cAttr string, cData []byte, flags uint32) (errno unix.Errno) {
+ // TODO
+ return unix.EOPNOTSUPP
+}
+
+func (n *Node) removeXAttr(cAttr string) (errno unix.Errno) {
+ // TODO
+ return unix.EOPNOTSUPP
+}
+
+func (n *Node) listXAttr() (out []string, errno unix.Errno) {
+ // TODO
+ return nil, unix.EOPNOTSUPP
+}
diff --git a/internal/fusefrontend_reverse/node_helpers.go b/internal/fusefrontend_reverse/node_helpers.go
index 3165db6..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.
@@ -134,7 +134,7 @@ func (n *Node) lookupLongnameName(ctx context.Context, nameFile string, out *fus
if errno != 0 {
return
}
- if rn.isExcludedPlain(filepath.Join(d.cPath, pName)) {
+ if rn.isExcludedPlain(filepath.Join(d.pPath, pName)) {
errno = syscall.EPERM
return
}
diff --git a/internal/fusefrontend_reverse/node_xattr_freebsd.go b/internal/fusefrontend_reverse/node_xattr_freebsd.go
new file mode 100644
index 0000000..949cf15
--- /dev/null
+++ b/internal/fusefrontend_reverse/node_xattr_freebsd.go
@@ -0,0 +1,17 @@
+package fusefrontend_reverse
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+const noSuchAttributeError = unix.ENOATTR
+
+func (n *Node) getXAttr(cAttr string) (out []byte, errno unix.Errno) {
+ // TODO
+ return nil, unix.EOPNOTSUPP
+}
+
+func (n *Node) listXAttr() (out []string, errno unix.Errno) {
+ // TODO
+ return nil, unix.EOPNOTSUPP
+}
diff --git a/internal/fusefrontend_reverse/root_node.go b/internal/fusefrontend_reverse/root_node.go
index 420ed22..1a668af 100644
--- a/internal/fusefrontend_reverse/root_node.go
+++ b/internal/fusefrontend_reverse/root_node.go
@@ -13,6 +13,7 @@ import (
"github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
+ "github.com/rfjakob/gocryptfs/v2/internal/configfile"
"github.com/rfjakob/gocryptfs/v2/internal/contentenc"
"github.com/rfjakob/gocryptfs/v2/internal/exitcodes"
"github.com/rfjakob/gocryptfs/v2/internal/fusefrontend"
@@ -136,7 +137,8 @@ func (rn *RootNode) findLongnameParent(fd int, diriv []byte, longname string) (p
// excluded (used when -exclude is passed by the user).
func (rn *RootNode) isExcludedPlain(pPath string) bool {
// root dir can't be excluded
- if pPath == "" {
+ // Don't exclude gocryptfs.conf too
+ if pPath == "" || pPath == configfile.ConfReverseName {
return false
}
return rn.excluder != nil && rn.excluder.MatchesPath(pPath)
diff --git a/internal/siv_aead/benchmark.bash b/internal/siv_aead/benchmark.bash
index 40b57b3..400c134 100755
--- a/internal/siv_aead/benchmark.bash
+++ b/internal/siv_aead/benchmark.bash
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
set -eu
diff --git a/internal/speed/benchmark.bash b/internal/speed/benchmark.bash
index d2678a7..699ceb8 100755
--- a/internal/speed/benchmark.bash
+++ b/internal/speed/benchmark.bash
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
set -eu
diff --git a/internal/stupidgcm/benchmark.bash b/internal/stupidgcm/benchmark.bash
index 8681495..8319659 100755
--- a/internal/stupidgcm/benchmark.bash
+++ b/internal/stupidgcm/benchmark.bash
@@ -1,3 +1,3 @@
-#!/bin/bash
+#!/usr/bin/env bash
exec ../speed/benchmark.bash
diff --git a/internal/syscallcompat/asuser_freebsd.go b/internal/syscallcompat/asuser_freebsd.go
new file mode 100644
index 0000000..dfa8e18
--- /dev/null
+++ b/internal/syscallcompat/asuser_freebsd.go
@@ -0,0 +1,24 @@
+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
+// in `context`.
+//
+// If `context` is nil, `f()` is executed directly without switching user id.
+//
+// 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) {
+ 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 91b592b..435c579 100644
--- a/internal/syscallcompat/emulate.go
+++ b/internal/syscallcompat/emulate.go
@@ -1,3 +1,5 @@
+//go:build !freebsd
+
package syscallcompat
import (
diff --git a/internal/syscallcompat/emulate_test.go b/internal/syscallcompat/emulate_test.go
index 16383f2..907ba3a 100644
--- a/internal/syscallcompat/emulate_test.go
+++ b/internal/syscallcompat/emulate_test.go
@@ -1,3 +1,5 @@
+//go:build !freebsd
+
package syscallcompat
import (
diff --git a/internal/syscallcompat/quirks_freebsd.go b/internal/syscallcompat/quirks_freebsd.go
new file mode 100644
index 0000000..c340cea
--- /dev/null
+++ b/internal/syscallcompat/quirks_freebsd.go
@@ -0,0 +1,22 @@
+package syscallcompat
+
+import (
+ "golang.org/x/sys/unix"
+
+ "github.com/rfjakob/gocryptfs/v2/internal/tlog"
+)
+
+// DetectQuirks decides if there are known quirks on the backing filesystem
+// that need to be workarounded.
+//
+// Tested by tests/root_test.TestBtrfsQuirks
+func DetectQuirks(cipherdir string) (q uint64) {
+ var st unix.Statfs_t
+ err := unix.Statfs(cipherdir, &st)
+ if err != nil {
+ tlog.Warn.Printf("DetectQuirks: Statfs on %q failed: %v", cipherdir, err)
+ return 0
+ }
+
+ return q
+}
diff --git a/internal/syscallcompat/sys_common.go b/internal/syscallcompat/sys_common.go
index 3cb9ffa..4f84d98 100644
--- a/internal/syscallcompat/sys_common.go
+++ b/internal/syscallcompat/sys_common.go
@@ -138,7 +138,7 @@ func getxattrSmartBuf(fn func(buf []byte) (int, error)) ([]byte, error) {
buf := make([]byte, GETXATTR_BUFSZ_SMALL)
sz, err := fn(buf)
// Non-existing xattr
- if err == unix.ENODATA {
+ if err == ENODATA {
return nil, err
}
// Underlying fs does not support security.capabilities (example: tmpfs)
diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go
index ef19f24..52d4e0f 100644
--- a/internal/syscallcompat/sys_darwin.go
+++ b/internal/syscallcompat/sys_darwin.go
@@ -24,6 +24,8 @@ const (
RENAME_NOREPLACE = unix.RENAME_EXCL
RENAME_EXCHANGE = unix.RENAME_SWAP
+ ENODATA = unix.ENODATA
+
// Only exists on Linux. Define here to fix build failure, even though
// we will never see this flag.
RENAME_WHITEOUT = 1 << 30
diff --git a/internal/syscallcompat/sys_freebsd.go b/internal/syscallcompat/sys_freebsd.go
new file mode 100644
index 0000000..d88b1cf
--- /dev/null
+++ b/internal/syscallcompat/sys_freebsd.go
@@ -0,0 +1,160 @@
+// Package syscallcompat wraps FreeBSD-specific syscalls
+package syscallcompat
+
+import (
+ "time"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/hanwen/go-fuse/v2/fuse"
+
+ "github.com/rfjakob/gocryptfs/v2/internal/tlog"
+)
+
+const (
+ O_DIRECT = unix.O_DIRECT
+
+ // O_PATH is supported on FreeBSD, but is missing from the sys/unix package
+ // FreeBSD-15.0 /usr/src/sys/sys/fcntl.h:135
+ O_PATH = 0x00400000
+
+ // Only defined on Linux, but we can emulate the functionality on FreeBSD
+ // in Renameat2() below
+ RENAME_NOREPLACE = 0x1
+ RENAME_EXCHANGE = 0x2
+ RENAME_WHITEOUT = 0x4
+
+ // ENODATA is only defined on Linux, but FreeBSD provides ENOATTR
+ ENODATA = unix.ENOATTR
+
+ // 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
+// changing the file size. This guarantees that we don't run out of
+// space while writing a ciphertext block (that would corrupt the block).
+//
+// The fallocate syscall isn't supported on FreeBSD with the same semantics
+// as Linux, in particular the _FALLOC_FL_KEEP_SIZE mode isn't supported.
+func EnospcPrealloc(fd int, off int64, len int64) (err error) {
+ return nil
+}
+
+// Fallocate wraps the posix_fallocate() syscall.
+// Fallocate returns an error if mode is not 0
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ if mode != 0 {
+ 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
+}
+
+// Mknodat wraps the Mknodat syscall.
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
+ return unix.Mknodat(dirfd, path, mode, uint64(dev))
+}
+
+// Dup3 wraps the Dup3 syscall. We want to use Dup3 rather than Dup2 because Dup2
+// is not implemented on arm64.
+func Dup3(oldfd int, newfd int, flags int) (err error) {
+ return unix.Dup3(oldfd, newfd, flags)
+}
+
+// FchmodatNofollow is like Fchmodat but never follows symlinks.
+func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) {
+ return unix.Fchmodat(dirfd, path, mode, unix.AT_SYMLINK_NOFOLLOW)
+}
+
+// LsetxattrUser runs the Lsetxattr syscall in the context of a different user.
+// This is useful when setting ACLs, as the result depends on the user running
+// the operation (see fuse-xfstests generic/375).
+//
+// If `context` is nil, this function behaves like ordinary Lsetxattr.
+func LsetxattrUser(path string, attr string, data []byte, flags int, context *fuse.Context) (err error) {
+ f := func() (int, error) {
+ err := unix.Lsetxattr(path, attr, data, flags)
+ return -1, err
+ }
+ _, err = asUser(f, context)
+ return err
+}
+
+func timesToTimespec(a *time.Time, m *time.Time) []unix.Timespec {
+ ts := make([]unix.Timespec, 2)
+ if a == nil {
+ ts[0] = unix.Timespec{Nsec: unix.UTIME_OMIT}
+ } else {
+ ts[0], _ = unix.TimeToTimespec(*a)
+ }
+ if m == nil {
+ ts[1] = unix.Timespec{Nsec: unix.UTIME_OMIT}
+ } else {
+ ts[1], _ = unix.TimeToTimespec(*m)
+ }
+ return ts
+}
+
+// FutimesNano syscall.
+func FutimesNano(fd int, a *time.Time, m *time.Time) (err error) {
+ ts := timesToTimespec(a, m)
+ return unix.UtimesNanoAt(unix.AT_FDCWD, "", ts, AT_EMPTY_PATH)
+}
+
+// UtimesNanoAtNofollow is like UtimesNanoAt but never follows symlinks.
+// Retries on EINTR.
+func UtimesNanoAtNofollow(dirfd int, path string, a *time.Time, m *time.Time) (err error) {
+ ts := timesToTimespec(a, m)
+ err = retryEINTR(func() error {
+ return unix.UtimesNanoAt(dirfd, path, ts, unix.AT_SYMLINK_NOFOLLOW)
+ })
+ return err
+}
+
+// Getdents syscall with "." and ".." filtered out.
+func Getdents(fd int) ([]fuse.DirEntry, error) {
+ entries, _, err := emulateGetdents(fd)
+ return entries, err
+}
+
+// GetdentsSpecial calls the Getdents syscall,
+// with normal entries and "." / ".." split into two slices.
+func GetdentsSpecial(fd int) (entries []fuse.DirEntry, entriesSpecial []fuse.DirEntry, err error) {
+ return emulateGetdents(fd)
+}
+
+// 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
+ }
+ if flags&(RENAME_NOREPLACE|RENAME_EXCHANGE) == RENAME_NOREPLACE|RENAME_EXCHANGE {
+ return unix.EINVAL
+ }
+
+ if flags&RENAME_NOREPLACE != 0 {
+ var st unix.Stat_t
+ err = unix.Fstatat(newdirfd, newpath, &st, 0)
+ if err == nil {
+ // Assume newpath is an existing file if we can stat() it.
+ // On Linux, RENAME_NOREPLACE fails with EEXIST if newpath
+ // already exists.
+ return unix.EEXIST
+ }
+ }
+ if flags&RENAME_EXCHANGE != 0 {
+ return unix.EINVAL
+ }
+ if flags&RENAME_WHITEOUT != 0 {
+ return unix.EINVAL
+ }
+
+ return unix.Renameat(olddirfd, oldpath, newdirfd, newpath)
+}
diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go
index 71478af..a850ba1 100644
--- a/internal/syscallcompat/sys_linux.go
+++ b/internal/syscallcompat/sys_linux.go
@@ -32,6 +32,9 @@ const (
// 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 (