Initial ART fuzzer for DEX verification

It fuzzes the verifier by generating DEX files,
trying to open them, and verify them.

Add a small corpus to start with:
 * Empty: Totally empty file (invalid DEX)
 * Main: Empty main (valid DEX)
 * Hello-world: Main that prints "Hello, world!"

Add a small dictionary with valid DEX headers.

Bug: 249085422
Change-Id: I9a6a555ea2462e7156669e1728815f8dcaacb23a
diff --git a/tools/fuzzer/Android.bp b/tools/fuzzer/Android.bp
new file mode 100644
index 0000000..8ade397
--- /dev/null
+++ b/tools/fuzzer/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2023 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.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "art_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["art_license"],
+}
+
+cc_fuzz {
+    name: "libart_verify_dex_fuzzer",
+    srcs: ["libart_verify_dex_fuzzer.cc"],
+    defaults: ["libart_static_defaults"],
+    // Build and run on x86 only for now.
+    host_supported: true,
+    device_supported: false,
+    corpus: ["corpus/*"],
+    dictionary: "dex.dict",
+    fuzz_config: {
+        cc: ["solanes@google.com", "art-bugs@google.com"],
+        componentid: 86431,
+        acknowledgement: [
+            "Santiago Aboy Solanes of Google",
+        ],
+    },
+}
diff --git a/tools/fuzzer/corpus/Main.dex b/tools/fuzzer/corpus/Main.dex
new file mode 100644
index 0000000..ec29035
--- /dev/null
+++ b/tools/fuzzer/corpus/Main.dex
Binary files differ
diff --git a/tools/fuzzer/corpus/empty.dex b/tools/fuzzer/corpus/empty.dex
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/fuzzer/corpus/empty.dex
diff --git a/tools/fuzzer/corpus/hello_world.dex b/tools/fuzzer/corpus/hello_world.dex
new file mode 100644
index 0000000..6e59dd7
--- /dev/null
+++ b/tools/fuzzer/corpus/hello_world.dex
Binary files differ
diff --git a/tools/fuzzer/dex.dict b/tools/fuzzer/dex.dict
new file mode 100644
index 0000000..e728414
--- /dev/null
+++ b/tools/fuzzer/dex.dict
@@ -0,0 +1,11 @@
+#
+# AFL dictionary for DEX code
+# -----------------------------
+#
+
+# Valid headers: DEX magic word + version
+header_dex_035=\x64\x65\x78\x0a\x30\x33\x35
+header_dex_037=\x64\x65\x78\x0a\x30\x33\x37
+header_dex_038=\x64\x65\x78\x0a\x30\x33\x38
+header_dex_039=\x64\x65\x78\x0a\x30\x33\x39
+header_dex_040=\x64\x65\x78\x0a\x30\x34\x30
diff --git a/tools/fuzzer/libart_verify_dex_fuzzer.cc b/tools/fuzzer/libart_verify_dex_fuzzer.cc
new file mode 100644
index 0000000..39ebe0e
--- /dev/null
+++ b/tools/fuzzer/libart_verify_dex_fuzzer.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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 "base/mem_map.h"
+#include "dex/dex_file_loader.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  // Initialize environment.
+  art::MemMap::Init();
+
+  // Open and verify the DEX file. Do not verify the checksum as we only care about the DEX file
+  // contents, and know that the checksum would probably be erroneous.
+  std::string error_msg;
+  art::DexFileLoader loader(data, size, /*location=*/"");
+  std::unique_ptr<const art::DexFile> dex_file = loader.Open(
+      /*location_checksum=*/0, /*verify=*/true, /*verify_checksum=*/false, &error_msg);
+  return 0;
+}