sensors hal fuzz test.
Test: manual
Change-Id: If3e769ffc384b4ad902470cd49218369c7fe2aca
diff --git a/testcases/hal/common/fuzz/Android.hal_fuzzer.mk b/testcases/hal/common/fuzz/Android.hal_fuzzer.mk
index d48a237..8262c29 100644
--- a/testcases/hal/common/fuzz/Android.hal_fuzzer.mk
+++ b/testcases/hal/common/fuzz/Android.hal_fuzzer.mk
@@ -14,6 +14,8 @@
# limitations under the License.
#
+include $(CLEAR_VARS)
+
# TODO(trong): enable for mips and x86.
ifeq (,$(findstring mips, $(TARGET_ARCH)))
ifeq (,$(findstring x86, $(TARGET_ARCH)))
@@ -33,6 +35,7 @@
LOCAL_SHARED_LIBRARIES := \
$(module_shared_libraries) \
libutils \
+ libhidl \
libhardware \
LOCAL_ARM_MODE := arm
diff --git a/testcases/hal/sensors/Android.mk b/testcases/hal/sensors/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/testcases/hal/sensors/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/testcases/hal/sensors/__init__.py b/testcases/hal/sensors/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testcases/hal/sensors/__init__.py
diff --git a/testcases/hal/sensors/fuzz/Android.mk b/testcases/hal/sensors/fuzz/Android.mk
new file mode 100644
index 0000000..379ff65
--- /dev/null
+++ b/testcases/hal/sensors/fuzz/Android.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+module_name := ISensorsFlush_fuzzer
+module_src_files := ISensorsFlush_fuzzer.cpp
+module_shared_libraries := android.hardware.sensors@1.0
+include test/vts/testcases/hal/common/fuzz/Android.hal_fuzzer.mk
+
+include $(CLEAR_VARS)
+module_name := ISensorsPoll_fuzzer
+module_src_files := ISensorsPoll_fuzzer.cpp
+module_shared_libraries := android.hardware.sensors@1.0
+include test/vts/testcases/hal/common/fuzz/Android.hal_fuzzer.mk
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ISensorsFuzzTest
+VTS_CONFIG_SRC_DIR := testcases/hal/sensors/fuzz
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/hal/sensors/fuzz/AndroidTest.xml b/testcases/hal/sensors/fuzz/AndroidTest.xml
new file mode 100644
index 0000000..ce29b2e
--- /dev/null
+++ b/testcases/hal/sensors/fuzz/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for VTS Sensors HIDL HAL's target-side fuzz test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="LLVMFuzzerTest.push" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="ISensorsFuzzTest" />
+ <option name="binary-test-sources" value="
+ hal_fuzz/ISensorsFlush_fuzzer,
+ hal_fuzz/ISensorsPoll_fuzzer
+ "/>
+ <option name="binary-test-type" value="llvmfuzzer" />
+ </test>
+</configuration>
diff --git a/testcases/hal/sensors/fuzz/ISensorsFlush_fuzzer.cpp b/testcases/hal/sensors/fuzz/ISensorsFlush_fuzzer.cpp
new file mode 100644
index 0000000..fab94be
--- /dev/null
+++ b/testcases/hal/sensors/fuzz/ISensorsFlush_fuzzer.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <FuzzerInterface.h>
+#include <android/hardware/sensors/1.0/ISensors.h>
+
+using ::android::hardware::sensors::V1_0::ISensors;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ static ::android::sp<ISensors> sensors_hal = ISensors::getService("sensors", true);
+ if (sensors_hal == nullptr) {
+ return 0;
+ }
+ if (size < sizeof(int32_t)) {
+ return 0;
+ }
+ int32_t sensorHandle;
+ memcpy(&sensorHandle, data, sizeof(int32_t));
+
+ sensors_hal->flush(sensorHandle);
+ return 0;
+}
diff --git a/testcases/hal/sensors/fuzz/ISensorsPoll_fuzzer.cpp b/testcases/hal/sensors/fuzz/ISensorsPoll_fuzzer.cpp
new file mode 100644
index 0000000..da3f0d7
--- /dev/null
+++ b/testcases/hal/sensors/fuzz/ISensorsPoll_fuzzer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+
+#include <FuzzerInterface.h>
+#include <android/hardware/sensors/1.0/ISensors.h>
+
+using ::android::hardware::sensors::V1_0::ISensors;
+
+auto _hidl_cb = [](auto x, auto y, auto z){};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ static ::android::sp<ISensors> sensors_hal = ISensors::getService("sensors", true);
+ if (sensors_hal == nullptr) {
+ return 0;
+ }
+ if (size < sizeof(int32_t)) {
+ return 0;
+ }
+ int32_t maxCount;
+ memcpy(&maxCount, data, sizeof(int32_t));
+
+ sensors_hal->poll(maxCount, _hidl_cb);
+ return 0;
+}
diff --git a/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py b/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py
index 2dafcf5..eb0e5b9 100644
--- a/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py
+++ b/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py
@@ -76,20 +76,19 @@
self._dut.adb.push("%s %s" % (push_src, config.FUZZER_TEST_DIR))
logging.info("Adb pushed: %s", testcase)
- # TODO(trong): save crash-causing inputs to the fuzzer.
def RunTestcase(self, testcase):
"""Runs the given testcase and asserts the result.
Args:
- testcase: string, path to executable fuzzer.
+ testcase: string, path to fuzzer executable.
"""
self.PushFiles(testcase)
- testcase = testcase.split("/")[-1]
+ fuzzer = testcase.split("/")[-1]
- chmod_cmd = "chmod -R 755 %s" % os.path.join(config.FUZZER_TEST_DIR, testcase)
- cd_cmd = "cd %s" % os.path.join(config.FUZZER_TEST_DIR)
- test_cmd = "./%s" % testcase
+ chmod_cmd = "chmod -R 755 %s" % os.path.join(config.FUZZER_TEST_DIR, fuzzer)
+ cd_cmd = "cd %s" % config.FUZZER_TEST_DIR
ld_path = "LD_LIBRARY_PATH=/data/local/tmp/32:/data/local/tmp/64:$LD_LIBRARY_PATH"
+ test_cmd = "./%s" % fuzzer
cmd = [
chmod_cmd,
@@ -98,10 +97,35 @@
logging.info("Executing: %s", cmd)
result = self._shell.Execute(cmd)
- self.AssertTestResult(result)
+ self.AssertTestResult(fuzzer, result)
+
+ def LogCrashReport(self, fuzzer):
+ """Logs crash-causing fuzzer input.
+
+ Reads the crash report file and logs the contents in format:
+ "\x01\x23\x45\x67\x89\xab\xcd\xef"
+
+ Args:
+ fuzzer: string, name of fuzzer executable.
+ """
+ cmd = "xxd -p %s" % config.FUZZER_TEST_CRASH_REPORT
+
+ # output is string of a hexdump from crash report file.
+ # From the example above, output would be "0123456789abcdef".
+ output = self._shell.Execute(cmd)[const.STDOUT][0]
+ remove_chars = ["\r", "\t", "\n", " "]
+ for char in remove_chars:
+ output = output.replace(char, "")
+
+ crash_report = ""
+ # output is guaranteed to be even in length since its a hexdump.
+ for offset in xrange(0, len(output), 2):
+ crash_report += "\\x%s" % output[offset:offset + 2]
+
+ logging.info("FUZZER_TEST_CRASH_REPORT for %s: '%s'", fuzzer, crash_report)
# TODO(trong): differentiate between crashes and sanitizer rule violations.
- def AssertTestResult(self, result):
+ def AssertTestResult(self, fuzzer, result):
"""Asserts that testcase finished as expected.
Checks that device is in responsive state. If not, waits for boot
@@ -109,23 +133,25 @@
returned exit code 0.
Args:
+ fuzzer: string, name of fuzzer executable.
result: dict([str],[str],[int]), command results from shell.
"""
- if self._dut.hasBooted():
- exit_codes = result[const.EXIT_CODE]
- logging.info("EXIT_CODE: %s", exit_codes)
- asserts.assertFalse(
- any(exit_codes), "Test case failed.")
- else:
+ if not self._dut.hasBooted():
self._dut.waitForBootCompletion()
- asserts.fail("Test case left the device in unresponsive state.")
+ asserts.fail("%s left the device in unresponsive state." % fuzzer)
+
+ # Last exit code is the exit code of the fuzzer executable.
+ exit_code = result[const.EXIT_CODE][-1]
+ if exit_code == config.ExitCode.FUZZER_TEST_FAIL:
+ self.LogCrashReport(fuzzer)
+ asserts.fail("%s failed" % fuzzer)
def generateFuzzerTests(self):
"""Runs fuzzer tests."""
self.runGeneratedTests(
test_func=self.RunTestcase,
settings=self._testcases,
- name_func=lambda x: x.replace('/','_'))
+ name_func=lambda x: x.split("/")[-1])
if __name__ == "__main__":
diff --git a/testcases/template/llvmfuzzer_test/llvmfuzzer_test_config.py b/testcases/template/llvmfuzzer_test/llvmfuzzer_test_config.py
index d4757d3..1407f76 100644
--- a/testcases/template/llvmfuzzer_test/llvmfuzzer_test_config.py
+++ b/testcases/template/llvmfuzzer_test/llvmfuzzer_test_config.py
@@ -15,13 +15,21 @@
# limitations under the License.
#
+class ExitCode(object):
+ """Exit codes for test binaries."""
+ FUZZER_TEST_PASS = 0
+ FUZZER_TEST_FAIL = 77
# Directory on the target where the tests are copied.
FUZZER_TEST_DIR = "/data/local/tmp/llvmfuzzer_test"
+# File used to save crash-causing fuzzer input.
+FUZZER_TEST_CRASH_REPORT = FUZZER_TEST_DIR + "/crash_report"
+
# Default parameters that will be passed to fuzzer executable.
FUZZER_PARAMS = {
"max_len": 64,
- "max_total_time": 10
+ "max_total_time": 10,
+ "exact_artifact_path": FUZZER_TEST_CRASH_REPORT
}