fusefrontend_reverse: secure GetAttr against symlink races
...by using the OpenNofollow helper & Fstatat. Also introduce a helper to convert from unix.Stat_t to syscall.Stat_t. Tracking ticket: https://github.com/rfjakob/gocryptfs/issues/165
This commit is contained in:
parent
03bf604fc0
commit
a3bdc2bf2b
@ -7,6 +7,8 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
"github.com/hanwen/go-fuse/fuse/nodefs"
|
||||
"github.com/hanwen/go-fuse/fuse/pathfs"
|
||||
@ -150,15 +152,13 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
|
||||
if err != nil {
|
||||
return nil, fuse.ToStatus(err)
|
||||
}
|
||||
absPath, _ := rfs.abs(pRelPath, nil)
|
||||
// Stat the backing file
|
||||
var st syscall.Stat_t
|
||||
if relPath == "" {
|
||||
// Look through symlinks for the root dir
|
||||
err = syscall.Stat(absPath, &st)
|
||||
} else {
|
||||
err = syscall.Lstat(absPath, &st)
|
||||
// Stat the backing file/dir using Fstatat
|
||||
var st unix.Stat_t
|
||||
dirFd, err := syscallcompat.OpenNofollow(rfs.args.Cipherdir, filepath.Dir(pRelPath), syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
||||
if err != nil {
|
||||
return nil, fuse.ToStatus(err)
|
||||
}
|
||||
err = syscallcompat.Fstatat(dirFd, filepath.Base(pRelPath), &st, unix.AT_SYMLINK_NOFOLLOW)
|
||||
if err != nil {
|
||||
return nil, fuse.ToStatus(err)
|
||||
}
|
||||
@ -169,7 +169,8 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
|
||||
return nil, fuse.ToStatus(syscall.EOVERFLOW)
|
||||
}
|
||||
var a fuse.Attr
|
||||
a.FromStat(&st)
|
||||
st2 := syscallcompat.Unix2syscall(st)
|
||||
a.FromStat(&st2)
|
||||
// Calculate encrypted file size
|
||||
if a.IsRegular() {
|
||||
a.Size = rfs.contentEnc.PlainSizeToCipherSize(a.Size)
|
||||
|
28
internal/syscallcompat/unix2syscall.go
Normal file
28
internal/syscallcompat/unix2syscall.go
Normal file
@ -0,0 +1,28 @@
|
||||
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,
|
||||
Atim: syscall.Timespec(u.Atim),
|
||||
Mtim: syscall.Timespec(u.Mtim),
|
||||
Ctim: syscall.Timespec(u.Ctim),
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user