Commit 33711add authored by Ed Schouten's avatar Ed Schouten Committed by Han-Wen Nienhuys

Don't crash when calling truncate(1) on a handle without a File.

For all operations that can be applied on file descriptors, we have
special treatment to permit the File to be nil. In that case, operations
are called against the Node object instead.

This check currently seems missing from SetAttr(), causing invocations
of the truncate(1) command line tool to cause a crash:

        panic: runtime error: invalid memory address or nil pointer dereference
        [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0xa30d0d]

        goroutine 12 [running]:
        github.com/hanwen/go-fuse/fuse/nodefs.(*rawBridge).SetAttr(0xc00013ecc0, 0xc0003a8000, 0xc0003ba0f0, 0xa27b98)
                external/com_github_hanwen_go_fuse/fuse/nodefs/fsops.go:203 +0x58d
        github.com/hanwen/go-fuse/fuse.doSetattr(0xc0003a4000, 0xc0003ba000)
                external/com_github_hanwen_go_fuse/fuse/opcode.go:171 +0x64
        github.com/hanwen/go-fuse/fuse.(*Server).handleRequest(0xc0003a4000, 0xc0003ba000, 0xc0003ba000)
                external/com_github_hanwen_go_fuse/fuse/server.go:431 +0x26b
        github.com/hanwen/go-fuse/fuse.(*Server).loop(0xc0003a4000, 0xc00000b101)
                external/com_github_hanwen_go_fuse/fuse/server.go:403 +0x18f
        created by github.com/hanwen/go-fuse/fuse.(*Server).readRequest
                external/com_github_hanwen_go_fuse/fuse/server.go:291 +0x2d8
parent dc73e9f1
......@@ -208,9 +208,10 @@ func (c *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse
var f File
if input.Valid&fuse.FATTR_FH != 0 {
opened := node.mount.getOpenedFile(input.Fh)
if opened := node.mount.getOpenedFile(input.Fh); opened != nil {
f = opened.WithFlags.File
}
}
if code.Ok() && input.Valid&fuse.FATTR_MODE != 0 {
permissions := uint32(07777) & input.Mode
......
// Copyright 2019 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package test
import (
"os"
"testing"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/hanwen/go-fuse/internal/testutil"
)
type truncatableFile struct {
nodefs.Node
}
func (d *truncatableFile) Open(flags uint32, context *fuse.Context) (nodefs.File, fuse.Status) {
return nil, fuse.OK
}
func (d *truncatableFile) Truncate(file nodefs.File, size uint64, context *fuse.Context) fuse.Status {
return fuse.OK
}
// TestNilFileTruncation verifies that the FUSE server process does not
// crash when file truncation is performed on nil file handles.
func TestNilFileTruncation(t *testing.T) {
dir := testutil.TempDir()
defer func() {
err := os.Remove(dir)
if err != nil {
t.Fatal(err)
}
}()
root := nodefs.NewDefaultNode()
opts := nodefs.NewOptions()
opts.Debug = testutil.VerboseTest()
srv, _, err := nodefs.MountRoot(dir, root, opts)
if err != nil {
t.Fatal(err)
}
hello := &truncatableFile{
Node: nodefs.NewDefaultNode(),
}
root.Inode().NewChild("hello.txt", false, hello)
go srv.Serve()
if err := srv.WaitMount(); err != nil {
t.Fatal("WaitMount", err)
}
defer func() {
err := srv.Unmount()
if err != nil {
t.Fatal(err)
}
}()
// truncate().
if err := os.Truncate(dir+"/hello.txt", 123); err != nil {
t.Fatalf("truncate: %s", err)
}
// ftruncate().
f, err := os.OpenFile(dir+"/hello.txt", os.O_WRONLY, 0)
if err != nil {
t.Fatalf("open: %s", err)
}
defer f.Close()
if err := f.Truncate(123); err != nil {
t.Fatalf("ftruncate: %s", err)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment