From c004db611a47a1562addd7079c9a926cc75fe9fc Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Mon, 13 May 2019 21:42:18 +0000 Subject: [PATCH] Add open flags to operation structs The open flag indicates the type of access we need. Add a test to the memfs server to make sure an open is blocked if the flags and permissions don't match. Signed-off-by: Ronald G. Minnich --- conversions.go | 8 ++++++++ fuseops/ops.go | 3 +++ samples/memfs/memfs.go | 18 ++++++++++++++++++ samples/memfs/memfs_test.go | 25 +++++++++++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/conversions.go b/conversions.go index 66be34f8..276b255a 100644 --- a/conversions.go +++ b/conversions.go @@ -255,8 +255,16 @@ func convertInMessage( } case fusekernel.OpOpen: + type input fusekernel.OpenIn + in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) + + if in == nil { + err = errors.New("Corrupt OpOpen") + return + } o = &fuseops.OpenFileOp{ Inode: fuseops.InodeID(inMsg.Header().Nodeid), + Flag: int(in.Flags), } case fusekernel.OpOpendir: diff --git a/fuseops/ops.go b/fuseops/ops.go index 56fe89c3..179611ab 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -593,6 +593,9 @@ type OpenFileOp struct { // layer. This allows for filesystems whose file sizes are not known in // advance, for example, because contents are generated on the fly. UseDirectIO bool + + // User-provided flags to open(2). See http://go/godoc/os/#OpenFile. + Flag int } // Read data from a file previously opened with CreateFile or OpenFile. diff --git a/samples/memfs/memfs.go b/samples/memfs/memfs.go index 909b9e0a..c77f1e63 100644 --- a/samples/memfs/memfs.go +++ b/samples/memfs/memfs.go @@ -26,6 +26,7 @@ import ( "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" "github.com/jacobsa/syncutil" + "golang.org/x/sys/unix" ) type memFS struct { @@ -615,6 +616,23 @@ func (fs *memFS) OpenFile( if !inode.isFile() { panic("Found non-file.") } + // The flags are not a bitmask, they are a 2-bit field + // with, technically, only 3 legal values. But testing shows + // that there are 4 legal values, so we accomodate that. + var perm int + switch op.Flag & unix.O_ACCMODE { + case unix.O_RDONLY: + perm = 0400 + case unix.O_WRONLY: + perm = 0200 + case unix.O_RDWR, unix.O_ACCMODE: + perm = 0600 + } + + // We only check user permissions, since this is a sample FS + if int(inode.attrs.Mode.Perm())&perm != perm { + err = unix.EACCES + } return } diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index 6e78a1bb..4c78f084 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -35,6 +35,7 @@ import ( . "github.com/jacobsa/oglematchers" . "github.com/jacobsa/ogletest" "github.com/kahing/go-xattr" + "golang.org/x/sys/unix" ) func TestMemFS(t *testing.T) { RunTests(t) } @@ -1706,6 +1707,30 @@ func (t *MemFSTest) RenameIntoFileSystem() { ExpectThat(err, Error(HasSubstr("cross-device"))) } +func (t *MemFSTest) TestPermissions() { + var e = unix.EACCES + var test = []struct { + name string + mode int + res [4]error + }{ + {name: "ro", mode: 0400, res: [4]error{nil, e, e, e}}, + {name: "wo", mode: 0200, res: [4]error{e, nil, e, e}}, + {name: "rw", mode: 0600, res: [4]error{nil, nil, nil, nil}}, + } + + for _, tt := range test { + n := path.Join(t.Dir, tt.name) + err := ioutil.WriteFile(n, []byte(""), os.FileMode(tt.mode)) + AssertEq(nil, err) + for f, r := range tt.res { + fd, err := unix.Open(n, f, 0) + unix.Close(fd) + AssertEq(r, err) + } + } +} + func (t *MemFSTest) RenameOverExistingFile() { var err error