diff options
Diffstat (limited to 'internal/fusefrontend')
| -rw-r--r-- | internal/fusefrontend/node_xattr.go | 15 | ||||
| -rw-r--r-- | internal/fusefrontend/node_xattr_darwin.go | 11 | ||||
| -rw-r--r-- | internal/fusefrontend/node_xattr_linux.go | 9 |
3 files changed, 21 insertions, 14 deletions
diff --git a/internal/fusefrontend/node_xattr.go b/internal/fusefrontend/node_xattr.go index 1470a2a..2ca5ff7 100644 --- a/internal/fusefrontend/node_xattr.go +++ b/internal/fusefrontend/node_xattr.go @@ -9,6 +9,7 @@ import ( "github.com/hanwen/go-fuse/v2/fuse" + "github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" "github.com/rfjakob/gocryptfs/v2/internal/tlog" ) @@ -136,10 +137,22 @@ func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errn if rn.args.NoXattr { return 0, 0 } - cNames, errno := n.listXAttr() + // cBuf is the buffer for the encrypted attr names. Double the size of what the user + // requested to allow for ciphertext expansion due to padding and base64 encoding. + // TODO: double-check max expansion factor + cBuf := make([]byte, 2*len(dest)) + sz, errno := n.listXAttr(cBuf) if errno != 0 { return 0, errno } + // A call with empty dest is a size probe as described in man 2 llistxattr. + // Should return the size of the full attr list and success. + // Because we don't know the size of the decrypted names yet, we return the + // size of the encrypted names. This is slightly higher and hence safe. + if len(dest) == 0 { + return uint32(sz), 0 + } + cNames := syscallcompat.ParseListxattrBlob(cBuf[:sz]) var buf bytes.Buffer for _, curName := range cNames { // ACLs are passed through without encryption diff --git a/internal/fusefrontend/node_xattr_darwin.go b/internal/fusefrontend/node_xattr_darwin.go index f8f224f..ad0cd9e 100644 --- a/internal/fusefrontend/node_xattr_darwin.go +++ b/internal/fusefrontend/node_xattr_darwin.go @@ -88,7 +88,7 @@ func (n *Node) removeXAttr(cAttr string) (errno syscall.Errno) { return fs.ToErrno(err) } -func (n *Node) listXAttr() (out []string, errno syscall.Errno) { +func (n *Node) listXAttr(buf []byte) (sz int, errno syscall.Errno) { dirfd, cName, errno := n.prepareAtSyscallMyself() if errno != 0 { return @@ -98,13 +98,10 @@ func (n *Node) listXAttr() (out []string, errno syscall.Errno) { // O_NONBLOCK to not block on FIFOs. fd, err := syscallcompat.Openat(dirfd, cName, syscall.O_RDONLY|syscall.O_NONBLOCK|syscall.O_NOFOLLOW, 0) if err != nil { - return nil, fs.ToErrno(err) + return 0, fs.ToErrno(err) } defer syscall.Close(fd) - cNames, err := syscallcompat.Flistxattr(fd) - if err != nil { - return nil, fs.ToErrno(err) - } - return cNames, 0 + sz, err = unix.Flistxattr(fd, buf) + return sz, fs.ToErrno(err) } diff --git a/internal/fusefrontend/node_xattr_linux.go b/internal/fusefrontend/node_xattr_linux.go index 9964212..d1747e8 100644 --- a/internal/fusefrontend/node_xattr_linux.go +++ b/internal/fusefrontend/node_xattr_linux.go @@ -57,7 +57,7 @@ func (n *Node) removeXAttr(cAttr string) (errno syscall.Errno) { return fs.ToErrno(unix.Lremovexattr(procPath, cAttr)) } -func (n *Node) listXAttr() (out []string, errno syscall.Errno) { +func (n *Node) listXAttr(buf []byte) (sz int, errno syscall.Errno) { dirfd, cName, errno := n.prepareAtSyscallMyself() if errno != 0 { return @@ -65,9 +65,6 @@ func (n *Node) listXAttr() (out []string, errno syscall.Errno) { defer syscall.Close(dirfd) procPath := fmt.Sprintf("/proc/self/fd/%d/%s", dirfd, cName) - cNames, err := syscallcompat.Llistxattr(procPath) - if err != nil { - return nil, fs.ToErrno(err) - } - return cNames, 0 + sz, err := unix.Llistxattr(procPath, buf) + return sz, fs.ToErrno(err) } |
