diff options
Diffstat (limited to 'sys/linux')
| -rw-r--r-- | sys/linux/init.go | 10 | ||||
| -rw-r--r-- | sys/linux/init_images.go | 56 | ||||
| -rw-r--r-- | sys/linux/init_images_test.go | 8 | ||||
| -rw-r--r-- | sys/linux/testdata/fs_images/0.in | 2 | ||||
| -rw-r--r-- | sys/linux/testdata/fs_images/0.out0 | bin | 8736 -> 8736 bytes |
5 files changed, 52 insertions, 24 deletions
diff --git a/sys/linux/init.go b/sys/linux/init.go index 09b70f092..7d537075c 100644 --- a/sys/linux/init.go +++ b/sys/linux/init.go @@ -173,8 +173,11 @@ type arch struct { TIOCGSERIAL uint64 } -func (arch *arch) neutralize(c *prog.Call) { - arch.unix.Neutralize(c) +func (arch *arch) neutralize(c *prog.Call, fixStructure bool) error { + err := arch.unix.Neutralize(c, fixStructure) + if err != nil { + return err + } switch c.Meta.CallName { case "mremap": // Add MREMAP_FIXED flag, otherwise it produces non-deterministic results. @@ -243,13 +246,14 @@ func (arch *arch) neutralize(c *prog.Call) { // Enabling a SCHED_FIFO or a SCHED_RR policy may lead to false positive stall-related crashes. neutralizeSchedAttr(c.Args[1]) case "syz_mount_image": - arch.fixUpSyzMountImage(c) + return arch.fixUpSyzMountImage(c, fixStructure) } switch c.Meta.Name { case "setsockopt$EBT_SO_SET_ENTRIES": arch.neutralizeEbtables(c) } + return nil } func neutralizeSchedAttr(a prog.Arg) { diff --git a/sys/linux/init_images.go b/sys/linux/init_images.go index eb1d7c7ad..e160234d9 100644 --- a/sys/linux/init_images.go +++ b/sys/linux/init_images.go @@ -64,9 +64,9 @@ func (zr *zeroReader) Read(p []byte) (n int, err error) { const imageMaxSize = 129 << 20 -func fixUpImageSegments(parsed *mountImageArgs) { - const maxImageSegments = 4096 - parsed.filterSegments(func(i int, segment *mountImageSegment) bool { +func fixUpImageSegments(parsed *mountImageArgs, fixStructure bool) error { + const maxImageSegments = 16784 + err := parsed.filterSegments(func(i int, segment *mountImageSegment) bool { if i >= maxImageSegments { // We don't want more than maxImageSegments segments. return false @@ -76,13 +76,16 @@ func fixUpImageSegments(parsed *mountImageArgs) { return false } return segment.offset.Val < imageMaxSize && segment.size.Val < imageMaxSize - }) + }, !fixStructure) + if err != nil { + return err + } // Overwriting of the image multiple times is not efficient and complicates image extraction in Go. // So let's make segments non-overlapping. - sort.Stable(parsed) - resizeSegment := func(s *mountImageSegment, size uint64) { - s.size.Val = size - s.data.SetData(s.data.Data()[0:size]) + if fixStructure { + sort.Stable(parsed) + } else if !sort.IsSorted(parsed) { + return fmt.Errorf("segments are not sorted") } newSize := parsed.size.Val @@ -99,11 +102,19 @@ func fixUpImageSegments(parsed *mountImageArgs) { // Adjust the end of the previous segment. prevSegment := parsed.segments[idx-1] if prevSegment.offset.Val+prevSegment.size.Val > segment.offset.Val { - resizeSegment(prevSegment, segment.offset.Val-prevSegment.offset.Val) + if fixStructure { + prevSegment.resize(segment.offset.Val - prevSegment.offset.Val) + } else { + return fmt.Errorf("segment %d has invalid size", idx-1) + } } } if segment.offset.Val+segment.size.Val > imageMaxSize { - resizeSegment(segment, imageMaxSize-segment.offset.Val) + if fixStructure { + segment.resize(imageMaxSize - segment.offset.Val) + } else { + return fmt.Errorf("segment %d has invalid size", idx) + } } if segment.offset.Val+segment.size.Val > newSize { newSize = segment.offset.Val + segment.size.Val @@ -116,12 +127,12 @@ func fixUpImageSegments(parsed *mountImageArgs) { parsed.size.Val = newSize // Drop 0-size segments. - parsed.filterSegments(func(i int, segment *mountImageSegment) bool { + return parsed.filterSegments(func(i int, segment *mountImageSegment) bool { return segment.size.Val > 0 - }) + }, !fixStructure) } -func (arch *arch) fixUpSyzMountImage(c *prog.Call) { +func (arch *arch) fixUpSyzMountImage(c *prog.Call, fixStructure bool) error { // Previously we did such a sanitization right in the common_linux.h, but this was problematic // for two reasons: // 1) It further complicates the already complicated executor code. @@ -129,10 +140,13 @@ func (arch *arch) fixUpSyzMountImage(c *prog.Call) { // So now we do all the initialization in Go and let the C code only interpret the commands. ret, err := parseSyzMountImage(c) if err != nil { - deactivateSyzMountImage(c) - return + if fixStructure { + deactivateSyzMountImage(c) + return nil + } + return err } - fixUpImageSegments(ret) + return fixUpImageSegments(ret, fixStructure) } type mountImageArgs struct { @@ -142,18 +156,21 @@ type mountImageArgs struct { segments []*mountImageSegment } -func (m *mountImageArgs) filterSegments(filter func(int, *mountImageSegment) bool) { +func (m *mountImageArgs) filterSegments(filter func(int, *mountImageSegment) bool, failOnRemove bool) error { newArgs := []prog.Arg{} newSegments := []*mountImageSegment{} for i, segment := range m.segments { if filter(i, segment) { newSegments = append(newSegments, segment) newArgs = append(newArgs, m.segmentsGroup.Inner[i]) + } else if failOnRemove { + return fmt.Errorf("segment #%d got filtered out", i) } } m.segments = newSegments m.segmentsGroup.Inner = newArgs m.segmentsCount.Val = uint64(len(newArgs)) + return nil } // Methods for segment sorting. @@ -177,6 +194,11 @@ type mountImageSegment struct { parseError error } +func (s *mountImageSegment) resize(newSize uint64) { + s.size.Val = newSize + s.data.SetData(s.data.Data()[0:newSize]) +} + func parseImageSegment(segmentArg prog.Arg) *mountImageSegment { ret := &mountImageSegment{} segmentFields, ok := segmentArg.(*prog.GroupArg) diff --git a/sys/linux/init_images_test.go b/sys/linux/init_images_test.go index 0bfb68cc4..1da41276e 100644 --- a/sys/linux/init_images_test.go +++ b/sys/linux/init_images_test.go @@ -38,12 +38,14 @@ func TestSyzMountImageNeutralize(t *testing.T) { // Invalid offset. In: `syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file1\x00', 0x20, 0x2, &(0x7f0000000200)=[{&(0x7f0000010000)="cefaad1bc0210000ff0f0000ffffffffffffffffffffffffffffffff73797a6b616c73797a6b616c00"/64, 0x40, 0x0}, {&(0x7f0000010040)="0200000011000000140000001f22000002000000ed4100000000000001000000020000005ffb19635ffb19635ffb196300"/64, 0x40, 0x9100000}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)`, // The segment is deleted. - Out: `syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file1\x00', 0x40, 0x1, &(0x7f0000000200)=[{&(0x7f0000010000)="cefaad1bc0210000ff0f0000ffffffffffffffffffffffffffffffff73797a6b616c73797a6b616c00"/64, 0x40, 0x0}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)`, + Out: `syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file1\x00', 0x40, 0x1, &(0x7f0000000200)=[{&(0x7f0000010000)="cefaad1bc0210000ff0f0000ffffffffffffffffffffffffffffffff73797a6b616c73797a6b616c00"/64, 0x40, 0x0}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)`, + StrictErr: `got filtered out`, }, { // Overlapping and unsorted segments. - In: `syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file0\x00', 0x2220, 0x3, &(0x7f0000000200)=[{&(0x7f0000010000)="cafef00d"/64, 0x50, 0x20}, {&(0x7f0000010040)="deadbeef"/64, 0x30, 0x10}, {&(0x7f0000010080)="abcdef"/64, 0x40, 0x20}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)`, - Out: `syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file0\x00', 0x2220, 0x2, &(0x7f0000000200)=[{&(0x7f0000010040)="deadbeef00"/16, 0x10, 0x10}, {&(0x7f0000010000)="cafef00d00"/64, 0x40, 0x20}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)`, + In: `syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file0\x00', 0x2220, 0x3, &(0x7f0000000200)=[{&(0x7f0000010000)="cafef00d"/64, 0x50, 0x20}, {&(0x7f0000010040)="deadbeef"/64, 0x30, 0x10}, {&(0x7f0000010080)="abcdef"/64, 0x40, 0x20}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)`, + Out: `syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file0\x00', 0x2220, 0x2, &(0x7f0000000200)=[{&(0x7f0000010040)="deadbeef00"/16, 0x10, 0x10}, {&(0x7f0000010000)="cafef00d00"/64, 0x40, 0x20}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)`, + StrictErr: `segments are not sorted`, }, }) } diff --git a/sys/linux/testdata/fs_images/0.in b/sys/linux/testdata/fs_images/0.in index 3eed397dd..7080226a0 100644 --- a/sys/linux/testdata/fs_images/0.in +++ b/sys/linux/testdata/fs_images/0.in @@ -1 +1 @@ -syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file0\x00', 0x2220, 0x3, &(0x7f0000000200)=[{&(0x7f0000010040)="deadbeef00"/64, 0x10, 0x10}, {&(0x7f0000010000)="cafef00d00"/64, 0x0, 0x20}, {&(0x7f0000010080)="abcdef00"/64, 0x40, 0x20}], 0x0, &(0x7f00000100a0)={[], [], 0x0})
\ No newline at end of file +syz_mount_image$bfs(&(0x7f0000000000)='bfs\x00', &(0x7f0000000100)='./file0\x00', 0x2220, 0x2, &(0x7f0000000200)=[{&(0x7f0000010040)="deadbeef00"/16, 0x10, 0x10}, {&(0x7f0000010000)="cafef00d00"/64, 0x40, 0x20}], 0x0, &(0x7f00000100a0)={[], [], 0x0}, 0x0)
\ No newline at end of file diff --git a/sys/linux/testdata/fs_images/0.out0 b/sys/linux/testdata/fs_images/0.out0 Binary files differindex 424d24bd8..4eb5233c9 100644 --- a/sys/linux/testdata/fs_images/0.out0 +++ b/sys/linux/testdata/fs_images/0.out0 |
