diff options
| author | Jakob Unterwurzacher | 2021-02-07 20:01:16 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2021-02-07 20:01:16 +0100 | 
| commit | eaca820e876bfcdc67323eac6dd43ecc420968f2 (patch) | |
| tree | 7d5fe2fef822778d6a78010fa2fa6f5c021f54d5 /internal | |
| parent | bb2484f1520102f4ab6c84400f9eef53d4cdd2ad (diff) | |
fusefrontend: do not encrypt ACLs
Pass through system.posix_acl_access and system.posix_acl_default
unencrypted to fix "cp -a" problems.
"cp -a" uses "setxattr" even to set normal permissions, see
https://www.spinics.net/lists/linux-nfs/msg63986.html .
Fixes https://github.com/rfjakob/gocryptfs/issues/543
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/node_xattr.go | 74 | 
1 files changed, 65 insertions, 9 deletions
| diff --git a/internal/fusefrontend/node_xattr.go b/internal/fusefrontend/node_xattr.go index cbc5804..3855b55 100644 --- a/internal/fusefrontend/node_xattr.go +++ b/internal/fusefrontend/node_xattr.go @@ -10,6 +10,9 @@ import (  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) +// -1 as uint32 +const minus1 = ^uint32(0) +  // xattr names are encrypted like file names, but with a fixed IV.  // Padded with "_xx" for length 16.  var xattrNameIV = []byte("xattr_name_iv_xx") @@ -22,6 +25,13 @@ var xattrStorePrefix = "user.gocryptfs."  // see https://github.com/rfjakob/gocryptfs/issues/515 for details.  var xattrCapability = "security.capability" +// 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. @@ -36,15 +46,34 @@ func (n *Node) Getxattr(ctx context.Context, attr string, dest []byte) (uint32,  		// and it did not cause trouble. Seems cleaner than saying ENODATA.  		return 0, syscall.EOPNOTSUPP  	} -	cAttr := rn.encryptXattrName(attr) -	cData, errno := n.getXAttr(cAttr) -	if errno != 0 { -		return 0, errno +	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 minus1, errno +		} +	} else { +		// encrypted user xattr +		cAttr := rn.encryptXattrName(attr) +		cData, errno := n.getXAttr(cAttr) +		if errno != 0 { +			return 0, errno +		} +		var err error +		data, err = rn.decryptXattrValue(cData) +		if err != nil { +			tlog.Warn.Printf("GetXAttr: %v", err) +			return minus1, syscall.EIO +		} +	} +	// Caller passes size zero to find out how large their buffer should be +	if len(dest) == 0 { +		return uint32(len(data)), 0  	} -	data, err := rn.decryptXattrValue(cData) -	if err != nil { -		tlog.Warn.Printf("GetXAttr: %v", err) -		return ^uint32(0), syscall.EIO +	if len(dest) < len(data) { +		return minus1, syscall.ERANGE  	}  	l := copy(dest, data)  	return uint32(l), 0 @@ -56,6 +85,12 @@ func (n *Node) Getxattr(ctx context.Context, attr string, dest []byte) (uint32,  func (n *Node) Setxattr(ctx context.Context, attr string, data []byte, flags uint32) syscall.Errno {  	rn := n.rootNode()  	flags = uint32(filterXattrSetFlags(int(flags))) + +	// ACLs are passed through without encryption +	if isAcl(attr) { +		return n.setXAttr(attr, data, flags) +	} +  	cAttr := rn.encryptXattrName(attr)  	cData := rn.encryptXattrValue(data)  	return n.setXAttr(cAttr, cData, flags) @@ -66,6 +101,12 @@ func (n *Node) Setxattr(ctx context.Context, attr string, data []byte, flags uin  // This function is symlink-safe through Fremovexattr.  func (n *Node) Removexattr(ctx context.Context, attr string) syscall.Errno {  	rn := n.rootNode() + +	// ACLs are passed through without encryption +	if isAcl(attr) { +		return n.removeXAttr(attr) +	} +  	cAttr := rn.encryptXattrName(attr)  	return n.removeXAttr(cAttr)  } @@ -81,6 +122,11 @@ func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errn  	rn := n.rootNode()  	var buf bytes.Buffer  	for _, curName := range cNames { +		// ACLs are passed through without encryption +		if isAcl(curName) { +			buf.WriteString(curName + "\000") +			continue +		}  		if !strings.HasPrefix(curName, xattrStorePrefix) {  			continue  		} @@ -90,10 +136,20 @@ func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errn  			rn.reportMitigatedCorruption(curName)  			continue  		} +		// We *used to* encrypt ACLs, which caused a lot of problems. +		if isAcl(name) { +			tlog.Warn.Printf("ListXAttr: ignoring deprecated encrypted ACL %q = %q", curName, name) +			rn.reportMitigatedCorruption(curName) +			continue +		}  		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 ^uint32(0), syscall.ERANGE +		return minus1, syscall.ERANGE  	}  	return uint32(copy(dest, buf.Bytes())), 0  } | 
