-
Notifications
You must be signed in to change notification settings - Fork 256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Xattrs support in reverse mode #878
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,9 +12,6 @@ import ( | |
"github.com/rfjakob/gocryptfs/v2/internal/tlog" | ||
) | ||
|
||
// -1 as uint32 | ||
const minus1 = ^uint32(0) | ||
|
||
// We store encrypted xattrs under this prefix plus the base64-encoded | ||
// encrypted original name. | ||
var xattrStorePrefix = "user.gocryptfs." | ||
|
@@ -50,13 +47,13 @@ func (n *Node) Getxattr(ctx context.Context, attr string, dest []byte) (uint32, | |
var errno syscall.Errno | ||
data, errno = n.getXAttr(attr) | ||
if errno != 0 { | ||
return minus1, errno | ||
return 0, errno | ||
} | ||
} else { | ||
// encrypted user xattr | ||
cAttr, err := rn.encryptXattrName(attr) | ||
if err != nil { | ||
return minus1, syscall.EIO | ||
return 0, syscall.EIO | ||
} | ||
cData, errno := n.getXAttr(cAttr) | ||
if errno != 0 { | ||
|
@@ -65,15 +62,11 @@ func (n *Node) Getxattr(ctx context.Context, attr string, dest []byte) (uint32, | |
data, err = rn.decryptXattrValue(cData) | ||
if err != nil { | ||
tlog.Warn.Printf("GetXAttr: %v", err) | ||
return minus1, syscall.EIO | ||
return 0, syscall.EIO | ||
} | ||
} | ||
// Caller passes size zero to find out how large their buffer should be | ||
if len(dest) == 0 { | ||
return uint32(len(data)), 0 | ||
} | ||
Comment on lines
-71
to
-74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why remove this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The behavior of the function is described in: |
||
if len(dest) < len(data) { | ||
return minus1, syscall.ERANGE | ||
return uint32(len(data)), syscall.ERANGE | ||
} | ||
l := copy(dest, data) | ||
return uint32(l), 0 | ||
|
@@ -155,12 +148,8 @@ func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errn | |
} | ||
buf.WriteString(name + "\000") | ||
} | ||
// Caller passes size zero to find out how large their buffer should be | ||
if len(dest) == 0 { | ||
return uint32(buf.Len()), 0 | ||
} | ||
if buf.Len() > len(dest) { | ||
return minus1, syscall.ERANGE | ||
return uint32(buf.Len()), syscall.ERANGE | ||
} | ||
return uint32(copy(dest, buf.Bytes())), 0 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// Package fusefrontend_reverse interfaces directly with the go-fuse library. | ||
package fusefrontend_reverse | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"syscall" | ||
|
||
"github.com/rfjakob/gocryptfs/v2/internal/pathiv" | ||
) | ||
|
||
// We store encrypted xattrs under this prefix plus the base64-encoded | ||
// encrypted original name. | ||
var xattrStorePrefix = "user.gocryptfs." | ||
|
||
// isAcl returns true if the attribute name is for storing ACLs | ||
// | ||
// ACLs are passed through without encryption | ||
func isAcl(attr string) bool { | ||
return attr == "system.posix_acl_access" || attr == "system.posix_acl_default" | ||
} | ||
|
||
// GetXAttr - FUSE call. Reads the value of extended attribute "attr". | ||
// | ||
// This function is symlink-safe through Fgetxattr. | ||
func (n *Node) Getxattr(ctx context.Context, attr string, dest []byte) (uint32, syscall.Errno) { | ||
rn := n.rootNode() | ||
var data []byte | ||
// ACLs are passed through without encryption | ||
if isAcl(attr) { | ||
var errno syscall.Errno | ||
data, errno = n.getXAttr(attr) | ||
if errno != 0 { | ||
return 0, errno | ||
} | ||
} else { | ||
pAttr, err := rn.decryptXattrName(attr) | ||
if err != nil { | ||
return 0, syscall.EINVAL | ||
} | ||
pData, errno := n.getXAttr(pAttr) | ||
if errno != 0 { | ||
return 0, errno | ||
} | ||
nonce := pathiv.Derive(n.Path()+"\000"+attr, pathiv.PurposeXattrIV) | ||
data = rn.encryptXattrValue(pData, nonce) | ||
} | ||
if len(dest) < len(data) { | ||
return uint32(len(data)), syscall.ERANGE | ||
} | ||
l := copy(dest, data) | ||
return uint32(l), 0 | ||
} | ||
|
||
// ListXAttr - FUSE call. Lists extended attributes on the file at "relPath". | ||
// | ||
// This function is symlink-safe through Flistxattr. | ||
func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errno) { | ||
pNames, errno := n.listXAttr() | ||
if errno != 0 { | ||
return 0, errno | ||
} | ||
rn := n.rootNode() | ||
var buf bytes.Buffer | ||
for _, pName := range pNames { | ||
// ACLs are passed through without encryption | ||
if isAcl(pName) { | ||
buf.WriteString(pName + "\000") | ||
continue | ||
} | ||
cName, err := rn.encryptXattrName(pName) | ||
if err != nil { | ||
continue | ||
} | ||
buf.WriteString(cName + "\000") | ||
} | ||
if buf.Len() > len(dest) { | ||
return uint32(buf.Len()), syscall.ERANGE | ||
} | ||
return uint32(copy(dest, buf.Bytes())), 0 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package fusefrontend_reverse | ||
|
||
import ( | ||
"syscall" | ||
|
||
"github.com/hanwen/go-fuse/v2/fs" | ||
|
||
"github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" | ||
) | ||
|
||
func (n *Node) getXAttr(cAttr string) (out []byte, errno syscall.Errno) { | ||
d, errno := n.prepareAtSyscall("") | ||
if errno != 0 { | ||
return | ||
} | ||
defer syscall.Close(d.dirfd) | ||
|
||
// O_NONBLOCK to not block on FIFOs. | ||
fd, err := syscallcompat.Openat(d.dirfd, d.pName, syscall.O_RDONLY|syscall.O_NONBLOCK|syscall.O_NOFOLLOW, 0) | ||
if err != nil { | ||
return nil, fs.ToErrno(err) | ||
} | ||
defer syscall.Close(fd) | ||
|
||
cData, err := syscallcompat.Fgetxattr(fd, cAttr) | ||
if err != nil { | ||
return nil, fs.ToErrno(err) | ||
} | ||
|
||
return cData, 0 | ||
} | ||
|
||
func (n *Node) listXAttr() (out []string, errno syscall.Errno) { | ||
d, errno := n.prepareAtSyscall("") | ||
if errno != 0 { | ||
return | ||
} | ||
defer syscall.Close(d.dirfd) | ||
|
||
// O_NONBLOCK to not block on FIFOs. | ||
fd, err := syscallcompat.Openat(d.dirfd, d.pName, syscall.O_RDONLY|syscall.O_NONBLOCK|syscall.O_NOFOLLOW, 0) | ||
if err != nil { | ||
return nil, fs.ToErrno(err) | ||
} | ||
defer syscall.Close(fd) | ||
|
||
pNames, err := syscallcompat.Flistxattr(fd) | ||
if err != nil { | ||
return nil, fs.ToErrno(err) | ||
} | ||
return pNames, 0 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package fusefrontend_reverse | ||
|
||
import ( | ||
"fmt" | ||
"syscall" | ||
|
||
"github.com/hanwen/go-fuse/v2/fs" | ||
|
||
"github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" | ||
) | ||
|
||
func (n *Node) getXAttr(cAttr string) (out []byte, errno syscall.Errno) { | ||
d, errno := n.prepareAtSyscall("") | ||
if errno != 0 { | ||
return | ||
} | ||
defer syscall.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 | ||
} | ||
|
||
func (n *Node) listXAttr() (out []string, errno syscall.Errno) { | ||
d, errno := n.prepareAtSyscall("") | ||
if errno != 0 { | ||
return | ||
} | ||
defer syscall.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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not -1 like https://man7.org/linux/man-pages/man2/getxattr.2.html#RETURN_VALUE says?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The behavior of the function is described in:
https://github.com/hanwen/go-fuse/blob/756578b6a0b03511fde147b2f23c5b97217ede27/fs/api.go#L312
Returning -1 does not make sense, since it is ignored on errors:
https://github.com/hanwen/go-fuse/blob/756578b6a0b03511fde147b2f23c5b97217ede27/fuse/opcode.go#L294