summaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
authorAllen Webb <allenwebb@google.com>2018-08-17 11:31:39 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-08-22 16:02:19 -0700
commit625acc6b7c7455b0f7c6ad49f467737ce64b37eb (patch)
treef9786735eb02c8e448ddcd02718ca4b833b9278a /fuzz
parent26708ffa05ee1fc88bd754ddb959499acea1c41d (diff)
downloadchrome-ec-625acc6b7c7455b0f7c6ad49f467737ce64b37eb.tar.gz
Move fuzzing tests into a fuzz subfolder.
BRANCH=none CQ-DEPEND=CL:*664115 BUG=chromium:876582 TEST=make -j buildall && make -j buildfuzztests Change-Id: Iade5e5138f495e6b3b99ec16f1a467861ade5537 Signed-off-by: Allen Webb <allenwebb@google.com> Reviewed-on: https://chromium-review.googlesource.com/1180179 Reviewed-by: Mattias Nissler <mnissler@chromium.org> Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
Diffstat (limited to 'fuzz')
-rw-r--r--fuzz/build.mk11
-rw-r--r--fuzz/fuzz_config.h29
-rw-r--r--fuzz/host_command_fuzz.c169
-rw-r--r--fuzz/host_command_fuzz.tasklist17
4 files changed, 226 insertions, 0 deletions
diff --git a/fuzz/build.mk b/fuzz/build.mk
new file mode 100644
index 0000000000..dc3fb8eb29
--- /dev/null
+++ b/fuzz/build.mk
@@ -0,0 +1,11 @@
+# -*- makefile -*-
+# Copyright 2018 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.
+#
+# fuzzer binaries
+#
+
+fuzz-test-list-host = host_command_fuzz
+
+host_command_fuzz-y = host_command_fuzz.o
diff --git a/fuzz/fuzz_config.h b/fuzz/fuzz_config.h
new file mode 100644
index 0000000000..6244340c7e
--- /dev/null
+++ b/fuzz/fuzz_config.h
@@ -0,0 +1,29 @@
+/* Copyright 2018 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.
+ */
+
+/* Fuzzer target config flags */
+
+#ifndef __FUZZ_FUZZ_CONFIG_H
+#define __FUZZ_FUZZ_CONFIG_H
+#ifdef TEST_FUZZ
+
+/* Disable hibernate: We never want to exit while fuzzing. */
+#undef CONFIG_HIBERNATE
+
+#ifdef TEST_HOST_COMMAND_FUZZ
+#undef CONFIG_HOSTCMD_DEBUG_MODE
+
+/* Defining this makes fuzzing slower, but exercises additional code paths. */
+#define FUZZ_HOSTCMD_VERBOSE
+
+#ifdef FUZZ_HOSTCMD_VERBOSE
+#define CONFIG_HOSTCMD_DEBUG_MODE HCDEBUG_PARAMS
+#else
+#define CONFIG_HOSTCMD_DEBUG_MODE HCDEBUG_OFF
+#endif /* ! FUZZ_HOSTCMD_VERBOSE */
+#endif /* TEST_HOST_COMMAND_FUZZ */
+
+#endif /* TEST_FUZZ */
+#endif /* __TEST_TEST_CONFIG_H */
diff --git a/fuzz/host_command_fuzz.c b/fuzz/host_command_fuzz.c
new file mode 100644
index 0000000000..7f0bfad7a5
--- /dev/null
+++ b/fuzz/host_command_fuzz.c
@@ -0,0 +1,169 @@
+/* Copyright 2018 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.
+ *
+ * Fuzz host command.
+ */
+
+#include <pthread.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "console.h"
+#include "host_command.h"
+#include "host_test.h"
+#include "task.h"
+#include "test_util.h"
+#include "timer.h"
+#include "util.h"
+
+/* Only test requests with valid size and checksum (makes fuzzing faster) */
+#define VALID_REQUEST_ONLY
+
+#define TASK_EVENT_FUZZ TASK_EVENT_CUSTOM(1)
+#define TASK_EVENT_HOSTCMD_DONE TASK_EVENT_CUSTOM(2)
+
+/* Request/response buffer size (and maximum command length) */
+#define BUFFER_SIZE 128
+
+struct host_packet pkt;
+static uint8_t resp_buf[BUFFER_SIZE];
+struct ec_host_response *resp = (struct ec_host_response *)resp_buf;
+static uint8_t req_buf[BUFFER_SIZE];
+static struct ec_host_request *req = (struct ec_host_request *)req_buf;
+
+static void hostcmd_respond(struct host_packet *pkt)
+{
+ task_set_event(TASK_ID_TEST_RUNNER, TASK_EVENT_HOSTCMD_DONE, 0);
+}
+
+static char calculate_checksum(const char *buf, int size)
+{
+ int c = 0;
+ int i;
+
+ for (i = 0; i < size; ++i)
+ c += buf[i];
+
+ return -c;
+}
+
+struct chunk {
+ int start;
+ int size;
+};
+
+static int hostcmd_fill(const uint8_t *data, size_t size)
+{
+ static int first = 1;
+
+#ifdef VALID_REQUEST_ONLY
+ const int checksum_offset = offsetof(struct ec_host_request, checksum);
+ const int checksum_size = sizeof(req->checksum);
+ const int data_len_offset = offsetof(struct ec_host_request, data_len);
+ const int data_len_size = sizeof(req->data_len);
+
+ struct chunk chunks[3];
+
+ chunks[0].start = 0;
+ chunks[0].size = checksum_offset;
+ chunks[1].start = chunks[0].start + chunks[0].size + checksum_size;
+ chunks[1].size = data_len_offset - chunks[1].start;
+ chunks[2].start = chunks[1].start + chunks[1].size + data_len_size;
+ chunks[2].size = sizeof(req_buf) - chunks[2].start;
+#else
+ struct chunk chunks[1] = { {0, sizeof(req_buf)} };
+#endif
+
+ int ipos = 0;
+ int i;
+ int req_size = 0;
+
+ /*
+ * TODO(chromium:854975): We should probably malloc req_buf with the
+ * correct size, to make we do not read uninitialized req_buf data.
+ */
+ memset(req_buf, 0, sizeof(req_buf));
+
+ /*
+ * Fill in req_buf, according to chunks defined above (i.e. skipping
+ * over checksum and data_len.
+ */
+ for (i = 0; i < ARRAY_SIZE(chunks) && ipos < size; i++) {
+ int cp_size = MIN(chunks[i].size, size-ipos);
+
+ memcpy(req_buf + chunks[i].start, data + ipos, cp_size);
+
+ ipos += cp_size;
+
+ req_size = chunks[i].start + cp_size;
+ }
+
+ /* Not enough space in req_buf. */
+ if (ipos != size)
+ return -1;
+
+ pkt.request_size = req_size;
+ req->data_len = req_size - sizeof(*req);
+ req->checksum = calculate_checksum(req_buf, req_size);
+
+ /*
+ * Print the full request on the first fuzzing attempt: useful to
+ * report bugs, and write up commit messages when reproducing
+ * issues.
+ */
+ if (first) {
+ ccprintf("Request: cmd=%04x data=%.*h\n",
+ req->command, req_size, req_buf);
+ first = 0;
+ }
+
+ pkt.send_response = hostcmd_respond;
+ pkt.request = (const void *)req_buf;
+ pkt.request_max = BUFFER_SIZE;
+ pkt.response = (void *)resp_buf;
+ pkt.response_max = BUFFER_SIZE;
+ pkt.driver_result = 0;
+
+ return 0;
+}
+
+static pthread_cond_t done_cond;
+static pthread_mutex_t lock;
+
+void run_test(void)
+{
+ ccprints("Fuzzing task started");
+ wait_for_task_started();
+
+ while (1) {
+ task_wait_event_mask(TASK_EVENT_FUZZ, -1);
+ /* Send the host command (pkt prepared by main thread). */
+ host_packet_receive(&pkt);
+ task_wait_event_mask(TASK_EVENT_HOSTCMD_DONE, -1);
+ pthread_cond_signal(&done_cond);
+ }
+}
+
+int test_fuzz_one_input(const uint8_t *data, unsigned int size)
+{
+ /* Fill in req_buf. */
+ if (hostcmd_fill(data, size) < 0)
+ return 0;
+
+ task_set_event(TASK_ID_TEST_RUNNER, TASK_EVENT_FUZZ, 0);
+ pthread_cond_wait(&done_cond, &lock);
+
+#ifdef VALID_REQUEST_ONLY
+ /*
+ * We carefully crafted all our requests to have a valid checksum, so
+ * we should never receive an invalid checksum error. (but ignore
+ * EC_CMD_TEST_PROTOCOL, as it can lead to arbitrary result values).
+ */
+ ASSERT(req->command == EC_CMD_TEST_PROTOCOL ||
+ resp->result != EC_RES_INVALID_CHECKSUM);
+#endif
+
+ return 0;
+}
+
diff --git a/fuzz/host_command_fuzz.tasklist b/fuzz/host_command_fuzz.tasklist
new file mode 100644
index 0000000000..de4df33e13
--- /dev/null
+++ b/fuzz/host_command_fuzz.tasklist
@@ -0,0 +1,17 @@
+/* Copyright 2018 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.
+ */
+
+/**
+ * List of enabled tasks in the priority order
+ *
+ * The first one has the lowest priority.
+ *
+ * For each task, use the macro TASK_TEST(n, r, d, s) where :
+ * 'n' in the name of the task
+ * 'r' in the main routine of the task
+ * 'd' in an opaque parameter passed to the routine at startup
+ * 's' is the stack size in bytes; must be a multiple of 8
+ */
+#define CONFIG_TEST_TASK_LIST