mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: add Makefile target for fuzzing and AML parser fuzzer
The fuzzer can be invoked by running: "make test-fuzz". The AML parser test suite has been augmented with a special "TestParserCrashers" function that can be used to replay corpuses identified by go-fuzz as causing parser crashes. The test can be invoked as: go test -v -run TestParserCrashers -aml-replace-crashers-from $BUILD/fuzz/corpus/src_gopheros_device_acpi_aml/crashers where $BUILD is the output directory (default: build/) defined in the Makefile.
This commit is contained in:
parent
d7028ed73d
commit
ddbddd2ea2
25
Makefile
25
Makefile
@ -11,13 +11,18 @@ iso_target := $(BUILD_DIR)/kernel-$(ARCH).iso
|
|||||||
# this: make run GO=go1.8
|
# this: make run GO=go1.8
|
||||||
GO ?= go
|
GO ?= go
|
||||||
|
|
||||||
# Prepend build path to GOPATH so the compiled packages and linter dependencies
|
# Prepend build path to GOPATH so the compiled packages and linter dependencies
|
||||||
# end up inside the build folder
|
# end up inside the build folder
|
||||||
GOPATH := $(BUILD_ABS_DIR):$(shell pwd):$(GOPATH)
|
GOPATH := $(BUILD_ABS_DIR):$(shell pwd):$(GOPATH)
|
||||||
|
|
||||||
|
FUZZ_PKG_LIST := src/gopheros/device/acpi/aml
|
||||||
|
# To append more entries to the above list use the following syntax
|
||||||
|
# FUZZ_PKG_LIST += path-to-pkg
|
||||||
|
|
||||||
ifeq ($(OS), Linux)
|
ifeq ($(OS), Linux)
|
||||||
export SHELL := /bin/bash -o pipefail
|
export SHELL := /bin/bash -o pipefail
|
||||||
|
|
||||||
|
|
||||||
LD := ld
|
LD := ld
|
||||||
AS := nasm
|
AS := nasm
|
||||||
|
|
||||||
@ -143,7 +148,7 @@ run-vbox: iso
|
|||||||
VBoxManage storageattach $(VBOX_VM_NAME) --storagectl "IDE Controller" --port 0 --device 0 --type dvddrive \
|
VBoxManage storageattach $(VBOX_VM_NAME) --storagectl "IDE Controller" --port 0 --device 0 --type dvddrive \
|
||||||
--medium $(iso_target) || true
|
--medium $(iso_target) || true
|
||||||
VBoxManage startvm $(VBOX_VM_NAME)
|
VBoxManage startvm $(VBOX_VM_NAME)
|
||||||
|
|
||||||
# When building gdb target disable optimizations (-N) and inlining (l) of Go code
|
# When building gdb target disable optimizations (-N) and inlining (l) of Go code
|
||||||
gdb: GC_FLAGS += -N -l
|
gdb: GC_FLAGS += -N -l
|
||||||
gdb: iso
|
gdb: iso
|
||||||
@ -185,12 +190,28 @@ lint: lint-check-deps
|
|||||||
src/...
|
src/...
|
||||||
|
|
||||||
lint-check-deps:
|
lint-check-deps:
|
||||||
|
@echo [go get] installing linter dependencies
|
||||||
@GOPATH=$(GOPATH) $(GO) get -u -t gopkg.in/alecthomas/gometalinter.v1
|
@GOPATH=$(GOPATH) $(GO) get -u -t gopkg.in/alecthomas/gometalinter.v1
|
||||||
@GOPATH=$(GOPATH) PATH=$(BUILD_ABS_DIR)/bin:$(PATH) gometalinter.v1 --install >/dev/null
|
@GOPATH=$(GOPATH) PATH=$(BUILD_ABS_DIR)/bin:$(PATH) gometalinter.v1 --install >/dev/null
|
||||||
|
|
||||||
test:
|
test:
|
||||||
GOPATH=$(GOPATH) $(GO) test -cover gopheros/...
|
GOPATH=$(GOPATH) $(GO) test -cover gopheros/...
|
||||||
|
|
||||||
|
fuzz-deps:
|
||||||
|
@mkdir -p $(BUILD_DIR)/fuzz
|
||||||
|
@echo [go get] installing go-fuzz dependencies
|
||||||
|
@GOPATH=$(GOPATH) $(GO) get -u github.com/dvyukov/go-fuzz/...
|
||||||
|
|
||||||
|
%.fuzzpkg: %
|
||||||
|
@echo [go-fuzz] fuzzing: $<
|
||||||
|
@GOPATH=$(GOPATH) PATH=$(BUILD_ABS_DIR)/bin:$(PATH) go-fuzz-build -o $(BUILD_ABS_DIR)/fuzz/$(subst /,_,$<).zip $(subst src/,,$<)
|
||||||
|
@mkdir -p $(BUILD_ABS_DIR)/fuzz/corpus/$(subst /,_,$<)/corpus
|
||||||
|
@echo [go-fuzz] + grepping for corpus file hints in $<
|
||||||
|
@grep "go-fuzz-corpus+=" $</*fuzz.go | cut -d'=' -f2 | tr '\n' '\0' | xargs -0 -I@ sh -c 'export F="@"; cp $$F $(BUILD_ABS_DIR)/fuzz/corpus/$(subst /,_,$<)/corpus/ && echo "[go fuzz] + copy extra corpus file: $$F"'
|
||||||
|
@go-fuzz -bin=$(BUILD_ABS_DIR)/fuzz/$(subst /,_,$<).zip -workdir=$(BUILD_ABS_DIR)/fuzz/corpus/$(subst /,_,$<) 2>&1 | sed -e "s/^/ | /g"
|
||||||
|
|
||||||
|
test-fuzz: fuzz-deps $(addsuffix .fuzzpkg,$(FUZZ_PKG_LIST))
|
||||||
|
|
||||||
collect-coverage:
|
collect-coverage:
|
||||||
GOPATH=$(GOPATH) sh coverage.sh
|
GOPATH=$(GOPATH) sh coverage.sh
|
||||||
|
|
||||||
|
40
src/gopheros/device/acpi/aml/parser_fuzz.go
Normal file
40
src/gopheros/device/acpi/aml/parser_fuzz.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// +build gofuzz
|
||||||
|
//
|
||||||
|
// The following lines contain paths to interesting corpus data and will be
|
||||||
|
// automatically grepped and copied by the Makefile when fuzzing.
|
||||||
|
//
|
||||||
|
//go-fuzz-corpus+=src/gopheros/device/acpi/table/tabletest/DSDT.aml
|
||||||
|
//go-fuzz-corpus+=src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.aml
|
||||||
|
|
||||||
|
package aml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopheros/device/acpi/table"
|
||||||
|
"io/ioutil"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fuzz is the driver for go-fuzz. The function must return 1 if the fuzzer
|
||||||
|
// should increase priority of the given input during subsequent fuzzing (for
|
||||||
|
// example, the input is lexically correct and was parsed successfully); -1 if
|
||||||
|
// the input must not be added to corpus even if gives new coverage; and 0
|
||||||
|
// otherwise; other values are reserved for future use.
|
||||||
|
func Fuzz(data []byte) int {
|
||||||
|
// Setup SDT header pointing to data
|
||||||
|
headerLen := unsafe.Sizeof(table.SDTHeader{})
|
||||||
|
stream := make([]byte, int(headerLen)+len(data))
|
||||||
|
copy(stream[headerLen:], data)
|
||||||
|
|
||||||
|
header := (*table.SDTHeader)(unsafe.Pointer(&stream[0]))
|
||||||
|
header.Signature = [4]byte{'D', 'S', 'D', 'T'}
|
||||||
|
header.Length = uint32(len(stream))
|
||||||
|
header.Revision = 2
|
||||||
|
|
||||||
|
tree := NewObjectTree()
|
||||||
|
tree.CreateDefaultScopes(0)
|
||||||
|
if err := NewParser(ioutil.Discard, tree).ParseAML(uint8(1), "DSDT", header); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
@ -16,9 +16,41 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
regenExpFiles = flag.Bool("aml-regenerate-parser-exp-files", false, "Regenerate the expected output files for AML parser tests against real AML files")
|
regenExpFiles = flag.Bool("aml-regenerate-parser-exp-files", false, "Regenerate the expected output files for AML parser tests against real AML files")
|
||||||
|
replayCrashersFrom = flag.String("aml-replay-crashers-from", "", "Replay go-fuzz generated crasher files from this folder")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TestParserCrashers scans through the crasher corpus generated by go-fuzz and
|
||||||
|
// pipes each corpus through the AML parser.
|
||||||
|
func TestParserCrashers(t *testing.T) {
|
||||||
|
if *replayCrashersFrom == "" {
|
||||||
|
t.Skip("-aml-replay-crashers-from not specified; skipping")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzzFiles, err := filepath.Glob(filepath.Join(*replayCrashersFrom, "*"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fuzzFile := range fuzzFiles {
|
||||||
|
// corpus files lack an extension
|
||||||
|
if filepath.Ext(fuzzFile) != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(fuzzFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("trying to parse crash corpus: %q", fuzzFile)
|
||||||
|
p, resolver := parserForMockPayload(t, data)
|
||||||
|
_ = p.ParseAML(0, "DSDT", resolver.LookupTable("DSDT"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestParser(t *testing.T) {
|
func TestParser(t *testing.T) {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user