From 089a944d51778640d26a125123e1d1946c828e90 Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Mon, 14 Oct 2019 17:03:45 +0200 Subject: tests: Add cgpt fuzzer. This adds a fuzzer binary to exercise GPT parsing. BUG=chromium:1014101 TEST=Build and run fuzzer. BRANCH=none Change-Id: Idecc0ddf491e976d4e01f5778e51a01ac317d961 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1859595 Reviewed-by: Julius Werner Tested-by: Manoj Gupta Commit-Queue: Manoj Gupta --- Makefile | 22 ++++++++++++++ tests/cgpt_fuzzer.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 tests/cgpt_fuzzer.c diff --git a/Makefile b/Makefile index d5aa28f3..93ac67c1 100644 --- a/Makefile +++ b/Makefile @@ -242,6 +242,10 @@ LDFLAGS += -static PKG_CONFIG += --static endif +ifneq (${FUZZ_FLAGS},) +CFLAGS += ${FUZZ_FLAGS} +endif + # Optional Libraries LIBZIP_VERSION := $(shell ${PKG_CONFIG} --modversion libzip 2>/dev/null) HAVE_LIBZIP := $(if ${LIBZIP_VERSION},1) @@ -775,6 +779,14 @@ TEST21_BINS = $(addprefix ${BUILD}/,${TEST21_NAMES}) # Directory containing test keys TEST_KEYS = ${SRC_RUN}/tests/testkeys +# ---------------------------------------------------------------------------- +# Fuzzing binaries + +FUZZ_TEST_NAMES = \ + tests/cgpt_fuzzer + +FUZZ_TEST_BINS = $(addprefix ${BUILD}/,${FUZZ_TEST_NAMES}) +FUZZ_TEST_OBJS += $(addsuffix .o,${FUZZ_TEST_BINS}) ############################################################################## # Finally, some targets. High-level ones first. @@ -793,6 +805,7 @@ host_tools: utils futil tests .PHONY: host_stuff host_stuff: utillib hostlib \ + $(if $(filter x86_64,${ARCH}),fuzzers) \ $(if ${NO_BUILD_TOOLS},,cgpt host_tools) .PHONY: clean @@ -1073,6 +1086,15 @@ ${TESTLIB}: ${TESTLIB_OBJS} @${PRINTF} " AR $(subst ${BUILD}/,,$@)\n" ${Q}ar qc $@ $^ +# ---------------------------------------------------------------------------- +# Fuzzers + +.PHONY: fuzzers +fuzzers: ${FUZZ_TEST_BINS} + +${FUZZ_TEST_BINS}: ${FWLIB} +${FUZZ_TEST_BINS}: LIBS = ${FWLIB} +${FUZZ_TEST_BINS}: LDFLAGS += -fsanitize=fuzzer # ---------------------------------------------------------------------------- # Generic build rules. LIBS and OBJS can be overridden to tweak the generic diff --git a/tests/cgpt_fuzzer.c b/tests/cgpt_fuzzer.c new file mode 100644 index 00000000..51ba72a3 --- /dev/null +++ b/tests/cgpt_fuzzer.c @@ -0,0 +1,86 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "cgptlib.h" +#include "gpt.h" + +struct MockDisk { + size_t sector_shift; + const uint8_t* data; + size_t size; +}; + +// GPT disk parameters provided by the fuzzer test case. See GptData type +// definition for details. +struct GptDataParams { + uint32_t sector_shift; + uint32_t flags; + uint64_t streaming_drive_sectors; + uint64_t gpt_drive_sectors; +} __attribute__((packed)); + +static struct MockDisk mock_disk; + +vb2_error_t VbExDiskRead(VbExDiskHandle_t h, uint64_t lba_start, + uint64_t lba_count, void *buffer) +{ + size_t lba_size = mock_disk.size >> mock_disk.sector_shift; + if (lba_start > lba_size || lba_size - lba_start < lba_count) { + return VB2_ERROR_UNKNOWN; + } + + size_t start = lba_start << mock_disk.sector_shift; + size_t size = lba_count << mock_disk.sector_shift; + + memcpy(buffer, &mock_disk.data[start], size); + return VB2_SUCCESS; +} + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + struct GptDataParams params; + if (size < sizeof(params)) { + return 0; + } + memcpy(¶ms, data, sizeof(params)); + + // Enforce a sane sector size. The sector size must accommodate the GPT + // header (the code assumes this) and large values don't make sense + // either (both in terms of actual hardware parameters and ability for + // the fuzzer to deal with effectively). + if (params.sector_shift < 9) { + params.sector_shift = 9; // 512 byte sectors min. + } + if (params.sector_shift > 12) { + params.sector_shift = 12; // 4K sectors max. + } + + mock_disk.sector_shift = params.sector_shift; + mock_disk.data = data + sizeof(params); + mock_disk.size = size - sizeof(params); + + GptData gpt; + memset(&gpt, 0, sizeof(gpt)); + gpt.sector_bytes = 1ULL << params.sector_shift; + gpt.streaming_drive_sectors = params.streaming_drive_sectors; + gpt.gpt_drive_sectors = params.gpt_drive_sectors; + gpt.flags = params.flags; + + if (0 == AllocAndReadGptData(0, &gpt)) { + int result = GptInit(&gpt); + while (GPT_SUCCESS == result) { + uint64_t part_start, part_size; + result = GptNextKernelEntry(&gpt, &part_start, + &part_size); + } + } + + WriteAndFreeGptData(0, &gpt); + + return 0; +} -- cgit v1.2.1