From 834bef5996794a44f1c95358bc533f54db080497 Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Fri, 16 Aug 2024 13:56:21 -0700 Subject: [PATCH] fuse: Error out in case of unsupported file type instead of panicking. Linux has the same behavior; see callers of fs/fuse/dir.c:fuse_invalid_attr(). Reported-by: syzbot+7e65f2f0bdf121c71bcf@syzkaller.appspotmail.com PiperOrigin-RevId: 663853750 --- pkg/sentry/fsimpl/fuse/fusefs.go | 17 +++++++++++++++-- pkg/sentry/fsimpl/fuse/inode.go | 11 +++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/pkg/sentry/fsimpl/fuse/fusefs.go b/pkg/sentry/fsimpl/fuse/fusefs.go index 4d1d6e113..31269705c 100644 --- a/pkg/sentry/fsimpl/fuse/fusefs.go +++ b/pkg/sentry/fsimpl/fuse/fusefs.go @@ -301,8 +301,11 @@ func (fs *filesystem) newRoot(ctx context.Context, creds *auth.Credentials, mode return &d } -func (fs *filesystem) newInode(ctx context.Context, out linux.FUSEEntryOut) kernfs.Inode { +func (fs *filesystem) newInode(ctx context.Context, out linux.FUSEEntryOut) (kernfs.Inode, error) { attr := out.Attr + if !isValidType(attr.Mode) { + return nil, linuxerr.EIO + } i := &inode{fs: fs, nodeID: out.NodeID, generation: out.Generation} i.attrMu.Lock() defer i.attrMu.Unlock() @@ -314,5 +317,15 @@ func (fs *filesystem) newInode(ctx context.Context, out linux.FUSEEntryOut) kern i.OrderedChildren.Init(kernfs.OrderedChildrenOptions{}) i.InitRefs() - return i + return i, nil +} + +// isValidType is analogous to fs/fuse/dir.c:fuse_valid_type(). +func isValidType(mode uint32) bool { + switch mode & linux.S_IFMT { + case linux.S_IFREG, linux.S_IFDIR, linux.S_IFLNK, linux.S_IFCHR, linux.S_IFBLK, linux.S_IFIFO, linux.S_IFSOCK: + return true + default: + return false + } } diff --git a/pkg/sentry/fsimpl/fuse/inode.go b/pkg/sentry/fsimpl/fuse/inode.go index 6f8e8a142..0f9c15c7a 100644 --- a/pkg/sentry/fsimpl/fuse/inode.go +++ b/pkg/sentry/fsimpl/fuse/inode.go @@ -15,7 +15,6 @@ package fuse import ( - "fmt" gotime "time" "gvisor.dev/gvisor/pkg/abi/linux" @@ -171,12 +170,9 @@ func (i *inode) touchAtime() { i.atime.Store(i.fs.clock.Now().Nanoseconds()) } +// Precondition: isValidType(mode) == true. // +checklocks:i.attrMu func (i *inode) init(creds *auth.Credentials, devMajor, devMinor uint32, nodeid uint64, mode linux.FileMode, nlink uint32) { - if mode.FileType() == 0 { - panic(fmt.Sprintf("No file type specified in 'mode' for InodeAttrs.Init(): mode=0%o", mode)) - } - i.nodeID = nodeid i.ino.Store(nodeid) i.mode.Store(uint32(mode)) @@ -560,7 +556,10 @@ func (i *inode) newEntry(ctx context.Context, name string, fileType linux.FileMo if opcode != linux.FUSE_LOOKUP && ((out.Attr.Mode&linux.S_IFMT)^uint32(fileType) != 0 || out.NodeID == 0 || out.NodeID == linux.FUSE_ROOT_ID) { return nil, linuxerr.EIO } - child := i.fs.newInode(ctx, out.FUSEEntryOut) + child, err := i.fs.newInode(ctx, out.FUSEEntryOut) + if err != nil { + return nil, err + } if opcode == linux.FUSE_CREATE { // File handler is returned by fuse server at a time of file create. // Save it temporary in a created child, so Open could return it when invoked