summaryrefslogtreecommitdiff
path: root/lib/btrfs/btrfsitem
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-07-10 23:49:07 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-07-11 00:44:30 -0600
commitad9ac6d07ce1819260c2b7f090fd4fe742c80d9f (patch)
treeab6a607ea8575382c978f07de943ccf6c077de7c /lib/btrfs/btrfsitem
parent41ef03aabf8d6db4f926480fc5ddfec014e342d3 (diff)
Fuzz btrfsitem, and by consequence improve binstruct errors
Diffstat (limited to 'lib/btrfs/btrfsitem')
-rw-r--r--lib/btrfs/btrfsitem/item_chunk.go6
-rw-r--r--lib/btrfs/btrfsitem/item_dir.go50
-rw-r--r--lib/btrfs/btrfsitem/item_extent.go8
-rw-r--r--lib/btrfs/btrfsitem/item_extentcsum.go4
-rw-r--r--lib/btrfs/btrfsitem/item_inoderef.go13
-rw-r--r--lib/btrfs/btrfsitem/item_rootref.go13
-rw-r--r--lib/btrfs/btrfsitem/items_gen.go8
-rw-r--r--lib/btrfs/btrfsitem/items_test.go65
-rw-r--r--lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/12de190a2cae6f0c72854a75c03ce8488d9d0508a66fa4de0817264e458d22602
-rw-r--r--lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/1ecbbb90e92add091b31e3c765955d76d06074ea5dca8f6b4ce523a640d50a2d2
-rw-r--r--lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/2ae21a60c209d36ee27afa2b253c5f0ae7389c05837daa91500317cec5122f2e2
-rw-r--r--lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/7b05bfc61add24e74c86043bfd0dea657fa522bd2b161d6334effe624c8478502
-rw-r--r--lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/990f7eb92226efeef4491768fae2b9260529446c07a34b99d7e384b5dd847d932
-rw-r--r--lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/aff8a82fa526d6a55b4e13d9320aee5f9413109bbab24e3b2269cdd6abb97fb72
-rw-r--r--lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/c9330e1640e459c9f623fc40d643eb42f727ed9b0b744c011a39a40552417cad2
15 files changed, 134 insertions, 47 deletions
diff --git a/lib/btrfs/btrfsitem/item_chunk.go b/lib/btrfs/btrfsitem/item_chunk.go
index 7197fb3..2ccc860 100644
--- a/lib/btrfs/btrfsitem/item_chunk.go
+++ b/lib/btrfs/btrfsitem/item_chunk.go
@@ -5,8 +5,6 @@
package btrfsitem
import (
- "fmt"
-
"git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/internal"
@@ -70,7 +68,7 @@ func (chunk *Chunk) UnmarshalBinary(dat []byte) (int, error) {
_n, err := binstruct.Unmarshal(dat[n:], &stripe)
n += _n
if err != nil {
- return n, fmt.Errorf("%T.UnmarshalBinary: %w", *chunk, err)
+ return n, err
}
chunk.Stripes = append(chunk.Stripes, stripe)
}
@@ -87,7 +85,7 @@ func (chunk Chunk) MarshalBinary() ([]byte, error) {
_ret, err := binstruct.Marshal(stripe)
ret = append(ret, _ret...)
if err != nil {
- return ret, fmt.Errorf("%T.MarshalBinary: %w", chunk, err)
+ return ret, err
}
}
return ret, nil
diff --git a/lib/btrfs/btrfsitem/item_dir.go b/lib/btrfs/btrfsitem/item_dir.go
index 859cd14..2fb2d41 100644
--- a/lib/btrfs/btrfsitem/item_dir.go
+++ b/lib/btrfs/btrfsitem/item_dir.go
@@ -9,47 +9,21 @@ import (
"hash/crc32"
"git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
+ "git.lukeshu.com/btrfs-progs-ng/lib/binstruct/binutil"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/internal"
)
-// key.objectid = inode of directory containing this entry
-// key.offset =
-// for DIR_ITEM and XATTR_ITEM = NameHash(name)
-// for DIR_INDEX = index id in the directory (starting at 2, because "." and "..")
-type DirEntries []DirEntry // DIR_ITEM=84 DIR_INDEX=96 XATTR_ITEM=24
+const MaxNameLen = 255
func NameHash(dat []byte) uint64 {
return uint64(^crc32.Update(1, crc32.MakeTable(crc32.Castagnoli), dat))
}
-func (o *DirEntries) UnmarshalBinary(dat []byte) (int, error) {
- *o = nil
- n := 0
- for n < len(dat) {
- var ref DirEntry
- _n, err := binstruct.Unmarshal(dat, &ref)
- n += _n
- if err != nil {
- return n, err
- }
- *o = append(*o, ref)
- }
- return n, nil
-}
-
-func (o DirEntries) MarshalBinary() ([]byte, error) {
- var ret []byte
- for _, ref := range o {
- bs, err := binstruct.Marshal(ref)
- ret = append(ret, bs...)
- if err != nil {
- return ret, err
- }
- }
- return ret, nil
-}
-
-type DirEntry struct {
+// key.objectid = inode of directory containing this entry
+// key.offset =
+// for DIR_ITEM and XATTR_ITEM = NameHash(name)
+// for DIR_INDEX = index id in the directory (starting at 2, because "." and "..")
+type DirEntry struct { // DIR_ITEM=84 DIR_INDEX=96 XATTR_ITEM=24
Location internal.Key `bin:"off=0x0, siz=0x11"`
TransID int64 `bin:"off=0x11, siz=8"`
DataLen uint16 `bin:"off=0x19, siz=2"` // [ignored-when-writing]
@@ -61,10 +35,20 @@ type DirEntry struct {
}
func (o *DirEntry) UnmarshalBinary(dat []byte) (int, error) {
+ if err := binutil.NeedNBytes(dat, 0x1e); err != nil {
+ return 0, err
+ }
n, err := binstruct.UnmarshalWithoutInterface(dat, o)
if err != nil {
return n, err
}
+ if o.NameLen > MaxNameLen {
+ return 0, fmt.Errorf("maximum name len is %v, but .NameLen=%v",
+ MaxNameLen, o.NameLen)
+ }
+ if err := binutil.NeedNBytes(dat, 0x1e+int(o.DataLen)+int(o.NameLen)); err != nil {
+ return 0, err
+ }
o.Data = dat[n : n+int(o.DataLen)]
n += int(o.DataLen)
o.Name = dat[n : n+int(o.NameLen)]
diff --git a/lib/btrfs/btrfsitem/item_extent.go b/lib/btrfs/btrfsitem/item_extent.go
index 9257d2b..d49243d 100644
--- a/lib/btrfs/btrfsitem/item_extent.go
+++ b/lib/btrfs/btrfsitem/item_extent.go
@@ -74,8 +74,8 @@ type ExtentHeader struct {
type TreeBlockInfo struct {
Key internal.Key `bin:"off=0, siz=0x11"`
- Level uint8 `bin:"off=0x11, siz=0x8"`
- binstruct.End `bin:"off=0x19"`
+ Level uint8 `bin:"off=0x11, siz=0x1"`
+ binstruct.End `bin:"off=0x12"`
}
type ExtentFlags uint64
@@ -131,7 +131,7 @@ func (o *ExtentInlineRef) UnmarshalBinary(dat []byte) (int, error) {
return n, err
}
default:
- return n, fmt.Errorf("btrfsitem.ExtentInlineRef.UnmarshalBinary: unexpected item type %v", o.Type)
+ return n, fmt.Errorf("unexpected item type %v", o.Type)
}
return n, nil
}
@@ -163,7 +163,7 @@ func (o ExtentInlineRef) MarshalBinary() ([]byte, error) {
return dat, err
}
default:
- return dat, fmt.Errorf("btrfsitem.ExtentInlineRef.MarshalBinary: unexpected item type %v", o.Type)
+ return dat, fmt.Errorf("unexpected item type %v", o.Type)
}
return dat, nil
}
diff --git a/lib/btrfs/btrfsitem/item_extentcsum.go b/lib/btrfs/btrfsitem/item_extentcsum.go
index f9c546d..a945295 100644
--- a/lib/btrfs/btrfsitem/item_extentcsum.go
+++ b/lib/btrfs/btrfsitem/item_extentcsum.go
@@ -20,7 +20,7 @@ type ExtentCSum struct { // EXTENT_CSUM=128
func (o *ExtentCSum) UnmarshalBinary(dat []byte) (int, error) {
if o.ChecksumSize == 0 {
- return 0, fmt.Errorf("btrfs.ExtentCSum.UnmarshalBinary: .ChecksumSize must be set")
+ return 0, fmt.Errorf(".ChecksumSize must be set")
}
for len(dat) >= o.ChecksumSize {
var csum btrfssum.CSum
@@ -33,7 +33,7 @@ func (o *ExtentCSum) UnmarshalBinary(dat []byte) (int, error) {
func (o ExtentCSum) MarshalBinary() ([]byte, error) {
if o.ChecksumSize == 0 {
- return nil, fmt.Errorf("btrfs.ExtentCSum.MarshalBinary: .ChecksumSize must be set")
+ return nil, fmt.Errorf(".ChecksumSize must be set")
}
var dat []byte
for _, csum := range o.Sums {
diff --git a/lib/btrfs/btrfsitem/item_inoderef.go b/lib/btrfs/btrfsitem/item_inoderef.go
index e4edf4a..b1eaf1b 100644
--- a/lib/btrfs/btrfsitem/item_inoderef.go
+++ b/lib/btrfs/btrfsitem/item_inoderef.go
@@ -5,7 +5,10 @@
package btrfsitem
import (
+ "fmt"
+
"git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
+ "git.lukeshu.com/btrfs-progs-ng/lib/binstruct/binutil"
)
// key.objectid = inode number of the file
@@ -18,10 +21,20 @@ type InodeRef struct { // INODE_REF=12
}
func (o *InodeRef) UnmarshalBinary(dat []byte) (int, error) {
+ if err := binutil.NeedNBytes(dat, 0xA); err != nil {
+ return 0, err
+ }
n, err := binstruct.UnmarshalWithoutInterface(dat, o)
if err != nil {
return n, err
}
+ if o.NameLen > MaxNameLen {
+ return 0, fmt.Errorf("maximum name len is %v, but .NameLen=%v",
+ MaxNameLen, o.NameLen)
+ }
+ if err := binutil.NeedNBytes(dat, 0xA+int(o.NameLen)); err != nil {
+ return 0, err
+ }
dat = dat[n:]
o.Name = dat[:o.NameLen]
n += int(o.NameLen)
diff --git a/lib/btrfs/btrfsitem/item_rootref.go b/lib/btrfs/btrfsitem/item_rootref.go
index 228ab55..1ee0ee4 100644
--- a/lib/btrfs/btrfsitem/item_rootref.go
+++ b/lib/btrfs/btrfsitem/item_rootref.go
@@ -5,7 +5,10 @@
package btrfsitem
import (
+ "fmt"
+
"git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
+ "git.lukeshu.com/btrfs-progs-ng/lib/binstruct/binutil"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/internal"
)
@@ -18,10 +21,20 @@ type RootRef struct { // ROOT_REF=156 ROOT_BACKREF=144
}
func (o *RootRef) UnmarshalBinary(dat []byte) (int, error) {
+ if err := binutil.NeedNBytes(dat, 0x12); err != nil {
+ return 0, err
+ }
n, err := binstruct.UnmarshalWithoutInterface(dat, o)
if err != nil {
return n, err
}
+ if o.NameLen > MaxNameLen {
+ return 0, fmt.Errorf("maximum name len is %v, but .NameLen=%v",
+ MaxNameLen, o.NameLen)
+ }
+ if err := binutil.NeedNBytes(dat, 0x12+int(o.NameLen)); err != nil {
+ return 0, err
+ }
o.Name = dat[n : n+int(o.NameLen)]
n += int(o.NameLen)
return n, nil
diff --git a/lib/btrfs/btrfsitem/items_gen.go b/lib/btrfs/btrfsitem/items_gen.go
index 82743b0..8573967 100644
--- a/lib/btrfs/btrfsitem/items_gen.go
+++ b/lib/btrfs/btrfsitem/items_gen.go
@@ -47,8 +47,8 @@ var keytype2gotype = map[Type]reflect.Type{
CHUNK_ITEM_KEY: reflect.TypeOf(Chunk{}),
DEV_EXTENT_KEY: reflect.TypeOf(DevExtent{}),
DEV_ITEM_KEY: reflect.TypeOf(Dev{}),
- DIR_INDEX_KEY: reflect.TypeOf(DirEntries{}),
- DIR_ITEM_KEY: reflect.TypeOf(DirEntries{}),
+ DIR_INDEX_KEY: reflect.TypeOf(DirEntry{}),
+ DIR_ITEM_KEY: reflect.TypeOf(DirEntry{}),
EXTENT_CSUM_KEY: reflect.TypeOf(ExtentCSum{}),
EXTENT_DATA_KEY: reflect.TypeOf(FileExtent{}),
EXTENT_DATA_REF_KEY: reflect.TypeOf(ExtentDataRef{}),
@@ -70,7 +70,7 @@ var keytype2gotype = map[Type]reflect.Type{
TREE_BLOCK_REF_KEY: reflect.TypeOf(Empty{}),
UUID_RECEIVED_SUBVOL_KEY: reflect.TypeOf(UUIDMap{}),
UUID_SUBVOL_KEY: reflect.TypeOf(UUIDMap{}),
- XATTR_ITEM_KEY: reflect.TypeOf(DirEntries{}),
+ XATTR_ITEM_KEY: reflect.TypeOf(DirEntry{}),
}
var untypedObjID2gotype = map[internal.ObjID]reflect.Type{
internal.FREE_SPACE_OBJECTID: reflect.TypeOf(FreeSpaceHeader{}),
@@ -81,7 +81,7 @@ func (Chunk) isItem() {}
func (Dev) isItem() {}
func (DevExtent) isItem() {}
func (DevStats) isItem() {}
-func (DirEntries) isItem() {}
+func (DirEntry) isItem() {}
func (Empty) isItem() {}
func (Extent) isItem() {}
func (ExtentCSum) isItem() {}
diff --git a/lib/btrfs/btrfsitem/items_test.go b/lib/btrfs/btrfsitem/items_test.go
new file mode 100644
index 0000000..aba8ca2
--- /dev/null
+++ b/lib/btrfs/btrfsitem/items_test.go
@@ -0,0 +1,65 @@
+// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package btrfsitem_test
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/internal"
+)
+
+func FuzzRoundTrip(f *testing.F) {
+ keySize := binstruct.StaticSize(internal.Key{})
+ sumtypeSize := binstruct.StaticSize(btrfssum.CSumType(0))
+
+ f.Add(make([]byte, 256))
+
+ f.Fuzz(func(t *testing.T, inDat []byte) {
+ if len(inDat) < keySize+sumtypeSize {
+ t.Skip()
+ }
+ keyInDat, inDat := inDat[:keySize], inDat[keySize:]
+ sumtypeInDat, inDat := inDat[:sumtypeSize], inDat[sumtypeSize:]
+ itemInDat := inDat
+
+ // key
+
+ var key internal.Key
+ n, err := binstruct.Unmarshal(keyInDat, &key)
+ require.NoError(t, err, "binstruct.Unmarshal(dat, &key)")
+ require.Equal(t, keySize, n, "binstruct.Unmarshal(dat, &key)")
+
+ keyOutDat, err := binstruct.Marshal(key)
+ require.NoError(t, err, "binstruct.Marshal(key)")
+ require.Equal(t, keyInDat, keyOutDat, "binstruct.Marshal(key)")
+
+ // sumtype
+
+ var sumtype btrfssum.CSumType
+ n, err = binstruct.Unmarshal(sumtypeInDat, &sumtype)
+ require.NoError(t, err, "binstruct.Unmarshal(dat, &sumtype)")
+ require.Equal(t, sumtypeSize, n, "binstruct.Unmarshal(dat, &sumtype)")
+
+ sumtypeOutDat, err := binstruct.Marshal(sumtype)
+ require.NoError(t, err, "binstruct.Marshal(sumtype)")
+ require.Equal(t, sumtypeInDat, sumtypeOutDat, "binstruct.Marshal(sumtype)")
+
+ // item
+
+ t.Logf("key=%v sumtype=%v dat=%q", key, sumtype, itemInDat)
+
+ item := btrfsitem.UnmarshalItem(key, sumtype, itemInDat)
+ require.NotNil(t, item, "btrfsitem.UnmarshalItem")
+
+ itemOutDat, err := binstruct.Marshal(item)
+ require.NoError(t, err, "binstruct.Marshal(item)")
+ require.Equal(t, string(itemInDat), string(itemOutDat), "binstruct.Marshal(item)")
+ })
+}
diff --git a/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/12de190a2cae6f0c72854a75c03ce8488d9d0508a66fa4de0817264e458d2260 b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/12de190a2cae6f0c72854a75c03ce8488d9d0508a66fa4de0817264e458d2260
new file mode 100644
index 0000000..6fb6f2c
--- /dev/null
+++ b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/12de190a2cae6f0c72854a75c03ce8488d9d0508a66fa4de0817264e458d2260
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00000000\x9c0000000000000000000000000000")
diff --git a/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/1ecbbb90e92add091b31e3c765955d76d06074ea5dca8f6b4ce523a640d50a2d b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/1ecbbb90e92add091b31e3c765955d76d06074ea5dca8f6b4ce523a640d50a2d
new file mode 100644
index 0000000..5aa6619
--- /dev/null
+++ b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/1ecbbb90e92add091b31e3c765955d76d06074ea5dca8f6b4ce523a640d50a2d
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00000000\x180000000000")
diff --git a/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/2ae21a60c209d36ee27afa2b253c5f0ae7389c05837daa91500317cec5122f2e b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/2ae21a60c209d36ee27afa2b253c5f0ae7389c05837daa91500317cec5122f2e
new file mode 100644
index 0000000..68454dd
--- /dev/null
+++ b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/2ae21a60c209d36ee27afa2b253c5f0ae7389c05837daa91500317cec5122f2e
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00000000\x800000000000")
diff --git a/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/7b05bfc61add24e74c86043bfd0dea657fa522bd2b161d6334effe624c847850 b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/7b05bfc61add24e74c86043bfd0dea657fa522bd2b161d6334effe624c847850
new file mode 100644
index 0000000..2576860
--- /dev/null
+++ b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/7b05bfc61add24e74c86043bfd0dea657fa522bd2b161d6334effe624c847850
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00000000`00000000000000000000000000000000000\x00\x00\x00\x0000")
diff --git a/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/990f7eb92226efeef4491768fae2b9260529446c07a34b99d7e384b5dd847d93 b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/990f7eb92226efeef4491768fae2b9260529446c07a34b99d7e384b5dd847d93
new file mode 100644
index 0000000..3f5d16a
--- /dev/null
+++ b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/990f7eb92226efeef4491768fae2b9260529446c07a34b99d7e384b5dd847d93
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00000000\xa80000000000000000000000000020000000")
diff --git a/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/aff8a82fa526d6a55b4e13d9320aee5f9413109bbab24e3b2269cdd6abb97fb7 b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/aff8a82fa526d6a55b4e13d9320aee5f9413109bbab24e3b2269cdd6abb97fb7
new file mode 100644
index 0000000..b9c2ffe
--- /dev/null
+++ b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/aff8a82fa526d6a55b4e13d9320aee5f9413109bbab24e3b2269cdd6abb97fb7
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00000000`0000000000000000000000000000000000000000")
diff --git a/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/c9330e1640e459c9f623fc40d643eb42f727ed9b0b744c011a39a40552417cad b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/c9330e1640e459c9f623fc40d643eb42f727ed9b0b744c011a39a40552417cad
new file mode 100644
index 0000000..c117858
--- /dev/null
+++ b/lib/btrfs/btrfsitem/testdata/fuzz/FuzzRoundTrip/c9330e1640e459c9f623fc40d643eb42f727ed9b0b744c011a39a40552417cad
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00000000\f00000000000000000000")