Snap for 7474514 from 309df156ac2344e041e981af204efac8e87c8a83 to mainline-media-release
Change-Id: I2b46905e59d51ee872db051759ec7ca60ee1196d
diff --git a/OWNERS b/OWNERS
index 96f0a09..7d6099d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,9 +6,12 @@
# Haiku members (fuzzing-on-Android)
hamzeh@google.com
-ispo@google.com
kalder@google.com
+mspector@google.com
# ASA
olorin@google.com
-danielaustin@google.com
+
+# Remote Provisioning
+jbires@google.com
+swillden@google.com
diff --git a/fuzzing/example_fuzzer/Android.bp b/fuzzing/example_fuzzer/Android.bp
index a3e9e8c..a3efd3e 100644
--- a/fuzzing/example_fuzzer/Android.bp
+++ b/fuzzing/example_fuzzer/Android.bp
@@ -1,3 +1,7 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_fuzz {
name: "example_fuzzer",
srcs: [
diff --git a/fuzzing/example_rust_fuzzer/Android.bp b/fuzzing/example_rust_fuzzer/Android.bp
new file mode 100644
index 0000000..dccc611
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2021, 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_fuzz {
+ name: "example_rust_fuzzer",
+ srcs: ["fuzzer.rs"],
+ fuzz_config: {
+ fuzz_on_haiku_device: true,
+ fuzz_on_haiku_host: false,
+ },
+ corpus: ["testdata/*"],
+ dictionary: "example_rust_fuzzer.dict",
+}
diff --git a/fuzzing/example_rust_fuzzer/example_rust_fuzzer.dict b/fuzzing/example_rust_fuzzer/example_rust_fuzzer.dict
new file mode 100644
index 0000000..6edf100
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/example_rust_fuzzer.dict
@@ -0,0 +1 @@
+"TEST"
\ No newline at end of file
diff --git a/fuzzing/example_rust_fuzzer/fuzzer.rs b/fuzzing/example_rust_fuzzer/fuzzer.rs
new file mode 100644
index 0000000..e4cebcb
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/fuzzer.rs
@@ -0,0 +1,30 @@
+// Copyright 2021, 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.
+
+#![allow(missing_docs)]
+#![no_main]
+#[macro_use] extern crate libfuzzer_sys;
+
+fn heap_oob() {
+ let xs = vec![0, 1, 2, 3];
+ let val = unsafe { *xs.as_ptr().offset(4) };
+ println!("Out-of-bounds heap value: {}", val);
+}
+
+fuzz_target!(|data: &[u8]| {
+ let magic_number = 327;
+ if data.len() == magic_number {
+ heap_oob();
+ }
+});
diff --git a/fuzzing/example_rust_fuzzer/testdata/test.txt b/fuzzing/example_rust_fuzzer/testdata/test.txt
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/testdata/test.txt
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/fuzzing/media_fuzzers/OWNERS b/fuzzing/media_fuzzers/OWNERS
deleted file mode 100644
index 241b65a..0000000
--- a/fuzzing/media_fuzzers/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-hamzeh@google.com
-ispo@google.com
-kalder@google.com
-mspector@google.com
-semsmith@google.com
diff --git a/fuzzing/orphans/OWNERS b/fuzzing/orphans/OWNERS
index c7bd45b..1913c00 100644
--- a/fuzzing/orphans/OWNERS
+++ b/fuzzing/orphans/OWNERS
@@ -1,4 +1,4 @@
hamzeh@google.com
-ispo@google.com
kalder@google.com
mitchp@google.com
+mspector@google.com
diff --git a/fuzzing/orphans/gptfdisk/Android.bp b/fuzzing/orphans/gptfdisk/Android.bp
new file mode 100644
index 0000000..e1c5333
--- /dev/null
+++ b/fuzzing/orphans/gptfdisk/Android.bp
@@ -0,0 +1,21 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+ name: "sgdisk_fuzz",
+ host_supported: true,
+ srcs: [
+ "sgdisk_fuzz.cc",
+ ],
+ static_libs: [
+ "libgptf",
+ ],
+ shared_libs: ["libext2_uuid"],
+ corpus: ["corpus/*"],
+ target: {
+ android: {
+ cflags: ["-DGPTFDISK_FUZZER_DEVICE"],
+ },
+ },
+}
diff --git a/fuzzing/orphans/gptfdisk/corpus/init.img b/fuzzing/orphans/gptfdisk/corpus/init.img
new file mode 100644
index 0000000..f87f897
--- /dev/null
+++ b/fuzzing/orphans/gptfdisk/corpus/init.img
Binary files differ
diff --git a/fuzzing/orphans/gptfdisk/sgdisk_fuzz.cc b/fuzzing/orphans/gptfdisk/sgdisk_fuzz.cc
new file mode 100644
index 0000000..6a02281
--- /dev/null
+++ b/fuzzing/orphans/gptfdisk/sgdisk_fuzz.cc
@@ -0,0 +1,58 @@
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <errno.h>
+#include "gptcl.h"
+#include <fcntl.h>
+#include <unistd.h>
+
+static int fuzz_gpt(char* partition_file) {
+ BasicMBRData mbrData;
+ GPTData gptData;
+ GPTPart partData;
+ int numParts = 0;
+ stringstream res;
+
+ gptData.JustLooking();
+ gptData.LoadPartitions((string) partition_file);
+ gptData.LoadMainTable();
+ gptData.GetDiskGUID();
+ numParts = gptData.GetNumParts();
+
+ //Extracted from the android_dump function in sgdisk.cc, hits more code
+ for (int i = 0; i < numParts; i++) {
+ partData = gptData[i];
+ if (partData.GetFirstLBA() > 0) {
+ partData.GetType();
+ partData.GetUniqueGUID();
+ partData.GetDescription();;
+ }
+ }
+ return 0;
+}
+
+#ifdef GPTFDISK_FUZZER_DEVICE
+#define TMPFILE_TEMPLATE "/data/local/tmp/gptfuzzXXXXXXXX\x00"
+#else
+#define TMPFILE_TEMPLATE "/dev/shm/gptfuzzXXXXXXXX\x00"
+#endif
+
+size_t TMPFILE_LEN = sizeof(TMPFILE_TEMPLATE);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ char partition_tmp_file[TMPFILE_LEN];
+ int tmpfd;
+
+ memcpy(partition_tmp_file, TMPFILE_TEMPLATE, TMPFILE_LEN);
+ tmpfd = mkstemp(partition_tmp_file);
+ if(tmpfd < 0)
+ return -1;
+ write(tmpfd, data, size);
+ close(tmpfd);
+ fuzz_gpt(partition_tmp_file);
+ remove(partition_tmp_file);
+ return 0;
+}
diff --git a/fuzzing/orphans/libcppbor/Android.bp b/fuzzing/orphans/libcppbor/Android.bp
new file mode 100644
index 0000000..3bb20f9
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/Android.bp
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+//
+// 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
+//
+// https://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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+ name: "cppbor_fuzzer",
+ srcs: [
+ "cppbor_fuzzer.cpp",
+ ],
+ shared_libs: [
+ "libcppbor_external",
+ ],
+ host_supported: true,
+}
+
+cc_fuzz {
+ name: "cppbor_parse_fuzzer",
+ srcs: [
+ "cppbor_parse_fuzzer.cpp",
+ ],
+ shared_libs: [
+ "libcppbor_external",
+ ],
+ corpus: ["corpus/*.cbor"],
+ host_supported: true,
+}
diff --git a/fuzzing/orphans/libcppbor/corpus/array_0.cbor b/fuzzing/orphans/libcppbor/corpus/array_0.cbor
new file mode 100644
index 0000000..5416677
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_0.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_1.cbor b/fuzzing/orphans/libcppbor/corpus/array_1.cbor
new file mode 100644
index 0000000..4cdf6ce
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_1.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_10.cbor b/fuzzing/orphans/libcppbor/corpus/array_10.cbor
new file mode 100644
index 0000000..9b1d08c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_10.cbor
@@ -0,0 +1 @@
+aa¡abac
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_11.cbor b/fuzzing/orphans/libcppbor/corpus/array_11.cbor
new file mode 100644
index 0000000..151c13e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_11.cbor
@@ -0,0 +1 @@
+aa¿abacÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_2.cbor b/fuzzing/orphans/libcppbor/corpus/array_2.cbor
new file mode 100644
index 0000000..80fd394
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_2.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_3.cbor b/fuzzing/orphans/libcppbor/corpus/array_3.cbor
new file mode 100644
index 0000000..a0f1ea2
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_3.cbor
@@ -0,0 +1 @@
+ÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_4.cbor b/fuzzing/orphans/libcppbor/corpus/array_4.cbor
new file mode 100644
index 0000000..dbbf8e5
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_4.cbor
@@ -0,0 +1 @@
+ÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_5.cbor b/fuzzing/orphans/libcppbor/corpus/array_5.cbor
new file mode 100644
index 0000000..ac2e49a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_5.cbor
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_6.cbor b/fuzzing/orphans/libcppbor/corpus/array_6.cbor
new file mode 100644
index 0000000..422ce24
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_6.cbor
@@ -0,0 +1 @@
+ÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_7.cbor b/fuzzing/orphans/libcppbor/corpus/array_7.cbor
new file mode 100644
index 0000000..f67cd57
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_7.cbor
@@ -0,0 +1 @@
+ÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_8.cbor b/fuzzing/orphans/libcppbor/corpus/array_8.cbor
new file mode 100644
index 0000000..78343ed
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_8.cbor
@@ -0,0 +1 @@
+ÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_9.cbor b/fuzzing/orphans/libcppbor/corpus/array_9.cbor
new file mode 100644
index 0000000..a9b24c8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_9.cbor
@@ -0,0 +1,3 @@
+
+
+ÿ
diff --git a/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_1.cbor b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_1.cbor
new file mode 100644
index 0000000..ff6a27b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_2.cbor b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_2.cbor
new file mode 100644
index 0000000..5790402
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/byte_string_0.cbor b/fuzzing/orphans/libcppbor/corpus/byte_string_0.cbor
new file mode 100644
index 0000000..b516b2c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/byte_string_0.cbor
@@ -0,0 +1 @@
+@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/byte_string_1.cbor b/fuzzing/orphans/libcppbor/corpus/byte_string_1.cbor
new file mode 100644
index 0000000..352e89a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/byte_string_1.cbor
@@ -0,0 +1 @@
+D
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/byte_string_2.cbor b/fuzzing/orphans/libcppbor/corpus/byte_string_2.cbor
new file mode 100644
index 0000000..2681a85
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/byte_string_2.cbor
@@ -0,0 +1 @@
+_BCÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_0.cbor b/fuzzing/orphans/libcppbor/corpus/cose_0.cbor
new file mode 100644
index 0000000..0768c4c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_1.cbor b/fuzzing/orphans/libcppbor/corpus/cose_1.cbor
new file mode 100644
index 0000000..17d89c4
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_10.cbor b/fuzzing/orphans/libcppbor/corpus/cose_10.cbor
new file mode 100644
index 0000000..e8805a1
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_10.cbor
@@ -0,0 +1,2 @@
+ÐC¡
+¡Mõ/e¡Å;Ra§XYtá¹:LÀe¢éçÿñaÓç´\ä`ÿµi
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_11.cbor b/fuzzing/orphans/libcppbor/corpus/cose_11.cbor
new file mode 100644
index 0000000..70f90d0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_11.cbor
@@ -0,0 +1,2 @@
+ÐC¡
+¡Ba§X%*ÔeÁ%¶vG9pAí -á9àS½ «Ê
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_12.cbor b/fuzzing/orphans/libcppbor/corpus/cose_12.cbor
new file mode 100644
index 0000000..fc2be35
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_12.cbor
@@ -0,0 +1 @@
+Øa
C¡ TThis is the content.H&º¸H@¢%Jour-secret@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_13.cbor b/fuzzing/orphans/libcppbor/corpus/cose_13.cbor
new file mode 100644
index 0000000..1c368ac
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_13.cbor
@@ -0,0 +1 @@
+Øa
C¡ TThis is the content.X 4H¬ÓÓ7nªû?ä©U¾,¾~Éo,KÃñjAD¡8£"X!peregrin.took@tuckborough.exampleX$meriadoc.brandybuck@buckland.example5X@M
SççO<j:Óï(jËø¢=UÏì}4¸$ô-½½,qð!N·y®(V«õ
¥h°çò©åÎMµ@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_14.cbor b/fuzzing/orphans/libcppbor/corpus/cose_14.cbor
new file mode 100644
index 0000000..03ffb68
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_14.cbor
@@ -0,0 +1 @@
+Øa
C¡ TThis is the content.H6õ¯¯«]C@¢$X$018c0ae5-4d9b-471b-bfd6-eef314bc7037Xq°Ü/ÄX]Î'ïúgÈ >ºo"{n°
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_15.cbor b/fuzzing/orphans/libcppbor/corpus/cose_15.cbor
new file mode 100644
index 0000000..9b0f078
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_15.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_16.cbor b/fuzzing/orphans/libcppbor/corpus/cose_16.cbor
new file mode 100644
index 0000000..987556b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_16.cbor
@@ -0,0 +1 @@
+ÑC¡ TThis is the content.Hr`CtP'!O
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_2.cbor b/fuzzing/orphans/libcppbor/corpus/cose_2.cbor
new file mode 100644
index 0000000..46e9790
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_3.cbor b/fuzzing/orphans/libcppbor/corpus/cose_3.cbor
new file mode 100644
index 0000000..110ea03
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_4.cbor b/fuzzing/orphans/libcppbor/corpus/cose_4.cbor
new file mode 100644
index 0000000..33b652f
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_5.cbor b/fuzzing/orphans/libcppbor/corpus/cose_5.cbor
new file mode 100644
index 0000000..b0f63b8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_5.cbor
@@ -0,0 +1 @@
+ÒC¡&¡B11TThis is the content.X@³>L£FZ°Z¬4Ìk#Õï\1ÄÒZ®ð°~*ù¢ª2áJ¸4ÜVí*"4DT~ñ; å¤ÃEÊË6
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_6.cbor b/fuzzing/orphans/libcppbor/corpus/cose_6.cbor
new file mode 100644
index 0000000..64bbfdd
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_6.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_7.cbor b/fuzzing/orphans/libcppbor/corpus/cose_7.cbor
new file mode 100644
index 0000000..675bc47
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_7.cbor
@@ -0,0 +1,2 @@
+Ø`C¡
+¡Mõ/e¡Å;Ra§lXu5H¡L§²i$íòã±pßé1¶¸GC¡)¢3PaabbccddeeffgghhJour-secret@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_8.cbor b/fuzzing/orphans/libcppbor/corpus/cose_8.cbor
new file mode 100644
index 0000000..5f3b4be
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_8.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_9.cbor b/fuzzing/orphans/libcppbor/corpus/cose_9.cbor
new file mode 100644
index 0000000..17ae70e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_9.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_claims_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_claims_0.cbor
new file mode 100644
index 0000000..5d4c4c6
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_claims_0.cbor
@@ -0,0 +1 @@
+§ucoap://as.example.comeerikwxcoap://light.example.comV®°VÙðVÙðBq
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_cose_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_cose_0.cbor
new file mode 100644
index 0000000..e1d1b46
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_cose_0.cbor
@@ -0,0 +1,2 @@
+¤ P#LMM0QýÂì
+8QÕ³LSymmetric128
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_cose_1.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_cose_1.cbor
new file mode 100644
index 0000000..fba0863
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_cose_1.cbor
@@ -0,0 +1 @@
+¤ X @6Þ¯da2 ]«áü·¨j´5ñì-yVLSymmetric256
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_cose_2.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_cose_2.cbor
new file mode 100644
index 0000000..1aebdd0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_cose_2.cbor
@@ -0,0 +1 @@
+§#X lvZìSXñs=({Ü9M¤ZlgÈX¼ l"X `÷ñ§Ø§¿·¢Ýk'è»ÎùÓÑhÛ)6ç¹!X 3)ÌçAi'YöZ4óÎ/ý¥Z~Êií£Ô/ RAsymmetricECDSA256&
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_encrypted_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_encrypted_0.cbor
new file mode 100644
index 0000000..9787644
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_encrypted_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_maced_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_maced_0.cbor
new file mode 100644
index 0000000..9787644
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_maced_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_maced_1.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_maced_1.cbor
new file mode 100644
index 0000000..a6eeeb2
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_maced_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_nested_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_nested_0.cbor
new file mode 100644
index 0000000..9787644
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_nested_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_signed_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_signed_0.cbor
new file mode 100644
index 0000000..74e0ea7
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_signed_0.cbor
@@ -0,0 +1 @@
+ÒC¡&¡RAsymmetricECDSA256XP§ucoap://as.example.comeerikwxcoap://light.example.comV®°VÙðVÙðBqX@T'Áÿ(Ò?ºÑòL|jU^`o¢y¼=t8ºÊÊZÍÈÔÔùa1hBøYQìît:R¹¶62År 0
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_0.cbor b/fuzzing/orphans/libcppbor/corpus/float16_0.cbor
new file mode 100644
index 0000000..e43ae5a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_1.cbor b/fuzzing/orphans/libcppbor/corpus/float16_1.cbor
new file mode 100644
index 0000000..6935671
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_10.cbor b/fuzzing/orphans/libcppbor/corpus/float16_10.cbor
new file mode 100644
index 0000000..7c2eb64
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_10.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_2.cbor b/fuzzing/orphans/libcppbor/corpus/float16_2.cbor
new file mode 100644
index 0000000..ed788bb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_3.cbor b/fuzzing/orphans/libcppbor/corpus/float16_3.cbor
new file mode 100644
index 0000000..5ac3929
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_4.cbor b/fuzzing/orphans/libcppbor/corpus/float16_4.cbor
new file mode 100644
index 0000000..735f467
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_4.cbor
@@ -0,0 +1 @@
+ù{ÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_5.cbor b/fuzzing/orphans/libcppbor/corpus/float16_5.cbor
new file mode 100644
index 0000000..8e144ff
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_5.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_6.cbor b/fuzzing/orphans/libcppbor/corpus/float16_6.cbor
new file mode 100644
index 0000000..16b0d43
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_6.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_7.cbor b/fuzzing/orphans/libcppbor/corpus/float16_7.cbor
new file mode 100644
index 0000000..e5b8b4d
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_7.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_8.cbor b/fuzzing/orphans/libcppbor/corpus/float16_8.cbor
new file mode 100644
index 0000000..2b119eb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_8.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_9.cbor b/fuzzing/orphans/libcppbor/corpus/float16_9.cbor
new file mode 100644
index 0000000..d73f58e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_9.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_0.cbor b/fuzzing/orphans/libcppbor/corpus/float32_0.cbor
new file mode 100644
index 0000000..f36a086
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_1.cbor b/fuzzing/orphans/libcppbor/corpus/float32_1.cbor
new file mode 100644
index 0000000..16f3345
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_1.cbor
@@ -0,0 +1 @@
+úÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_2.cbor b/fuzzing/orphans/libcppbor/corpus/float32_2.cbor
new file mode 100644
index 0000000..82965f3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_3.cbor b/fuzzing/orphans/libcppbor/corpus/float32_3.cbor
new file mode 100644
index 0000000..2a9ccae
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_4.cbor b/fuzzing/orphans/libcppbor/corpus/float32_4.cbor
new file mode 100644
index 0000000..a9e0eeb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_0.cbor b/fuzzing/orphans/libcppbor/corpus/float64_0.cbor
new file mode 100644
index 0000000..fc9ea00
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_0.cbor
@@ -0,0 +1 @@
+û?ñ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_1.cbor b/fuzzing/orphans/libcppbor/corpus/float64_1.cbor
new file mode 100644
index 0000000..8e79bf5
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_2.cbor b/fuzzing/orphans/libcppbor/corpus/float64_2.cbor
new file mode 100644
index 0000000..815adc3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_2.cbor
@@ -0,0 +1 @@
+ûÀffffff
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_3.cbor b/fuzzing/orphans/libcppbor/corpus/float64_3.cbor
new file mode 100644
index 0000000..c90d682
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_4.cbor b/fuzzing/orphans/libcppbor/corpus/float64_4.cbor
new file mode 100644
index 0000000..802efe1
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_5.cbor b/fuzzing/orphans/libcppbor/corpus/float64_5.cbor
new file mode 100644
index 0000000..7a1f61c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_5.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/map_0.cbor b/fuzzing/orphans/libcppbor/corpus/map_0.cbor
new file mode 100644
index 0000000..eea1bf0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_0.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_1.cbor b/fuzzing/orphans/libcppbor/corpus/map_1.cbor
new file mode 100644
index 0000000..abc169a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_1.cbor
@@ -0,0 +1 @@
+¢
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_2.cbor b/fuzzing/orphans/libcppbor/corpus/map_2.cbor
new file mode 100644
index 0000000..81e3847
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_2.cbor
@@ -0,0 +1 @@
+¢aaab
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_3.cbor b/fuzzing/orphans/libcppbor/corpus/map_3.cbor
new file mode 100644
index 0000000..05bb07f
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_3.cbor
@@ -0,0 +1 @@
+¥aaaAabaBacaCadaDaeaE
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_4.cbor b/fuzzing/orphans/libcppbor/corpus/map_4.cbor
new file mode 100644
index 0000000..018602c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_4.cbor
@@ -0,0 +1 @@
+¿aaabÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_5.cbor b/fuzzing/orphans/libcppbor/corpus/map_5.cbor
new file mode 100644
index 0000000..c0f4fd5
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_5.cbor
@@ -0,0 +1 @@
+¿cFunõcAmt!ÿ
\ No newline at end of file
diff --git a/sanitizer-status/MODULE_LICENSE_APACHE2 b/fuzzing/orphans/libcppbor/corpus/negative_integer_0.cbor
similarity index 100%
rename from sanitizer-status/MODULE_LICENSE_APACHE2
rename to fuzzing/orphans/libcppbor/corpus/negative_integer_0.cbor
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_1.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_1.cbor
new file mode 100644
index 0000000..e8a0f87
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_1.cbor
@@ -0,0 +1 @@
+)
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_2.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_2.cbor
new file mode 100644
index 0000000..bfefdad
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_2.cbor
@@ -0,0 +1 @@
+8c
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_3.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_3.cbor
new file mode 100644
index 0000000..5de2555
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_3.cbor
@@ -0,0 +1 @@
+9ç
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_4.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_4.cbor
new file mode 100644
index 0000000..077457a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_4.cbor
@@ -0,0 +1 @@
+;ÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_0.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_0.cbor
new file mode 100644
index 0000000..f76dd23
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_1.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_1.cbor
new file mode 100644
index 0000000..6b2aaa7
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_1.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_10.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_10.cbor
new file mode 100644
index 0000000..fed1e13
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_10.cbor
@@ -0,0 +1 @@
+ÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_2.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_2.cbor
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_2.cbor
@@ -0,0 +1 @@
+
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_3.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_3.cbor
new file mode 100644
index 0000000..c96ab3c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_3.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_4.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_4.cbor
new file mode 100644
index 0000000..a1910b3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_4.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_5.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_5.cbor
new file mode 100644
index 0000000..d4e634a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_5.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_6.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_6.cbor
new file mode 100644
index 0000000..3b5c907
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_6.cbor
@@ -0,0 +1 @@
+d
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_7.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_7.cbor
new file mode 100644
index 0000000..fda74fd
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_7.cbor
@@ -0,0 +1 @@
+è
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_8.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_8.cbor
new file mode 100644
index 0000000..9162819
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_8.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_9.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_9.cbor
new file mode 100644
index 0000000..4cdcd7c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_9.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_0.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_0.cbor
new file mode 100644
index 0000000..3a6e607
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_0.cbor
@@ -0,0 +1 @@
+ô
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_1.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_1.cbor
new file mode 100644
index 0000000..bb7d13c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_1.cbor
@@ -0,0 +1 @@
+õ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_2.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_2.cbor
new file mode 100644
index 0000000..f7a8cad
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_2.cbor
@@ -0,0 +1 @@
+ö
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_3.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_3.cbor
new file mode 100644
index 0000000..04f7b5b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_3.cbor
@@ -0,0 +1 @@
+ð
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_5.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_5.cbor
new file mode 100644
index 0000000..a61a462
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_5.cbor
@@ -0,0 +1 @@
+øÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_6.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_6.cbor
new file mode 100644
index 0000000..009080e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_6.cbor
@@ -0,0 +1 @@
+÷
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/struct_0.cbor b/fuzzing/orphans/libcppbor/corpus/struct_0.cbor
new file mode 100644
index 0000000..5f34271
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/struct_0.cbor
@@ -0,0 +1,5 @@
+¨aTõbUiÿÿÿÿÿÿÿÿaI9çaFûÀffffffaBX
+
+aSx+The quick brown fox jumps over the lazy dogdSlci
+
+cMssacaCaeaEafaFagaGahaHanaNamaMaaaAabaBadaDaiaIajaJalaL
diff --git a/fuzzing/orphans/libcppbor/corpus/struct_keyasint_0.cbor b/fuzzing/orphans/libcppbor/corpus/struct_keyasint_0.cbor
new file mode 100644
index 0000000..4511f9e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/struct_keyasint_0.cbor
@@ -0,0 +1,5 @@
+¨õÿÿÿÿÿÿÿÿ9çûÀffffffX
+
+x+The quick brown fox jumps over the lazy dog
+
+adaDafaFagaGahaHamaManaNaaaAabaBacaCaeaEaiaIajaJalaL
diff --git a/fuzzing/orphans/libcppbor/corpus/struct_toarray_0.cbor b/fuzzing/orphans/libcppbor/corpus/struct_toarray_0.cbor
new file mode 100644
index 0000000..d8faa45
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/struct_toarray_0.cbor
@@ -0,0 +1,5 @@
+õÿÿÿÿÿÿÿÿ9çûÀffffffX
+
+x+The quick brown fox jumps over the lazy dog
+
+abaBacaCadaDaeaEafaFaiaIanaNaaaAagaGahaHajaJalaLamaM
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_0.cbor b/fuzzing/orphans/libcppbor/corpus/tag_0.cbor
new file mode 100644
index 0000000..d2fbff8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_0.cbor
@@ -0,0 +1 @@
+Àt2013-03-21T20:04:00Z
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_1.cbor b/fuzzing/orphans/libcppbor/corpus/tag_1.cbor
new file mode 100644
index 0000000..4ecf946
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_1.cbor
@@ -0,0 +1 @@
+ÁQKg°
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_2.cbor b/fuzzing/orphans/libcppbor/corpus/tag_2.cbor
new file mode 100644
index 0000000..00a3f0c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_3.cbor b/fuzzing/orphans/libcppbor/corpus/tag_3.cbor
new file mode 100644
index 0000000..b4818a3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_4.cbor b/fuzzing/orphans/libcppbor/corpus/tag_4.cbor
new file mode 100644
index 0000000..c5c79cf
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_5.cbor b/fuzzing/orphans/libcppbor/corpus/tag_5.cbor
new file mode 100644
index 0000000..7d0120d
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_5.cbor
@@ -0,0 +1 @@
+×D
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_6.cbor b/fuzzing/orphans/libcppbor/corpus/tag_6.cbor
new file mode 100644
index 0000000..2784fd8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_6.cbor
@@ -0,0 +1 @@
+ØEdIETF
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_7.cbor b/fuzzing/orphans/libcppbor/corpus/tag_7.cbor
new file mode 100644
index 0000000..b7d2601
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_7.cbor
@@ -0,0 +1 @@
+Ø vhttp://www.example.com
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_0.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_0.cbor
new file mode 100644
index 0000000..64845fb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_0.cbor
@@ -0,0 +1 @@
+`
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_1.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_1.cbor
new file mode 100644
index 0000000..7ec9a4b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_1.cbor
@@ -0,0 +1 @@
+aa
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_2.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_2.cbor
new file mode 100644
index 0000000..743669b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_2.cbor
@@ -0,0 +1 @@
+dIETF
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_3.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_3.cbor
new file mode 100644
index 0000000..cce6615
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_3.cbor
@@ -0,0 +1 @@
+b"\
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_4.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_4.cbor
new file mode 100644
index 0000000..9055a92
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_4.cbor
@@ -0,0 +1 @@
+bü
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_5.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_5.cbor
new file mode 100644
index 0000000..0868c9a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_5.cbor
@@ -0,0 +1 @@
+c水
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_6.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_6.cbor
new file mode 100644
index 0000000..8ea48a0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_6.cbor
@@ -0,0 +1 @@
+d𐅑
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_7.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_7.cbor
new file mode 100644
index 0000000..d0daf28
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_7.cbor
@@ -0,0 +1 @@
+estreadmingÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/cppbor_fuzzer.cpp b/fuzzing/orphans/libcppbor/cppbor_fuzzer.cpp
new file mode 100644
index 0000000..6ee80a6
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/cppbor_fuzzer.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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 <fuzzer/FuzzedDataProvider.h>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+void FuzzStringParsing(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ std::string contents = dataProvider.ConsumeRemainingBytesAsString();
+ cppbor::Tstr val(contents);
+ cppbor::parse(val.encode());
+}
+
+void FuzzVectorParsing(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ size_t keySize = dataProvider.remaining_bytes() / 4;
+ std::string key1 = dataProvider.ConsumeBytesAsString(keySize);
+ std::string key2 = dataProvider.ConsumeBytesAsString(keySize);
+ std::vector<uint8_t> contentsBytes = dataProvider.ConsumeRemainingBytes<uint8_t>();
+ cppbor::Map map;
+ map.add(key1, cppbor::Array().add(cppbor::Map().add(key2, contentsBytes)));
+ cppbor::parse(map.encode());
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzStringParsing(data, size);
+ FuzzVectorParsing(data, size);
+ return 0;
+}
diff --git a/fuzzing/orphans/libcppbor/cppbor_parse_fuzzer.cpp b/fuzzing/orphans/libcppbor/cppbor_parse_fuzzer.cpp
new file mode 100644
index 0000000..52ed8ad
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/cppbor_parse_fuzzer.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 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 <cppbor_parse.h>
+
+using namespace cppbor;
+
+class FuzzParseClient : public ParseClient {
+ public:
+ virtual ParseClient* item(std::unique_ptr<Item>&, const uint8_t*, const uint8_t*,
+ const uint8_t*) override {
+ return this;
+ }
+ virtual ParseClient* itemEnd(std::unique_ptr<Item>&, const uint8_t*, const uint8_t*,
+ const uint8_t*) override {
+ return this;
+ }
+ virtual void error(const uint8_t*, const std::string&) override {}
+};
+
+void FuzzParse(const uint8_t* data, size_t size) {
+ const uint8_t* cursor = data;
+ const uint8_t* end = data + size;
+ while (cursor < end) {
+ auto [item, newPos, errMsg] = parse(cursor, end);
+ if (!item || !errMsg.empty()) {
+ return;
+ }
+ cursor = newPos;
+ }
+}
+
+void FuzzParseWithViews(const uint8_t* data, size_t size) {
+ const uint8_t* cursor = data;
+ const uint8_t* end = data + size;
+ while (cursor < end) {
+ auto [item, newPos, errMsg] = parseWithViews(cursor, end);
+ if (!item || !errMsg.empty()) {
+ return;
+ }
+ cursor = newPos;
+ }
+}
+
+void FuzzParseWithClient(const uint8_t* data, size_t size) {
+ const uint8_t* end = data + size;
+ FuzzParseClient parseClient;
+ parse(data, end, &parseClient);
+}
+
+void FuzzParseWithClientAndViews(const uint8_t* data, size_t size) {
+ const uint8_t* end = data + size;
+ FuzzParseClient parseClient;
+ parseWithViews(data, end, &parseClient);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzParse(data, size);
+ FuzzParseWithViews(data, size);
+ FuzzParseWithClient(data, size);
+ FuzzParseWithClientAndViews(data, size);
+ return 0;
+}
diff --git a/fuzzing/orphans/libexif/Android.bp b/fuzzing/orphans/libexif/Android.bp
index e68788d..d7ee450 100644
--- a/fuzzing/orphans/libexif/Android.bp
+++ b/fuzzing/orphans/libexif/Android.bp
@@ -1,3 +1,7 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_fuzz {
name: "libexif_fuzzer",
srcs: [
@@ -7,4 +11,5 @@
"libexif",
],
host_supported: false,
+ corpus: ["corpus/*"],
}
diff --git a/fuzzing/orphans/libffi/Android.bp b/fuzzing/orphans/libffi/Android.bp
new file mode 100644
index 0000000..9e49f93
--- /dev/null
+++ b/fuzzing/orphans/libffi/Android.bp
@@ -0,0 +1,22 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+ name: "libffi_fuzz",
+ host_supported: true,
+ srcs: [
+ "fuzz_ffi.cc",
+ ],
+ include_dirs: [
+ "external/libffi",
+ ],
+ cflags: [
+ "-Wno-macro-redefined",
+ "-Wno-unused-parameter",
+ "-Wno-deprecated-declarations",
+ ],
+ static_libs: [
+ "libffi",
+ ],
+}
diff --git a/fuzzing/orphans/libffi/fuzz_ffi.cc b/fuzzing/orphans/libffi/fuzz_ffi.cc
new file mode 100644
index 0000000..525f58a
--- /dev/null
+++ b/fuzzing/orphans/libffi/fuzz_ffi.cc
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2020 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.
+ */
+
+// Don't lint the next line, as cpplint will suggest adding
+// /tools/security as an include_dir
+// NOLINTNEXTLINE
+#include "fuzz_ffi.h"
+
+#include <vector>
+#include "include/ffi_common.h"
+
+// Empty functions we can use for our function targets
+void fn(int num_args, ...) {}
+void closure_fn(ffi_cif* cif __UNUSED__,
+ void* resp, void** args, void* userdata) {}
+void raw_closure_fn(ffi_cif* cif __UNUSED__,
+ void* resp, ffi_raw* args, void* userdata) {}
+void java_raw_closure_fn(ffi_cif* cif __UNUSED__,
+ void* resp, ffi_java_raw* args, void* userdata) {}
+
+ffi_type* generateCustomType(FuzzedDataProvider* dataProvider) {
+ // Set our flag so we don't call a java-related function (triggers an abort)
+ args_contain_struct = true;
+
+ ffi_type* new_type = reinterpret_cast<ffi_type*>(malloc(sizeof(ffi_type)));
+ ffi_alloc_vector.push_back(new_type);
+
+ new_type->size = 0;
+ new_type->alignment = 0;
+ new_type->type = FFI_TYPE_STRUCT;
+
+ // Generate our subobjects
+ size_t num_elements = dataProvider->ConsumeIntegralInRange<size_t>(0,
+ MAX_NUM_ELEMENTS);
+ new_type->elements = reinterpret_cast<ffi_type**>(
+ malloc(sizeof(ffi_type*)*(num_elements+1)));
+
+ // Nested custom structs will cause an assert, so disable them
+ // TODO(michael.ensing@leviathansecurity.com):
+ // change the 'false' here to true once libffi supports nested structs.
+ // It'll just throw an assert currently.
+ for (size_t i=0; i < num_elements; i++) {
+ new_type->elements[i] = getRandomType(dataProvider, false);
+ }
+
+ // The final element must be a nullptr
+ new_type->elements[num_elements] = NULL;
+
+ // Get our size/alignment
+ ffi_get_struct_offsets(abi, new_type, NULL);
+
+ return new_type;
+}
+
+size_t getTotalSize(ffi_type* type) {
+ if (type == NULL) {
+ return 0;
+ }
+
+ // Start the total as the size of the object itself
+ size_t total_size = type->size > WORDSIZE_BYTES ?
+ type->size : WORDSIZE_BYTES;
+
+ // Recursively add the size of the subelements
+ if (type->elements != NULL) {
+ for (size_t i=0; type->elements[i] != NULL; i++) {
+ total_size += getTotalSize(type->elements[i]);
+ }
+ }
+
+ return total_size;
+}
+
+ffi_type* getRandomType(FuzzedDataProvider* dataProvider,
+ bool allowCustomTypes) {
+ // Which type? Let type==NUM_TYPES be our custom struct case
+ size_t type_index = dataProvider->ConsumeIntegralInRange<size_t>(0,
+ NUM_TYPES);
+ ffi_type* type;
+ if (type_index == NUM_TYPES) {
+ if (allowCustomTypes) {
+ type = generateCustomType(dataProvider);
+ } else {
+ return NULL;
+ }
+ } else {
+ type = ffi_types[type_index];
+ }
+
+ return type;
+}
+
+void* genArg(ffi_type* type, FuzzedDataProvider* dataProvider) {
+ // Allocate the space for our arg
+ // TODO(michael.ensing@leviathansecurity.com):
+ // Properly allocate the correct amount of aligned-space,
+ // don't just double (which should contain any alignment)
+ size_t type_size = getTotalSize(type)*2;
+
+ if (type_size == 0) {
+ return NULL;
+ }
+
+ void* ret = malloc(type_size);
+
+ std::vector<uint8_t> bytes = dataProvider->ConsumeBytes<uint8_t>(type_size);
+ memcpy(ret, bytes.data(), bytes.size());
+
+ return ret;
+}
+
+bool buildArgArrays(ffi_type* arg_types[], void* arg_array[], size_t num_args,
+ FuzzedDataProvider* dataProvider) {
+ // The first value in our array should be the number of arguments
+ arg_types[0] = &ffi_type_sint;
+ size_t* size_ptr = reinterpret_cast<size_t*>(malloc(sizeof(size_t)));
+ *size_ptr = num_args;
+ arg_array[0] = size_ptr;
+
+ // Grab our arguments
+ for (size_t i = 1; i <= num_args; i++) {
+ // Determine what type we're using
+ ffi_type* type = getRandomType(dataProvider, true);
+ if (type == NULL) {
+ return false;
+ }
+ arg_types[i] = type;
+
+ // Generate a value for it and add to our arguments array
+ arg_array[i] = genArg(type, dataProvider);
+ }
+
+ // Our arrays of pointers need to be nullptr-terminated
+ arg_types[num_args+1] = NULL;
+ arg_array[num_args+1] = NULL;
+
+ return true;
+}
+
+void runMainFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
+ FuzzedDataProvider* dataProvider) {
+ // Call function
+ ffi_call(cif, FFI_FN(fn), resp_buf, arg_array);
+
+ // Prep Closure
+ ffi_closure* pcl = NULL;
+ void* code;
+ ffi_status ret;
+
+ pcl = reinterpret_cast<ffi_closure*>(
+ ffi_closure_alloc(sizeof(ffi_closure), &code));
+ if (pcl == NULL) {
+ return;
+ }
+
+ size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
+ MAX_RESP_SIZE);
+ std::vector<uint8_t> data_vector =
+ dataProvider->ConsumeBytes<uint8_t>(buf_size);
+ ret = ffi_prep_closure_loc(
+ pcl,
+ cif,
+ closure_fn,
+ data_vector.data(),
+ code);
+ if (ret != FFI_OK) {
+ ffi_closure_free(pcl);
+ }
+}
+
+void runRawFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
+ FuzzedDataProvider* dataProvider) {
+ #if !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
+ // Allocate our ffi_raw and put our args there
+ size_t rsize = ffi_raw_size(cif);
+ ffi_raw* raw_args = reinterpret_cast<ffi_raw*>(malloc(rsize));
+ raw_alloc_vector.push_back(raw_args);
+ ffi_ptrarray_to_raw(cif, arg_array, raw_args);
+
+ // Call
+ ffi_raw_call(cif, FFI_FN(fn), resp_buf, raw_args);
+
+ // Prep Closure
+ #if FFI_CLOSURES
+ ffi_raw_closure* pcl = NULL;
+ void* code;
+ ffi_status ret;
+
+ pcl = static_cast<ffi_raw_closure*>(
+ ffi_closure_alloc(sizeof(ffi_raw_closure), &code));
+ if (pcl == NULL) {
+ return;
+ }
+ size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
+ MAX_RESP_SIZE);
+ std::vector<uint8_t> data_vector =
+ dataProvider->ConsumeBytes<uint8_t>(buf_size);
+ ret = ffi_prep_raw_closure_loc(
+ pcl,
+ cif,
+ raw_closure_fn,
+ data_vector.data(),
+ code);
+ if (ret != FFI_OK) {
+ ffi_closure_free(pcl);
+ }
+
+ #endif // FFI_CLOSURES
+ #endif // !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
+}
+
+void runJavaFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
+ FuzzedDataProvider* dataProvider) {
+ #if !defined(NO_JAVA_RAW_API)
+ #if !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
+
+ // Allocate our ffi_java_raw and put our args there
+ size_t rsize = ffi_java_raw_size(cif);
+ // NOTE: a buffer overread will occasionally happen if we don't
+ // increase rsize.
+ ffi_java_raw* raw_args = reinterpret_cast<ffi_raw*>(malloc(rsize*2));
+ raw_alloc_vector.push_back(raw_args);
+ ffi_ptrarray_to_raw(cif, arg_array, raw_args);
+
+ // Call
+ ffi_java_raw_call(cif, FFI_FN(fn), resp_buf, raw_args);
+
+ // Prep Closure
+ #if FFI_CLOSURES
+ ffi_java_raw_closure* pcl = NULL;
+ void* code;
+ ffi_status ret;
+
+ pcl = static_cast<ffi_java_raw_closure*>(
+ ffi_closure_alloc(sizeof(ffi_java_raw_closure), &code));
+ if (pcl == NULL) {
+ return;
+ }
+ size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
+ MAX_RESP_SIZE);
+ std::vector<uint8_t> data_vector =
+ dataProvider->ConsumeBytes<uint8_t>(buf_size);
+ ret = ffi_prep_java_raw_closure_loc(
+ pcl,
+ cif,
+ raw_closure_fn,
+ data_vector.data(),
+ code);
+ if (ret != FFI_OK) {
+ ffi_closure_free(pcl);
+ }
+
+ #endif // FFI_CLOSURES
+ #endif // !FFI_NATIVE_RAW_API
+ #endif // !NO_JAVA_RAW_API
+}
+
+void freeFFI(ffi_type* ffi_type) {
+ // Make sure it's one of our structs
+ if (ffi_type == NULL || ffi_type->type != FFI_TYPE_STRUCT) {
+ return;
+ }
+
+ if (ffi_type->elements != NULL) {
+ free(ffi_type->elements);
+ }
+
+ // Finally, free our object
+ free(ffi_type);
+}
+
+void freeAll(void* arg_array[], size_t num_args, void* resp_buf) {
+ // Free our custom struct objects
+ for (const auto& ffi : ffi_alloc_vector) {
+ freeFFI(ffi);
+ }
+ ffi_alloc_vector.clear();
+ for (const auto& raw : raw_alloc_vector) {
+ free(raw);
+ }
+ raw_alloc_vector.clear();
+
+ for (size_t i=0; i <= num_args; i++) {
+ free(arg_array[i]);
+ }
+
+ if (resp_buf) {
+ free(resp_buf);
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ // Init our wrapper
+ FuzzedDataProvider dataProvider(Data, Size);
+ ffi_cif cif;
+ ffi_status ret;
+ void* resp_buf = NULL;
+ args_contain_struct = false;
+ ffi_type* rtype;
+
+ // How many args are we sending?
+ size_t num_args = dataProvider.ConsumeIntegralInRange<size_t>(0,
+ MAX_NUM_ARGS);
+
+ // Build our array of args (+2 for leading arg_count and trailing nullptr)
+ ffi_type* arg_types[num_args+2];
+ void* arg_array[num_args+2];
+ bool success = buildArgArrays(arg_types, arg_array, num_args,
+ &dataProvider);
+ if (!success) {
+ goto free;
+ }
+
+ // Get return type
+ rtype = dataProvider.PickValueInArray<ffi_type*, NUM_TYPES>(ffi_types);
+
+ // Create a buffer for our return value
+ resp_buf = malloc(MAX_RESP_SIZE);
+ if (resp_buf == NULL) {
+ goto free;
+ }
+
+ // Set up our ABI
+ // NOTE: fuzzing abi triggers an abort on linux-x86_64,
+ // so only fuzz it on ARM
+ #if MAX_ABI > 0 && defined(ARM)
+ abi = static_cast<ffi_abi>(
+ dataProvider.ConsumeIntegralInRange<uint32_t>(0, MAX_ABI));
+ #endif
+ #if HAVE_LONG_DOUBLE_VARIANT
+ ffi_prep_types(abi);
+ #endif
+
+ // ============= Call Functions =============
+ ret = ffi_prep_cif_var(&cif, abi, 1, num_args, rtype,
+ arg_types);
+ if (ret != FFI_OK) {
+ goto free;
+ }
+
+ runMainFunctions(&cif, resp_buf, arg_array, &dataProvider);
+ runRawFunctions(&cif, resp_buf, arg_array, &dataProvider);
+ if (!args_contain_struct) {
+ runJavaFunctions(&cif, resp_buf, arg_array, &dataProvider);
+ }
+
+free:
+ freeAll(arg_array, num_args, resp_buf);
+ return 0;
+}
diff --git a/fuzzing/orphans/libffi/fuzz_ffi.h b/fuzzing/orphans/libffi/fuzz_ffi.h
new file mode 100644
index 0000000..db4a66f
--- /dev/null
+++ b/fuzzing/orphans/libffi/fuzz_ffi.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifndef FUZZING_ORPHANS_LIBFFI_FUZZ_FFI_H_
+#define FUZZING_ORPHANS_LIBFFI_FUZZ_FFI_H_
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <ffi.h>
+#include <cstdarg>
+#include <vector>
+
+#if defined(__GNUC__)
+#define __UNUSED__ __attribute__((__unused__))
+#endif
+
+#define MAX_NUM_ARGS 128
+#define MAX_NUM_ELEMENTS 16
+#define MAX_RESP_SIZE 4096
+#define WORDSIZE_BYTES (__WORDSIZE / 8)
+
+// TODO(michael.ensing@leviathansecurity.com):
+// Ideally, we should add/remove supported types based on
+// arch-specific #defines (listed in ffi_gen.h)
+#define NUM_TYPES 21
+ffi_type* ffi_types[] = {
+ &ffi_type_uchar,
+ &ffi_type_schar,
+ &ffi_type_ushort,
+ &ffi_type_sshort,
+ &ffi_type_uint,
+ &ffi_type_sint,
+ &ffi_type_ulong,
+ &ffi_type_slong,
+ &ffi_type_void,
+ &ffi_type_uint8,
+ &ffi_type_sint8,
+ &ffi_type_uint16,
+ &ffi_type_sint16,
+ &ffi_type_uint32,
+ &ffi_type_sint32,
+ &ffi_type_uint64,
+ &ffi_type_sint64,
+ &ffi_type_float,
+ &ffi_type_double,
+ &ffi_type_pointer,
+ &ffi_type_longdouble,
+ // The following types are not available on some architectures
+ // &ffi_type_complex_float,
+ // &ffi_type_complex_double,
+ // &ffi_type_complex_longdouble,
+ // // nullptrs are used to terminate the array. Handle them manually.
+ // nullptr
+};
+
+// Store vectors of allocated objects
+std::vector<ffi_type*> ffi_alloc_vector;
+std::vector<void*> raw_alloc_vector;
+
+
+// Keep a boolean to track if the args have a struct,
+// which will trigger an abort on java calls
+bool args_contain_struct = false;
+
+// Store the current ABI as a global
+ffi_abi abi = FFI_DEFAULT_ABI;
+
+// Define the number of possible ffi_abi values
+// NOTE: Only supported architectures are arm/arm64, x86_64
+// arm
+#if defined(ARM)
+#define MAX_ABI 4
+// x86_64
+#elif defined(X86_64) || (defined(__x86_64__) && defined(X86_DARWIN))
+#define MAX_ABI 7
+#else
+#define MAX_ABI 0 // If we hit this case, do NOT fuzz the abi value.
+#endif
+
+// Retrieve the total size (in bytes) of a ffi_type.
+// Useful for custom structs
+size_t getTotalSize(ffi_type*);
+
+// Retrieve a random type from the ffi_types array
+ffi_type* getRandomType(FuzzedDataProvider*, bool);
+
+// Generates a custom struct, in ffi_type format
+ffi_type* generateCustomType(FuzzedDataProvider*);
+
+// Copies buffer data into a buffer described by the provided ffi_type
+// (may be a struct or have subobjects)
+size_t copyArg(ffi_type*, void*, FuzzedDataProvider*);
+
+// Builds out the arrays of ffi_types and arguments to define a function's
+// parameters. Returns true on success, false on failure.
+bool buildArgArrays(ffi_type*[], void*[], size_t, FuzzedDataProvider*);
+
+// Allocates the necessary space for a new argument buffer for given ffi_type
+// After allocation, calls copyArg() to fill buffer with data
+void* genArg(ffi_type*, FuzzedDataProvider*);
+
+// Functions to perform our library calls
+void runMainFunctions(ffi_cif&, void*, void**, FuzzedDataProvider*);
+void runRawFunctions(ffi_cif&, void*, void**, FuzzedDataProvider*);
+void runJavaFunctions(ffi_cif&, void*, void**, FuzzedDataProvider*);
+
+// Free any custom struct ffi_type objects
+// Safe to call on default types.
+void freeFFI(ffi_type*);
+
+// Frees all elements that the fuzzer has allocated
+void freeAll();
+
+#endif // FUZZING_ORPHANS_LIBFFI_FUZZ_FFI_H_
diff --git a/fuzzing/orphans/libskia/Android.bp b/fuzzing/orphans/libskia/Android.bp
new file mode 100644
index 0000000..a1c353f
--- /dev/null
+++ b/fuzzing/orphans/libskia/Android.bp
@@ -0,0 +1,54 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+ name: "libskia_image_processor_fuzzer",
+
+ srcs: [
+ "libskia_image_processor_fuzzer.cpp",
+ ],
+
+ shared_libs: [
+ "libdng_sdk",
+ "libft2",
+ "libjpeg",
+ "liblog",
+ "libpiex",
+ "libpng",
+ ],
+ static_libs: [
+ "libskia",
+ "libarect",
+ "libsfntly",
+ "libwebp-decode",
+ "libwebp-encode",
+ ],
+
+ target: {
+ android: {
+ shared_libs: [
+ "libz",
+ "libexpat",
+ "libandroidicu",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libheif",
+ "libvulkan",
+ "libnativewindow",
+ ],
+ export_shared_lib_headers: [
+ "libvulkan",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libcutils",
+ ],
+ },
+ },
+
+ corpus: ["corpus/*"],
+ host_supported: true,
+}
diff --git a/fuzzing/orphans/libskia/corpus/test1.bmp b/fuzzing/orphans/libskia/corpus/test1.bmp
new file mode 100644
index 0000000..abe9c91
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test1.bmp
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test2.gif b/fuzzing/orphans/libskia/corpus/test2.gif
new file mode 100644
index 0000000..6da1431
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test2.gif
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test3.heic b/fuzzing/orphans/libskia/corpus/test3.heic
new file mode 100644
index 0000000..1f6c29d
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test3.heic
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test4.tif b/fuzzing/orphans/libskia/corpus/test4.tif
new file mode 100644
index 0000000..ca33b52
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test4.tif
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test5.jpg b/fuzzing/orphans/libskia/corpus/test5.jpg
new file mode 100644
index 0000000..cc116e3
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test5.jpg
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test6.png b/fuzzing/orphans/libskia/corpus/test6.png
new file mode 100644
index 0000000..eb5492a
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test6.png
Binary files differ
diff --git a/fuzzing/orphans/libskia/libskia_image_processor_fuzzer.cpp b/fuzzing/orphans/libskia/libskia_image_processor_fuzzer.cpp
new file mode 100644
index 0000000..6f3f2f2
--- /dev/null
+++ b/fuzzing/orphans/libskia/libskia_image_processor_fuzzer.cpp
@@ -0,0 +1,83 @@
+/////////////////////////////////////////////////////////////////////////
+//
+// Author: Mateusz Jurczyk (mjurczyk@google.com)
+//
+// Copyright 2020 Google LLC
+//
+// 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
+//
+// https://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 <cstdio>
+#include <string>
+
+#include "SkAndroidCodec.h"
+#include "SkBitmap.h"
+#include "SkCodec.h"
+#include "SkString.h"
+
+#include "fuzzer/FuzzedDataProvider.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+static int getAndroidPixels(std::string& contents, bool requestPremul) {
+ // Generate stream contents
+ std::unique_ptr<SkMemoryStream> stream = SkMemoryStream::MakeDirect(contents.data(), contents.size());
+ if (!stream) {
+ return 0;
+ }
+
+ std::unique_ptr<SkCodec> c = SkCodec::MakeFromStream(std::move(stream),
+ nullptr);
+ if (!c) {
+ return 0;
+ }
+
+ std::unique_ptr<SkAndroidCodec> codec;
+ codec = SkAndroidCodec::MakeFromCodec(std::move(c));
+ if (!codec) {
+ return 0;
+ }
+
+ SkImageInfo info = codec->getInfo();
+ const int width = info.width();
+ const int height = info.height();
+
+ SkColorType decodeColorType = kN32_SkColorType;
+ SkAlphaType alphaType =
+ codec->computeOutputAlphaType(requestPremul);
+ const SkImageInfo decodeInfo =
+ SkImageInfo::Make(width, height, decodeColorType, alphaType);
+
+ SkImageInfo bitmapInfo = decodeInfo;
+ SkBitmap decodingBitmap;
+ if (!decodingBitmap.tryAllocPixels(bitmapInfo)) {
+ return 0;
+ }
+
+ codec->getAndroidPixels(
+ decodeInfo, decodingBitmap.getPixels(), decodingBitmap.rowBytes());
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(char *data, size_t size) {
+ if (size == 0) {
+ return 0;
+ }
+
+ std::string sdata1(data, size);
+ getAndroidPixels(sdata1, true);
+ std::string sdata2(data, size);
+ getAndroidPixels(sdata2, false);
+ return 0;
+}
diff --git a/fuzzing/orphans/pppd/Android.bp b/fuzzing/orphans/pppd/Android.bp
new file mode 100644
index 0000000..e2b4dc0
--- /dev/null
+++ b/fuzzing/orphans/pppd/Android.bp
@@ -0,0 +1,35 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+ name: "eap_pppd_fuzz",
+
+ srcs: [
+ "eap_fuzz.proto",
+ "eap_fuzz.cc",
+ "eap_fuzz_Cproxy.c",
+ ],
+
+ static_libs: [
+ "libprotobuf-mutator",
+ "libpppd",
+ ],
+ shared_libs: [
+ "libprotobuf-cpp-full",
+ "libdl",
+ "liblog",
+ "libcutils",
+ "libcrypto",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+
+ ldflags: ["-rdynamic"],
+ required: [
+ "pppol2tp-android",
+ "pppopptp-android",
+ ],
+}
diff --git a/fuzzing/orphans/pppd/eap_fuzz.cc b/fuzzing/orphans/pppd/eap_fuzz.cc
new file mode 100644
index 0000000..5372e15
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz.cc
@@ -0,0 +1,215 @@
+#include <stdint.h>
+extern "C" {
+#include "eap_fuzz_Cproxy.h"
+}
+
+#include <src/libfuzzer/libfuzzer_macro.h>
+#include "eap_fuzz.pb.h"
+
+#define S_MALLOC(var, size) \
+do { \
+ if ((var = (uint8_t *)malloc(size)) == NULL) { \
+ return; \
+ } \
+} while(0)
+
+void write_header(uint8_t *packet, uint16_t data_size, uint8_t type)
+{
+ data_size += EAP_HEADERLEN;
+ //the packet type
+ *(packet)++ = type&0xff;
+ //id
+ *(packet)++ = 0x0;
+ //the length as big endian short
+ *(packet)++ = ((data_size >> 8)&0xff);
+ *(packet)++ = data_size&0xff;
+}
+
+DEFINE_BINARY_PROTO_FUZZER(const eap_fuzz::proto::PacketSet &packets){
+ init();
+
+ for(const eap_fuzz::proto::Packet& packet: packets.packets()){
+ uint8_t *fuzz_packet = NULL;
+ size_t packet_len = 0;
+ std::string data = "";
+ uint8_t packet_type = -1;
+ switch(packet.PacketType_case()){
+ case eap_fuzz::proto::Packet::kEapRequest: {
+ packet_type = EAP_REQUEST;
+ uint8_t eap_request_type = -1;
+ auto eap_request = packet.eap_request();
+ switch(eap_request.EapRequestType_case()){
+ case eap_fuzz::proto::EapRequest::kIdentity: {
+ eap_request_type = EAPT_IDENTITY;
+ data = eap_request.identity().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+ break;
+ }
+ case eap_fuzz::proto::EapRequest::kNotification: {
+ eap_request_type = EAPT_NOTIFICATION;
+ data = eap_request.notification().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+ break;
+ }
+ case eap_fuzz::proto::EapRequest::kMd5Chap: {
+ eap_request_type = EAPT_MD5CHAP;
+ data = eap_request.md5chap().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+ break;
+ }
+ case eap_fuzz::proto::EapRequest::kSrp: {
+ auto request_srp = eap_request.srp();
+ eap_request_type = EAPT_SRP;
+ uint8_t srp_type = -1;
+ switch(request_srp.EspMessage_case()){
+ case eap_fuzz::proto::EaptRequestSRP::kSrpChallenge:{
+ data = request_srp.srp_challenge().data();
+ srp_type = EAPSRP_CHALLENGE;
+ break;
+ }
+ case eap_fuzz::proto::EaptRequestSRP::kSrpValidator:{
+ data = request_srp.srp_validator().data();
+ srp_type = EAPSRP_SVALIDATOR;
+ break;
+ }
+ case eap_fuzz::proto::EaptRequestSRP::kSrpKey:{
+ data = request_srp.srp_key().data();
+ srp_type = EAPSRP_SKEY;
+ break;
+ }
+ case eap_fuzz::proto::EaptRequestSRP::kSrpLwreChallenge:{
+ data = request_srp.srp_lwre_challenge().data();
+ srp_type = EAPSRP_LWRECHALLENGE;
+ break;
+ }
+ case eap_fuzz::proto::EaptRequestSRP::ESPMESSAGE_NOT_SET:{
+ return;
+ }
+
+ }
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+2);
+ *(fuzz_packet+EAP_HEADERLEN+1) = srp_type;
+ packet_len++;
+ break;
+ }
+ case eap_fuzz::proto::EapRequest::EAPREQUESTTYPE_NOT_SET: {
+ return;
+ }
+ }
+ *(fuzz_packet+EAP_HEADERLEN) = eap_request_type;
+ ++packet_len;
+ break;
+ }
+
+ case eap_fuzz::proto::Packet::kEapResponse: {
+ packet_type = EAP_RESPONSE;
+ auto eap_response = packet.eap_response();
+ uint8_t eap_response_type = -1;
+ switch(eap_response.EapResponseType_case()){
+ case eap_fuzz::proto::EapResponse::kIdentity: {
+ eap_response_type = EAPT_IDENTITY;
+ data = eap_response.identity().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+ break;
+ }
+ case eap_fuzz::proto::EapResponse::kNotification: {
+ eap_response_type = EAPT_NOTIFICATION;
+ data = eap_response.notification().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+ break;
+ }
+ case eap_fuzz::proto::EapResponse::kMd5Chap: {
+ eap_response_type = EAPT_MD5CHAP;
+ data = eap_response.md5chap().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+ break;
+ }
+ case eap_fuzz::proto::EapResponse::kNak: {
+ eap_response_type = EAPT_NAK;
+ auto response_nak = eap_response.nak();
+ uint8_t nak_type = -1;
+ switch(response_nak.EaptResponseNAKType_case()){
+ case eap_fuzz::proto::EaptResponseNAK::kSrp:{
+ nak_type = EAPT_SRP;
+ break;
+
+ }
+ case eap_fuzz::proto::EaptResponseNAK::kMd5Chap:{
+ nak_type = EAPT_MD5CHAP;
+ break;
+
+ }
+ case eap_fuzz::proto::EaptResponseNAK::EAPTRESPONSENAKTYPE_NOT_SET:{
+ return;
+ }
+ }
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+2);
+ *(fuzz_packet+EAP_HEADERLEN+1) = nak_type;
+ packet_len++;
+ break;
+ }
+ case eap_fuzz::proto::EapResponse::kSrp: {
+ auto response_srp = eap_response.srp();
+ eap_response_type = EAPT_SRP;
+ uint8_t srp_type = -1;
+ switch(response_srp.EspMessage_case()){
+ case eap_fuzz::proto::EaptResponseSRP::kSrpChallenge:{
+ data = response_srp.srp_challenge().data();
+ srp_type = EAPSRP_LWRECHALLENGE;
+ break;
+ }
+ case eap_fuzz::proto::EaptResponseSRP::kSrpCvalidator:{
+ data = response_srp.srp_cvalidator().data();
+ srp_type = EAPSRP_CVALIDATOR;
+ break;
+ }
+ case eap_fuzz::proto::EaptResponseSRP::kSrpCkey:{
+ data = response_srp.srp_ckey().data();
+ srp_type = EAPSRP_CKEY;
+ break;
+ }
+ case eap_fuzz::proto::EaptResponseSRP::kSrpAck:{
+ data = response_srp.srp_ack().data();
+ srp_type = EAPSRP_ACK;
+ break;
+ }
+ case eap_fuzz::proto::EaptResponseSRP::ESPMESSAGE_NOT_SET:{
+ return;
+ }
+
+ }
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+2);
+ *(fuzz_packet+EAP_HEADERLEN+1) = srp_type;
+ packet_len++;
+ break;
+ }
+ case eap_fuzz::proto::EapResponse::EAPRESPONSETYPE_NOT_SET: {
+ return;
+ }
+ }
+ *(fuzz_packet+EAP_HEADERLEN) = eap_response_type;
+ ++packet_len;
+ break;
+ }
+ case eap_fuzz::proto::Packet::kEapSuccess: {
+ packet_type = EAP_SUCCESS;
+ data = packet.eap_success().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN);
+ break;
+ }
+ case eap_fuzz::proto::Packet::kEapFailure: {
+ packet_type = EAP_FAILURE;
+ data = packet.eap_failure().data();
+ S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN);
+ break;
+ }
+ case eap_fuzz::proto::Packet::PACKETTYPE_NOT_SET: {
+ return;
+ }
+ }
+ write_header(fuzz_packet, data.size()+packet_len, packet_type);
+ memcpy(fuzz_packet+EAP_HEADERLEN+packet_len, data.data(), data.size());
+ proxy_packet(fuzz_packet, data.size()+EAP_HEADERLEN+packet_len);
+ free(fuzz_packet);
+ }
+}
diff --git a/fuzzing/orphans/pppd/eap_fuzz.proto b/fuzzing/orphans/pppd/eap_fuzz.proto
new file mode 100644
index 0000000..6d41214
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz.proto
@@ -0,0 +1,133 @@
+syntax = "proto2";
+package eap_fuzz.proto;
+
+message PacketSet{
+ repeated Packet packets = 1;
+}
+
+message Packet{
+ oneof PacketType {
+ EapRequest eap_request = 1;
+ EapResponse eap_response = 2;
+ EapSuccess eap_success = 3;
+ EapFailure eap_failure = 4;
+ }
+}
+
+message EapRequest{
+ oneof EapRequestType{
+ EaptRequestIdentity identity = 1;
+ EsptRequestNotification notification = 2;
+ EaptRequestMD5Chap md5chap = 3;
+ EaptRequestSRP srp = 4;
+ }
+
+}
+
+message EaptRequestIdentity{
+ required bytes data = 1;
+}
+
+message EsptRequestNotification{
+ required bytes data = 1;
+}
+
+message EaptRequestMD5Chap{
+ required bytes data = 2;
+}
+message EaptRequestSRP{
+ oneof EspMessage {
+ EapRequestSRPChallenge srp_challenge = 1;
+ EapRequestSRPKey srp_key = 2;
+ EapRequestSRPValidator srp_validator = 3;
+ EapRequestSRPLWREChallenge srp_lwre_challenge = 4;
+ }
+}
+
+message EapRequestSRPChallenge{
+ required bytes data = 1;
+}
+
+message EapRequestSRPKey{
+ required bytes data = 1;
+}
+
+message EapRequestSRPValidator {
+ required bytes data = 1;
+}
+
+message EapRequestSRPLWREChallenge{
+ required bytes data = 1;
+}
+
+message EapResponse{
+ oneof EapResponseType{
+ EaptResponseIdentity identity = 1;
+ EsptResponseNotification notification = 2;
+ EaptResponseNAK nak = 3;
+ EaptResponseMD5Chap md5chap = 4;
+ EaptResponseSRP srp = 5;
+ }
+}
+
+message EaptResponseIdentity{
+ required bytes data = 1;
+}
+
+message EsptResponseNotification{
+ required bytes data = 1;
+}
+
+message EaptResponseNAK{
+ oneof EaptResponseNAKType{
+ EaptResponseNAKSRP srp = 1;
+ EaptResponseNAKMD5Chap md5_chap = 2;
+ }
+}
+
+
+message EaptResponseNAKSRP{
+ required bytes data = 1;
+}
+
+message EaptResponseNAKMD5Chap {
+ required bytes data = 1;
+}
+
+message EaptResponseMD5Chap {
+ required bytes data = 1;
+}
+
+message EaptResponseSRP{
+ oneof EspMessage {
+ EapResponseSRPCKey srp_ckey = 1;
+ EapResponseSRPCValidator srp_cvalidator = 2;
+ EapResponseSRPACK srp_ack = 3;
+ EapResponseSRPLWEChallenge srp_challenge = 4;
+ }
+}
+
+message EapResponseSRPCKey {
+ required bytes data = 1;
+}
+
+message EapResponseSRPCValidator{
+ required bytes data = 1;
+}
+
+message EapResponseSRPACK{
+ required bytes data = 1;
+}
+
+message EapResponseSRPLWEChallenge{
+ required bytes data = 1;
+}
+
+message EapSuccess{
+ required bytes data = 1;
+}
+
+message EapFailure{
+ required bytes data = 1;
+}
+
diff --git a/fuzzing/orphans/pppd/eap_fuzz_Cproxy.c b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.c
new file mode 100644
index 0000000..e2b7d98
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "pppd.h"
+#include "pathnames.h"
+#include "md5.h"
+#include "eap.h"
+#include "magic.h"
+
+void init()
+{
+ eap_protent.init(0);
+}
+
+
+void proxy_packet(uint8_t *data, int len)
+{
+ eap_protent.input(0, data, len);
+}
diff --git a/fuzzing/orphans/pppd/eap_fuzz_Cproxy.h b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.h
new file mode 100644
index 0000000..6846f5e
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.h
@@ -0,0 +1,56 @@
+//from pppd.h, can't include it directly in the fuzzer because C -> C++ issues
+#define EAP_HEADERLEN 4
+
+/* EAP message codes. */
+#define EAP_REQUEST 1
+#define EAP_RESPONSE 2
+#define EAP_SUCCESS 3
+#define EAP_FAILURE 4
+
+/* EAP types */
+#define EAPT_IDENTITY 1
+#define EAPT_NOTIFICATION 2
+#define EAPT_NAK 3 /* (response only) */
+#define EAPT_MD5CHAP 4
+#define EAPT_OTP 5 /* One-Time Password; RFC 1938 */
+#define EAPT_TOKEN 6 /* Generic Token Card */
+/* 7 and 8 are unassigned. */
+#define EAPT_RSA 9 /* RSA Public Key Authentication */
+#define EAPT_DSS 10 /* DSS Unilateral */
+#define EAPT_KEA 11 /* KEA */
+#define EAPT_KEA_VALIDATE 12 /* KEA-VALIDATE */
+#define EAPT_TLS 13 /* EAP-TLS */
+#define EAPT_DEFENDER 14 /* Defender Token (AXENT) */
+#define EAPT_W2K 15 /* Windows 2000 EAP */
+#define EAPT_ARCOT 16 /* Arcot Systems */
+#define EAPT_CISCOWIRELESS 17 /* Cisco Wireless */
+#define EAPT_NOKIACARD 18 /* Nokia IP smart card */
+#define EAPT_SRP 19 /* Secure Remote Password */
+/* 20 is deprecated */
+
+/* EAP SRP-SHA1 Subtypes */
+#define EAPSRP_CHALLENGE 1 /* Request 1 - Challenge */
+#define EAPSRP_CKEY 1 /* Response 1 - Client Key */
+#define EAPSRP_SKEY 2 /* Request 2 - Server Key */
+#define EAPSRP_CVALIDATOR 2 /* Response 2 - Client Validator */
+#define EAPSRP_SVALIDATOR 3 /* Request 3 - Server Validator */
+#define EAPSRP_ACK 3 /* Response 3 - final ack */
+#define EAPSRP_LWRECHALLENGE 4 /* Req/resp 4 - Lightweight rechal */
+
+#define SRPVAL_EBIT 0x00000001 /* Use shared key for ECP */
+
+#define SRP_PSEUDO_ID "pseudo_"
+#define SRP_PSEUDO_LEN 7
+
+#define MD5_SIGNATURE_SIZE 16
+#define MIN_CHALLENGE_LENGTH 16
+#define MAX_CHALLENGE_LENGTH 24
+
+void init();
+void proxy_packet(uint8_t *data, int len);
+
+//override output so we don't write to a broken fd
+void output (int unit, unsigned char *p, int len)
+{
+
+}
diff --git a/fuzzing/orphans/widevine/trusty/Android.bp b/fuzzing/orphans/widevine/trusty/Android.bp
new file mode 100644
index 0000000..c1f1165
--- /dev/null
+++ b/fuzzing/orphans/widevine/trusty/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+ name: "trusty_widevine_tipc_fuzzer",
+ defaults: ["trusty_fuzzer_defaults"],
+ srcs: [":trusty_tipc_fuzzer"],
+ cflags: [
+ "-DTRUSTY_APP_PORT=\"com.android.trusty.widevine\"",
+ "-DTRUSTY_APP_UUID=\"08d3ed40-bde2-448c-a91d-75f1989c57ef\"",
+ "-DTRUSTY_APP_FILENAME=\"widevine.syms.elf\"",
+ ],
+}
+
+// Fuzzer for ODK_DispatchMessage() that's inside Trusty.
+cc_fuzz {
+ name: "trusty_widevine_dispatch_fuzzer",
+ defaults: ["trusty_fuzzer_defaults"],
+ srcs: ["dispatch_fuzzer.cpp"],
+ shared_libs: [
+ "libdmabufheap",
+ ],
+}
diff --git a/fuzzing/orphans/widevine/trusty/OWNERS b/fuzzing/orphans/widevine/trusty/OWNERS
new file mode 100644
index 0000000..5f8199f
--- /dev/null
+++ b/fuzzing/orphans/widevine/trusty/OWNERS
@@ -0,0 +1 @@
+trong@google.com
diff --git a/fuzzing/orphans/widevine/trusty/dispatch_fuzzer.cpp b/fuzzing/orphans/widevine/trusty/dispatch_fuzzer.cpp
new file mode 100644
index 0000000..072b661
--- /dev/null
+++ b/fuzzing/orphans/widevine/trusty/dispatch_fuzzer.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2021 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 <BufferAllocator/BufferAllocator.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <trusty/coverage/coverage.h>
+#include <trusty/fuzz/counters.h>
+#include <trusty/fuzz/utils.h>
+#include <trusty/tipc.h>
+#include <unistd.h>
+#include <iostream>
+
+using android::trusty::coverage::CoverageRecord;
+using android::trusty::fuzz::ExtraCounters;
+using android::trusty::fuzz::TrustyApp;
+
+#define countof(arr) (sizeof(arr) / sizeof(arr[0]))
+
+#define TIPC_DEV "/dev/trusty-ipc-dev0"
+#define WIDEVINE_PORT "com.android.trusty.widevine"
+#define WIDEVINE_MODULE_NAME "widevine.syms.elf"
+
+#define WV_IPC_BUFFER_SIZE (32)
+#define WV_MESSAGE_BUFFER_SIZE (32 * 1024)
+#define WV_SHARED_BUFFER_SIZE (16 * 1024 * 1024)
+
+struct wv_ipc_header {
+ uint16_t tag;
+};
+
+enum wv_tag : uint16_t {
+ WV_TAG_ACK = 0u,
+ WV_TAG_BIND = 1u,
+ WV_TAG_WIDEVINE = 2u,
+};
+
+struct bind_message {
+ uint32_t protocol_version;
+ uint32_t message_buffer_size;
+ uint32_t shared_buffer_size;
+};
+
+struct widevine_message {
+ uint32_t message_size;
+};
+
+/* Widevine TA's UUID is 08d3ed40-bde2-448c-a91d-75f1989c57ef */
+static struct uuid widevine_uuid = {
+ 0x08d3ed40,
+ 0xbde2,
+ 0x448c,
+ {0xa9, 0x1d, 0x75, 0xf1, 0x98, 0x9c, 0x57, 0xef},
+};
+
+static android::base::unique_fd wv_msg_buf_fd;
+static void* wv_msg_buf_base;
+
+static android::base::unique_fd wv_shared_buf_fd;
+static void* wv_shared_buf_base;
+
+static TrustyApp trusty_app(TIPC_DEV, WIDEVINE_PORT);
+static CoverageRecord record(TIPC_DEV, &widevine_uuid, WIDEVINE_MODULE_NAME);
+
+extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
+ auto ret = trusty_app.Connect();
+ if (!ret.ok()) {
+ std::cerr << ret.error() << std::endl;
+ exit(-1);
+ }
+
+ ret = record.Open();
+ if (!ret.ok()) {
+ std::cerr << ret.error() << std::endl;
+ exit(-1);
+ }
+
+ BufferAllocator allocator;
+
+ wv_msg_buf_fd.reset(allocator.Alloc(kDmabufSystemHeapName, WV_MESSAGE_BUFFER_SIZE));
+ if (wv_msg_buf_fd < 0) {
+ std::cerr << "Failed to allocate message buffer." << std::endl;
+ exit(-1);
+ }
+
+ wv_msg_buf_base = mmap(0, WV_MESSAGE_BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+ wv_msg_buf_fd, 0);
+ if (wv_msg_buf_base == MAP_FAILED) {
+ std::cerr << "Failed to mmap() message buffer." << std::endl;
+ exit(-1);
+ }
+
+ wv_shared_buf_fd.reset(allocator.Alloc(kDmabufSystemHeapName, WV_SHARED_BUFFER_SIZE));
+ if (wv_shared_buf_fd < 0) {
+ std::cerr << "Failed to allocate shared buffer." << std::endl;
+ exit(-1);
+ }
+
+ wv_shared_buf_base = mmap(0, WV_SHARED_BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+ wv_shared_buf_fd, 0);
+ if (wv_shared_buf_base == MAP_FAILED) {
+ std::cerr << "Failed to mmap() shared buffer." << std::endl;
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static bool Bind() {
+ wv_ipc_header hdr = {
+ .tag = WV_TAG_BIND,
+ };
+ bind_message args = {
+ .protocol_version = 0,
+ .message_buffer_size = WV_MESSAGE_BUFFER_SIZE,
+ .shared_buffer_size = WV_SHARED_BUFFER_SIZE,
+ };
+ iovec iov[] = {
+ {
+ .iov_base = &hdr,
+ .iov_len = sizeof(hdr),
+ },
+ {
+ .iov_base = &args,
+ .iov_len = sizeof(args),
+ },
+ };
+ trusty_shm handles[] = {
+ {
+ .fd = wv_msg_buf_fd,
+ .transfer = TRUSTY_SHARE,
+ },
+ {
+ .fd = wv_shared_buf_fd,
+ .transfer = TRUSTY_SHARE,
+ },
+ };
+ int chan = *trusty_app.GetRawFd();
+
+ int rc = tipc_send(chan, iov, countof(iov), handles, countof(handles));
+ if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
+ return false;
+ }
+
+ rc = read(chan, &hdr, sizeof(hdr));
+ if (rc != static_cast<int>(sizeof(hdr))) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool Msg(const uint8_t* data, size_t size) {
+ size = std::min((size_t)WV_MESSAGE_BUFFER_SIZE, size);
+ wv_ipc_header hdr = {
+ .tag = WV_TAG_WIDEVINE,
+ };
+ widevine_message args = {
+ .message_size = static_cast<uint32_t>(size),
+ };
+ iovec iov[] = {
+ {
+ .iov_base = &hdr,
+ .iov_len = sizeof(hdr),
+ },
+ {
+ .iov_base = &args,
+ .iov_len = sizeof(args),
+ },
+ };
+ int chan = *trusty_app.GetRawFd();
+
+ memset(wv_msg_buf_base, 0, WV_MESSAGE_BUFFER_SIZE);
+ memcpy(wv_msg_buf_base, data, size);
+
+ int rc = tipc_send(chan, iov, countof(iov), NULL, 0);
+ if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
+ return false;
+ }
+
+ rc = readv(chan, iov, countof(iov));
+ if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
+ return false;
+ }
+
+ return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ ExtraCounters counters(&record);
+ counters.Reset();
+
+ bool success = Bind();
+ if (!success) {
+ android::trusty::fuzz::Abort();
+ }
+
+ success = Msg(data, size);
+ if (!success) {
+ android::trusty::fuzz::Abort();
+ }
+
+ // Reconnect to ensure that the service is still up.
+ trusty_app.Disconnect();
+ auto ret = trusty_app.Connect();
+ if (!ret.ok()) {
+ std::cerr << ret.error() << std::endl;
+ android::trusty::fuzz::Abort();
+ }
+
+ return 0;
+}
diff --git a/fuzzing/system_fuzzers/libcrypto_utils/Android.bp b/fuzzing/system_fuzzers/libcrypto_utils/Android.bp
index 4214b35..c9f4820 100644
--- a/fuzzing/system_fuzzers/libcrypto_utils/Android.bp
+++ b/fuzzing/system_fuzzers/libcrypto_utils/Android.bp
@@ -1,3 +1,7 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_fuzz {
host_supported: true,
name : "libcrypto_utils_fuzzer",
@@ -14,4 +18,3 @@
"libcrypto",
],
}
-
diff --git a/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp b/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp
index b14086d..cc40a3b 100644
--- a/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp
+++ b/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp
@@ -21,6 +21,7 @@
#include <openssl/obj_mac.h>
#include <openssl/rsa.h>
#include <cstdio>
+#include <limits>
#define ANDROID_PUBKEY_MODULUS_SIZE_WORDS (ANDROID_PUBKEY_MODULUS_SIZE / 4)
@@ -35,7 +36,7 @@
uint32_t modulus_size_words = ANDROID_PUBKEY_MODULUS_SIZE_WORDS;
memcpy(buffer, &modulus_size_words, sizeof(uint32_t));
- uint32_t n0inv = fdp.ConsumeIntegralInRange<uint32_t>(0,2^32);
+ uint32_t n0inv = fdp.ConsumeIntegralInRange<uint32_t>(0,std::numeric_limits<uint32_t>::max());
memcpy(buffer+sizeof(uint32_t), &n0inv, sizeof(uint32_t));
std::string s = fdp.ConsumeBytesAsString(ANDROID_PUBKEY_MODULUS_SIZE);
diff --git a/fuzzing/system_fuzzers/libwatchdog_perf_service/Android.bp b/fuzzing/system_fuzzers/libwatchdog_perf_service/Android.bp
new file mode 100644
index 0000000..1193d18
--- /dev/null
+++ b/fuzzing/system_fuzzers/libwatchdog_perf_service/Android.bp
@@ -0,0 +1,27 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+ name : "libwatchdog_perf_service_fuzzer",
+ srcs: [
+ "libwatchdog_perf_service_fuzzer.cpp",
+ ],
+ defaults: [
+ "carwatchdogd_defaults",
+ "libwatchdog_perf_service_defaults",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter"
+ ],
+ static_libs: [
+ "libgtest",
+ "libwatchdog_perf_service",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+}
diff --git a/fuzzing/system_fuzzers/libwatchdog_perf_service/libwatchdog_perf_service_fuzzer.cpp b/fuzzing/system_fuzzers/libwatchdog_perf_service/libwatchdog_perf_service_fuzzer.cpp
new file mode 100644
index 0000000..4de3b0e
--- /dev/null
+++ b/fuzzing/system_fuzzers/libwatchdog_perf_service/libwatchdog_perf_service_fuzzer.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 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 "IoPerfCollection.h"
+#include "UidIoStats.h"
+
+#include <android-base/file.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <iostream>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::base::WriteStringToFile;
+
+struct statsInfo {
+ std::string instr[13];
+ int len[13];
+};
+
+statsInfo info = {{"cpu", "procs_running", "procs_blocked", "cpu0", "cpu1", "cpu2", "cpu3", "intr",
+ "ctxt", "btime", "process", "procs_sleeping", "softirq"},
+ {10, 1, 1, 10, 10, 10, 10, 31, 1, 1, 1, 1, 11}};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ std::string uidIoStatsSnapshot;
+ std::string procStatsSnapshot;
+
+ // Prepare for UidIOStats data
+ int count = 0;
+ while (fdp.remaining_bytes() > (size / 2)) {
+ uint64_t val = fdp.ConsumeIntegral<uint64_t>();
+ uidIoStatsSnapshot += (((count % 11) == 0 ? "" : " ") + std::to_string(val));
+ if (count > 0 && count % 11 == 10) {
+ uidIoStatsSnapshot += "\n";
+ }
+ count++;
+ }
+
+ // Prepare for ProcStats data
+ while (fdp.remaining_bytes() > 5) {
+ uint32_t choose = fdp.ConsumeIntegralInRange<uint32_t>(0, 3);
+ uint32_t idx = choose;
+ switch (choose) {
+ case 0:
+ case 1:
+ case 2:
+ break;
+ case 3:
+ idx = fdp.ConsumeIntegralInRange<uint32_t>(3, 12);
+ break;
+ default:
+ break;
+ }
+ procStatsSnapshot += info.instr[idx];
+ for (int i = 0; i < info.len[idx]; i++) {
+ uint64_t val = fdp.ConsumeIntegral<uint64_t>();
+ procStatsSnapshot += " " + std::to_string(val);
+ }
+ procStatsSnapshot += "\n";
+ }
+
+ if (uidIoStatsSnapshot.size() > 0 && procStatsSnapshot.size() > 0) {
+ // Test UidIoStats
+ TemporaryFile tf1;
+ WriteStringToFile(uidIoStatsSnapshot, tf1.path);
+ UidIoStats uidIoStats(tf1.path);
+ assert(uidIoStats.enabled() == true);
+ uidIoStats.collect();
+ // Test ProcStats
+ TemporaryFile tf2;
+ WriteStringToFile(procStatsSnapshot, tf2.path);
+ ProcStat procStat(tf2.path);
+ assert(procStat.enabled() == true);
+ procStat.collect();
+ }
+ return 0;
+}
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
diff --git a/fuzzing/vrp_fuzzers/OWNERS b/fuzzing/vrp_fuzzers/OWNERS
deleted file mode 100644
index 241b65a..0000000
--- a/fuzzing/vrp_fuzzers/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-hamzeh@google.com
-ispo@google.com
-kalder@google.com
-mspector@google.com
-semsmith@google.com
diff --git a/gdb/gdb_json_printer/README.md b/gdb/gdb_json_printer/README.md
new file mode 100644
index 0000000..8e4636f
--- /dev/null
+++ b/gdb/gdb_json_printer/README.md
@@ -0,0 +1,77 @@
+# gdb-json-pretty-printer
+This is a printer that prints variables in json format.
+## Install in GDB
+Copy the content in gdbinit into your ~/.gdbinit, replace the path <path_to_gdb_json_printer> by the actual path of gdb_json_printer directory.
+## Run tests
+First, in the gdb_json_printer directory, compile each example program with O0 optimization
+```
+g++ test_examples/basic_types.cpp -O0 -g -o test_examples/basic_types
+g++ test_examples/objects1.cpp -O0 -g -o test_examples/objects1
+g++ test_examples/objects2.cpp -O0 -g -o test_examples/objects2
+g++ test_examples/objects.cpp -O0 -g -o test_examples/objects
+g++ test_examples/array.cpp -O0 -g -o test_examples/array
+g++ test_examples/reference.cpp -O0 -g -o test_examples/reference
+```
+second, run gdb in the gdb_json_printer directory:
+```
+gdb
+```
+finally, source the test script:
+```
+source test/gdb_json_printer_test.py
+```
+## printing format
+```
+Pointer := {
+ type: 'pointer',
+ ctype: ctype for pointer,
+ address: Address,
+ reference: Struct
+}
+
+Struct := {
+ type: 'struct',
+ ctype: ctype for struct,
+ address: Address,
+ fields: StructField[]
+}
+
+StructField := {
+ field: name of field,
+ field_type: 'base_class' or 'argument'
+ value: Value
+}
+
+Int := {
+ type: 'int',
+ ctype: ctype for int,
+ address: Address,
+ value: number
+}
+
+Float := {
+ type: 'float',
+ ctype: 'float' or 'double',
+ address: Address,
+ value: number
+}
+
+Enum := {
+ type: 'enum',
+ ctype: ctype for enum,
+ address: Address,
+ value: number
+}
+
+Visit variable := {
+ type: 'visited',
+ ctype: ctype for struct,
+ address: Address,
+}
+
+```
+
+## problem to solve
+* support for print parent/child class members.
+* the printer treats all arrays as pointers now. We expected it to have ability to extract array/buffer length.
+* the printer prints smart pointers into a super complex json block. Maybe we need some specific printer for these common objects.
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/gdb_json_printer/printers.py b/gdb/gdb_json_printer/gdb_json_printer/printers.py
new file mode 100644
index 0000000..167f503
--- /dev/null
+++ b/gdb/gdb_json_printer/gdb_json_printer/printers.py
@@ -0,0 +1,404 @@
+# Copyright 2020 - 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.
+
+import gdb
+import gdb.printing
+import re
+from abc import ABC, abstractmethod
+import json
+
+# our code now only support Python3. In python2 we need to use intptr=long. Use this typedef
+# for easier support of Python2 later.
+intptr = int
+
+
+def check_optimized_out(to_json):
+ """ A decorator for to_json method of JsonPrinters. Check if the value in the printer
+ is already optimized out.
+ If the value is already optimized out, return {'type': 'optimized_out'}.
+
+ Args:
+ to_json: A to_json method of a JsonPrinter.
+
+ Returns:
+ decorated to_json method
+ """
+
+ def decorator(self, *args, **kwargs):
+ if self.value is None or self.value.is_optimized_out:
+ return {'type': 'optimized_out'}
+
+ return to_json(self, *args, **kwargs)
+ return decorator
+
+
+def check_visited(to_json):
+ """ A decorator for to_json method of JsonPrinters. Check if the value in the printer
+ has appeared in visited_addresses_and_types.
+ If the value has appeared in visited_addresses_and_types, return {'type': 'visited',
+ 'ctype': str(self.value.type), 'address': self.address}
+
+ Args:
+ to_json: A to_json method of a JsonPrinter.
+
+ Returns:
+ decorated to_json method
+ """
+
+ def decorator(self):
+ addresstype = self.get_address_type()
+ if addresstype != None and addresstype in self.visited_addresses_and_types:
+ return {
+ 'type': 'visited',
+ 'ctype': str(self.value.type),
+ 'address': self.address
+ }
+ self.visited_addresses_and_types.add(self.get_address_type())
+ return to_json(self)
+ return decorator
+
+
+class JsonPrinter(ABC):
+ """Base class for all json printers.
+
+ Attributes:
+ value:
+ The value to print, note that the lifetime of printer is limited to single print command.
+ visited_addresses_and_types:
+ A set of all `address`_`type` string that already visited during printing.
+ If the address and type is in the set and the value is a struct or pointer,
+ the printer will mark 'type' as visited and no longer expand the value. Can be None.
+ """
+
+ def __init__(self, value, visited_addresses_and_types=None):
+ """ Constructor. A JsonPrinter will be created for each time a variable is printed.
+
+ Args:
+ value:
+ A gdb.Value object, the value to print.
+ visited_addresses_and_types:
+ A set of all `address`_`type` string that already visited during printing.
+ If the address and type is in the set and the value is a struct or pointer,
+ the printer will mark 'type' as visited and no longer expand the value. Can be None.
+ """
+ self.value = value
+ self.visited_addresses_and_types = visited_addresses_and_types
+ if self.visited_addresses_and_types == None:
+ self.visited_addresses_and_types = set()
+
+ # value may not have address attribute if it's in register
+ if hasattr(self.value, 'address') and self.value.address is not None:
+ self.address = hex(intptr(self.value.address))
+ else:
+ self.address = None
+
+ def to_string(self):
+ """ Gdb Python interface to print a gdb.Value.
+
+ Returns:
+ A string representing the json format of a gdb.Value.
+ """
+ return json.dumps(self.to_json(), indent=4)
+
+ @abstractmethod
+ def to_json(self):
+ """ The method to be implemented. Convert a gdb.Value object into a Python json object.
+
+ Returns:
+ A Python json object.
+ """
+ pass
+
+ # we use address and type to identify a printed value and avoid circular references
+ def get_address_type(self):
+ address_str = self.address if self.address is not None else ""
+ return address_str + "_" + str(self.value.type.strip_typedefs())
+
+
+class BasicTypePrinter(JsonPrinter):
+ """ Printer for basic types, now supports Enum, Int, Float, and Void.
+
+ All integer variables in C++ will be considered as Int, e.g. char, short, long. Similarly,
+ float and double are all considered as Float. For enum variables, they are actually int in
+ C++, gdb knows they are enum variables, but can only print them as integer.
+ """
+
+ """
+ BasicTypePrinter uses this dict to print basic_types.
+ """
+ basic_type_json_info = {
+ gdb.TYPE_CODE_ENUM: {'type': 'enum', 'value_func': lambda value: str(int(value))},
+ gdb.TYPE_CODE_INT: {'type': 'int', 'value_func': lambda value: str(int(value))},
+ gdb.TYPE_CODE_FLT: {'type': 'float', 'value_func': lambda value: str(float(value))},
+ gdb.TYPE_CODE_VOID: {'type': 'void', 'value_func': lambda value: None},
+ }
+
+ @check_optimized_out
+ @check_visited
+ def to_json(self):
+ """ Output format is:
+ {
+ 'type': 'int'/'float'/'enum'/'void',
+ 'ctype': string format type in C++,
+ 'address': string format address,
+ 'value': string format value
+ }.
+ """
+ type_code = self.value.type.strip_typedefs().code
+ json_type = BasicTypePrinter.basic_type_json_info[type_code]["type"]
+ value_func = BasicTypePrinter.basic_type_json_info[type_code]["value_func"]
+ value_json = {
+ 'type': json_type,
+ 'ctype': str(self.value.type),
+ 'address': self.address,
+ 'value': value_func(self.value)
+ }
+ return value_json
+
+
+class ObjectPrinter(JsonPrinter):
+ """ A Printer for objects in C++.
+
+ The current version won't extract the dynamic/actual type of objects, and the member variable
+ of a parent/child class won't be printed. We expect to support this function later.
+ """
+
+ @check_visited
+ def to_json_without_expanding_base_class(self):
+ """ A helper function for the to_json method.
+
+ It tries to extract all member variables of an object without casting it into base classes.
+ """
+ value_json = {
+ 'type': 'struct',
+ 'ctype': str(self.value.type),
+ 'address': self.address,
+ 'fields': []
+ }
+
+ for field in self.value.type.fields():
+ if not field.is_base_class:
+ field_json = {
+ 'field': field.name,
+ 'value': None
+ }
+
+ field_printer = general_lookup_function(
+ self.value[field.name], self.visited_addresses_and_types)
+ try:
+ field_json['value'] = field_printer.to_json()
+ except:
+ field_json['value'] = "extract failed"
+
+ value_json['fields'].append(field_json)
+
+ return value_json
+
+ @check_optimized_out
+ def to_json(self, cast_to_dynamic_type=True):
+ """Output format:
+ {
+ 'type': 'struct',
+ 'ctype': string format type in C++,
+ 'address': string format address,
+ 'base_classes': [] # a list of value casted into each base class
+ 'fields': [] # a list of struct fields
+ }.
+ For each field in fields, its format is:
+ {
+ 'field': string format of field name,
+ 'field_type': 'base_class'/'member', if it is a base class. the value will be the
+ object which is casted into that base_class. Otherwise, the value is the json of
+ the member variable.
+ 'value': json of the field
+ }.
+ """
+ if cast_to_dynamic_type and \
+ self.value.type.strip_typedefs() != self.value.dynamic_type.strip_typedefs():
+ self.value = self.value.cast(self.value.dynamic_type)
+
+ # address/type pair is set to visited after casted to dynamic type to avoid base class
+ # being filtered by the visited check
+ value_json = self.to_json_without_expanding_base_class()
+
+ # if the type is visited, it's not necessary to explore its ancestors.
+ if value_json["type"] != "visited":
+ base_classes_list = []
+ for field in self.value.type.fields():
+ if field.is_base_class:
+ field_json = {
+ 'base_class': field.name,
+ 'value': None
+ }
+
+ base_class_printer = ObjectPrinter(
+ self.value.cast(field.type),
+ self.visited_addresses_and_types)
+ field_json["value"] = base_class_printer.to_json(
+ cast_to_dynamic_type=False)
+ base_classes_list.append(field_json)
+ value_json['base_classes'] = base_classes_list
+
+ return value_json
+
+
+class RefAndPtrPrinter(JsonPrinter):
+ """ Printer for reference and raw pointer in C++.
+ """
+
+ def __init__(self, value, visited_addresses_and_types=None):
+ super().__init__(value, visited_addresses_and_types)
+ self.void_ptr_re = re.compile(r"^.*void\s?\*$")
+
+ @check_optimized_out
+ @check_visited
+ def to_json(self):
+ """Output format:
+ {
+ 'type': 'pointer'/"reference,
+ 'ctype': string format type in C++,
+ 'address': string format address,
+ 'reference': Json for a C++ object
+ }.
+ If the pointer is a void* pointer, reference would be "cannot extract void ptr",
+ because gdb cannot extract content from a void* pointer. If the pointer is nullptr,
+ reference would be "nullptr".
+ """
+ value_type = 'pointer' if self.value.type.code == gdb.TYPE_CODE_PTR else 'reference'
+ value_json = {
+ 'type': value_type,
+ 'ctype': str(self.value.type),
+ 'address': self.address,
+ 'reference': None
+ }
+
+ # handle void pointer, dereference a void pointer will cause exception
+ if self.void_ptr_re.match(str(self.value.type.strip_typedefs())) is not None:
+ value_json['reference'] = "cannot extract void ptr"
+ return value_json
+
+ # handle nullptr
+ if value_type == 'pointer' and int(self.value) == 0:
+ value_json['reference'] = "nullptr"
+ return value_json
+
+ deref_value = self.value.referenced_value()
+ deref_value_printer = general_lookup_function(
+ deref_value, self.visited_addresses_and_types)
+ value_json['reference'] = deref_value_printer.to_json()
+ return value_json
+
+
+class ExtractFailedPrinter(JsonPrinter):
+ """ Printer for the case that cannot be extracted by current printer.
+ """
+
+ def to_json(self):
+ """ output format: {'type': 'extract failed'}
+ """
+ return {'type': 'extract failed'}
+
+
+class OptimizedOutPrinter(JsonPrinter):
+ """ Printer for the case that a variable is already optimized out.
+ """
+
+ def to_json(self):
+ """ Output format: {'type': 'optimized out'}.
+ """
+ return {'type': 'optimized out'}
+
+
+class StackArrayPrinter(JsonPrinter):
+ """ Printer for the arrays in C++.
+
+ Note that this printer works only for C++ arrays(with type= T[]). It cannot
+ print out buffers on heap.
+ Output format:
+ {
+ 'type': 'array',
+ 'element_type': string format type of array elements in C++,
+ 'values': A list of Value json indiciating each element in array
+ }.
+ """
+ @check_optimized_out
+ @check_visited
+ def to_json(self):
+ total_size = self.value.type.sizeof
+ element_size = self.value.type.target().sizeof
+ element_count = total_size // element_size
+ stack_array_json = {
+ 'type': 'array',
+ 'element_type': str(self.value.type.target()),
+ 'values': []
+ }
+ for idx in range(element_count):
+ element_json = general_lookup_function(
+ self.value[idx], self.visited_addresses_and_types).to_json()
+ stack_array_json['values'].append(element_json)
+ return stack_array_json
+
+
+""" The table indiciating which printer should be called given a gdb value.
+"""
+gdb_type_printer_map = {
+ gdb.TYPE_CODE_PTR: RefAndPtrPrinter,
+ gdb.TYPE_CODE_ARRAY: StackArrayPrinter,
+ gdb.TYPE_CODE_STRUCT: ObjectPrinter,
+ gdb.TYPE_CODE_UNION: ObjectPrinter,
+ gdb.TYPE_CODE_ENUM: BasicTypePrinter,
+ gdb.TYPE_CODE_FLAGS: None,
+ gdb.TYPE_CODE_FUNC: None,
+ gdb.TYPE_CODE_INT: BasicTypePrinter,
+ gdb.TYPE_CODE_FLT: BasicTypePrinter,
+ gdb.TYPE_CODE_VOID: BasicTypePrinter,
+ gdb.TYPE_CODE_SET: None, # not exist in C++
+ gdb.TYPE_CODE_RANGE: None, # not exist in C++?
+ # not exist in C++, in C++, string is not a built-in type
+ gdb.TYPE_CODE_STRING: None,
+ gdb.TYPE_CODE_BITSTRING: None, # deprecated
+ gdb.TYPE_CODE_ERROR: None,
+ gdb.TYPE_CODE_METHOD: None,
+ gdb.TYPE_CODE_METHODPTR: None,
+ gdb.TYPE_CODE_MEMBERPTR: None,
+ gdb.TYPE_CODE_REF: RefAndPtrPrinter,
+ gdb.TYPE_CODE_RVALUE_REF: None,
+ gdb.TYPE_CODE_CHAR: None, # char is an integer in C++
+ gdb.TYPE_CODE_BOOL: None, # bool is actually char in C++
+ gdb.TYPE_CODE_COMPLEX: None, # not exist in C++
+ gdb.TYPE_CODE_TYPEDEF: None,
+ gdb.TYPE_CODE_NAMESPACE: None,
+ gdb.TYPE_CODE_DECFLOAT: None, # not exist in C++
+ gdb.TYPE_CODE_INTERNAL_FUNCTION: None
+}
+
+
+def general_lookup_function(value, visited_addresses_and_types=None):
+ """ The actual printer installed, it will select JsonPrinter based on the gdb value given.
+ """
+ if value.is_optimized_out:
+ return OptimizedOutPrinter(value)
+ type_code = value.type.strip_typedefs().code
+ if type_code not in gdb_type_printer_map or gdb_type_printer_map[type_code] is None:
+ return ExtractFailedPrinter(value)
+
+ # TODO: add regex match and specific printer for some type here? such as shared_ptr
+
+ return gdb_type_printer_map[type_code](value, visited_addresses_and_types)
+
+
+def register_printers():
+ """ Call this function in your ~/.gdbinit to register the printer into gdb.
+ """
+ gdb.pretty_printers.append(general_lookup_function)
diff --git a/gdb/gdb_json_printer/gdbinit b/gdb/gdb_json_printer/gdbinit
new file mode 100644
index 0000000..1410988
--- /dev/null
+++ b/gdb/gdb_json_printer/gdbinit
@@ -0,0 +1,7 @@
+set auto-load python-scripts off
+python
+import sys
+sys.path.insert(0, '<path_to_gdb_json_printer>')
+from gdb_json_printer.printers import register_printers
+register_printers()
+end
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_a.json b/gdb/gdb_json_printer/test/array_42_a.json
new file mode 100644
index 0000000..7518900
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_a.json
@@ -0,0 +1,36 @@
+{
+ "type": "array",
+ "element_type": "int16_t",
+ "values": [
+ {
+ "type": "int",
+ "ctype": "int16_t",
+ "address": "0x7fffffffd766",
+ "value": "1"
+ },
+ {
+ "type": "int",
+ "ctype": "int16_t",
+ "address": "0x7fffffffd768",
+ "value": "2"
+ },
+ {
+ "type": "int",
+ "ctype": "int16_t",
+ "address": "0x7fffffffd76a",
+ "value": "3"
+ },
+ {
+ "type": "int",
+ "ctype": "int16_t",
+ "address": "0x7fffffffd76c",
+ "value": "4"
+ },
+ {
+ "type": "int",
+ "ctype": "int16_t",
+ "address": "0x7fffffffd76e",
+ "value": "5"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_b.json b/gdb/gdb_json_printer/test/array_42_b.json
new file mode 100644
index 0000000..8edf0b4
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_b.json
@@ -0,0 +1,11 @@
+{
+ "type": "pointer",
+ "ctype": "int16_t *",
+ "address": "0x7fffffffd778",
+ "reference": {
+ "type": "int",
+ "ctype": "int16_t",
+ "address": "0x7fffffffd76a",
+ "value": "3"
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_bar.json b/gdb/gdb_json_printer/test/array_42_bar.json
new file mode 100644
index 0000000..ed2f5be
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_bar.json
@@ -0,0 +1,57 @@
+{
+ "type": "array",
+ "element_type": "Bar",
+ "values": [
+ {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd72a",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd72a",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ },
+ {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd72c",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd72c",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ },
+ {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd72e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd72e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_foo.json b/gdb/gdb_json_printer/test/array_42_foo.json
new file mode 100644
index 0000000..fafd644
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_foo.json
@@ -0,0 +1,132 @@
+{
+ "type": "array",
+ "element_type": "Foo",
+ "values": [
+ {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd730",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd730",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd738",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd72a",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd72a",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ },
+ {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd740",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd740",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd748",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd72c",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd72c",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ },
+ {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd750",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd750",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd758",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd72e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd72e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/gdb_json_printer_test.py b/gdb/gdb_json_printer/test/gdb_json_printer_test.py
new file mode 100644
index 0000000..dd6b40e
--- /dev/null
+++ b/gdb/gdb_json_printer/test/gdb_json_printer_test.py
@@ -0,0 +1,236 @@
+# Copyright 2020 - 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.
+
+import unittest
+import gdb
+import json
+
+
+def remove_gdb_output_prefix(str):
+ """ gdb output contains a "$%d =" prefix, the function remove the prefix
+ """
+ idx = str.find("=")
+ return str[idx + 1:]
+
+
+def check_type_and_ctype(input_json, input_type, ctype):
+ assert(input_json["type"] == input_type)
+ assert(input_json["ctype"] == ctype)
+
+
+def check_basic_value(input_json, input_type, ctype, value):
+ check_type_and_ctype(input_json, input_type, ctype)
+ assert(input_json["value"] == value)
+
+
+def gdb_extract_variable_to_json(variable_name):
+ """ extract a variable from gdb
+
+ Args:
+ variable_name:
+ a string, the name of the variable to extract
+ Returns:
+ A json Object in Python
+ """
+ variable = gdb.execute("p {}".format(variable_name), to_string=True)
+ variable = remove_gdb_output_prefix(variable)
+ variable_json = json.loads(variable)
+ return variable_json
+
+
+def json_equal_except_address(testcase, json0, json1):
+ """ check if all content of two json are same except the address fields
+
+ The function will check the two json objects recursively to set address fields to None,
+ then convert two json objects into strings with sorted keys, and check if the two strings
+ are same.
+ """
+ def replace_address_by_None(input_json):
+ if isinstance(input_json, dict):
+ for (k, v) in input_json.items():
+ if k == "address":
+ input_json[k] = None
+ else:
+ replace_address_by_None(v)
+ elif isinstance(input_json, list):
+ for item in input_json:
+ replace_address_by_None(item)
+
+ replace_address_by_None(json0)
+ replace_address_by_None(json1)
+ json0 = json.dumps(json0, sort_keys=True)
+ json1 = json.dumps(json1, sort_keys=True)
+ testcase.assertEqual(json0, json1)
+
+
+def test_json_variable(testcase, testname, line, variable_name_list):
+ for variable_name in variable_name_list:
+ variable_json = gdb_extract_variable_to_json(variable_name)
+ with open("test/{}_{}_{}.json".format(testname, str(line), variable_name), "r") as f:
+ expect_variable = json.load(f)
+ json_equal_except_address(testcase, variable_json, expect_variable)
+
+
+class TestGdbJsonPrinter(unittest.TestCase):
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.maxDiff = None
+
+ def test_basic_types(self):
+ gdb.execute("file test_examples/basic_types")
+ gdb.execute("b 42")
+ gdb.execute("r")
+
+ variable_json = gdb_extract_variable_to_json("a")
+ check_basic_value(variable_json, "int", "uint8_t", "1")
+
+ variable_json = gdb_extract_variable_to_json("a")
+ check_basic_value(variable_json, "int", "uint8_t", "1")
+
+ variable_json = gdb_extract_variable_to_json("b")
+ check_basic_value(variable_json, "int", "int8_t", "-2")
+
+ variable_json = gdb_extract_variable_to_json("c")
+ check_basic_value(variable_json, "int", "uint16_t", "3")
+
+ variable_json = gdb_extract_variable_to_json("d")
+ check_basic_value(variable_json, "int", "int16_t", "-4")
+
+ variable_json = gdb_extract_variable_to_json("e")
+ check_basic_value(variable_json, "int", "uint32_t", "5")
+
+ variable_json = gdb_extract_variable_to_json("f")
+ check_basic_value(variable_json, "int", "int32_t", "-6")
+
+ variable_json = gdb_extract_variable_to_json("g")
+ check_basic_value(variable_json, "int", "uint64_t", "7")
+
+ variable_json = gdb_extract_variable_to_json("h")
+ check_basic_value(variable_json, "int", "int64_t", "-8")
+
+ variable_json = gdb_extract_variable_to_json("i")
+ check_basic_value(variable_json, "float", "float", "9.0")
+
+ variable_json = gdb_extract_variable_to_json("j")
+ check_basic_value(variable_json, "float", "double", "-10.0")
+
+ variable_json = gdb_extract_variable_to_json("k")
+ check_type_and_ctype(variable_json, "pointer", "const char *")
+ check_basic_value(
+ variable_json["reference"], "int", "const char", "72")
+
+ variable_json = gdb_extract_variable_to_json("l")
+ check_type_and_ctype(variable_json, "pointer", "void *")
+ assert(variable_json["reference"] == "cannot extract void ptr")
+
+ variable_json = gdb_extract_variable_to_json("m")
+ check_type_and_ctype(variable_json, "pointer", "char *")
+ assert(variable_json["reference"] == "nullptr")
+
+ variable_json = gdb_extract_variable_to_json("o")
+ check_basic_value(variable_json, "enum", "Animal", "0")
+
+ gdb.execute("b 61")
+ gdb.execute("c")
+
+ variable_json = gdb_extract_variable_to_json("a")
+ check_basic_value(variable_json, "int", "const uint8_t", "1")
+
+ variable_json = gdb_extract_variable_to_json("a")
+ check_basic_value(variable_json, "int", "const uint8_t", "1")
+
+ variable_json = gdb_extract_variable_to_json("b")
+ check_basic_value(variable_json, "int", "const int8_t", "-2")
+
+ variable_json = gdb_extract_variable_to_json("c")
+ check_basic_value(variable_json, "int", "const uint16_t", "3")
+
+ variable_json = gdb_extract_variable_to_json("d")
+ check_basic_value(variable_json, "int", "const int16_t", "-4")
+
+ variable_json = gdb_extract_variable_to_json("e")
+ check_basic_value(variable_json, "int", "const uint32_t", "5")
+
+ variable_json = gdb_extract_variable_to_json("f")
+ check_basic_value(variable_json, "int", "const int32_t", "-6")
+
+ variable_json = gdb_extract_variable_to_json("g")
+ check_basic_value(variable_json, "int", "const uint64_t", "7")
+
+ variable_json = gdb_extract_variable_to_json("h")
+ check_basic_value(variable_json, "int", "const int64_t", "-8")
+
+ variable_json = gdb_extract_variable_to_json("i")
+ check_basic_value(variable_json, "float", "const float", "9.0")
+
+ variable_json = gdb_extract_variable_to_json("j")
+ check_basic_value(variable_json, "float", "const double", "-10.0")
+
+ variable_json = gdb_extract_variable_to_json("k")
+ check_type_and_ctype(variable_json, "pointer", "const char *")
+ check_basic_value(
+ variable_json["reference"], "int", "const char", "72")
+
+ variable_json = gdb_extract_variable_to_json("l")
+ check_type_and_ctype(variable_json, "pointer", "const void *")
+ assert(variable_json["reference"] == "cannot extract void ptr")
+
+ variable_json = gdb_extract_variable_to_json("m")
+ check_type_and_ctype(variable_json, "pointer", "const char *")
+ assert(variable_json["reference"] == "nullptr")
+
+ variable_json = gdb_extract_variable_to_json("o")
+ check_basic_value(variable_json, "enum", "const Animal", "1")
+
+ def test_objects(self):
+ gdb.execute("file test_examples/objects")
+ gdb.execute("b 37")
+ gdb.execute("r")
+ test_json_variable(self, "objects", 37, ["bar", "foo"])
+
+ def test_objects1(self):
+ gdb.execute("file test_examples/objects1")
+ gdb.execute("b 41")
+ gdb.execute("r")
+ test_json_variable(self, "objects1", 41, ["bar", "foo"])
+
+ def test_objects2(self):
+ gdb.execute("file test_examples/objects2")
+ gdb.execute("b 85")
+ gdb.execute("r")
+ test_json_variable(
+ self,
+ "objects2",
+ 85,
+ ["a", "b", "c", "d", "e", "f", "w", "x", "y", "z"])
+
+ def test_array(self):
+ gdb.execute("file test_examples/array")
+ gdb.execute("b 42")
+ gdb.execute("r")
+ test_json_variable(self, "array", 42, ["a", "b", "bar", "foo"])
+
+ def test_reference(self):
+ gdb.execute("file test_examples/reference")
+ gdb.execute("b 41")
+ gdb.execute("r")
+ test_json_variable(
+ self,
+ "reference",
+ 41,
+ ["bar", "foo", "bar_ref", "foo_ref", "bar_ptr", "foo_ptr"])
+
+
+unittest.main()
diff --git a/gdb/gdb_json_printer/test/objects1_41_bar.json b/gdb/gdb_json_printer/test/objects1_41_bar.json
new file mode 100644
index 0000000..2f0cdac
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects1_41_bar.json
@@ -0,0 +1,60 @@
+{
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd760",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x55555556aed0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556aed0",
+ "value": "2"
+ }
+ },
+ {
+ "field": "foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x55555556aed8",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556aeb0",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556aeb0",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x55555556aeb8",
+ "reference": {
+ "type": "visited",
+ "ctype": "Bar",
+ "address": "0x55555556aed0"
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects1_41_foo.json b/gdb/gdb_json_printer/test/objects1_41_foo.json
new file mode 100644
index 0000000..6ce8164
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects1_41_foo.json
@@ -0,0 +1,60 @@
+{
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x7fffffffd768",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556aeb0",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556aeb0",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x55555556aeb8",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x55555556aed0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556aed0",
+ "value": "2"
+ }
+ },
+ {
+ "field": "foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x55555556aed8",
+ "reference": {
+ "type": "visited",
+ "ctype": "Foo",
+ "address": "0x55555556aeb0"
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_a.json b/gdb/gdb_json_printer/test/objects2_85_a.json
new file mode 100644
index 0000000..f6ae441
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_a.json
@@ -0,0 +1,22 @@
+{
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd748",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x55555556af29",
+ "fields": [
+ {
+ "field": "e",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556af29",
+ "value": "5"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_b.json b/gdb/gdb_json_printer/test/objects2_85_b.json
new file mode 100644
index 0000000..2a78825
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_b.json
@@ -0,0 +1,63 @@
+{
+ "type": "struct",
+ "ctype": "Foo2",
+ "address": "0x7fffffffd710",
+ "fields": [
+ {
+ "field": "c",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x7fffffffd71c",
+ "value": "4"
+ }
+ },
+ {
+ "field": "cc",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x7fffffffd720",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd710",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x7fffffffd710",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c70",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd718",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_c.json b/gdb/gdb_json_printer/test/objects2_85_c.json
new file mode 100644
index 0000000..41fed32
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_c.json
@@ -0,0 +1,146 @@
+{
+ "type": "reference",
+ "ctype": "Foo &",
+ "address": "0x55555556aef0",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo3",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "d",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af14",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo1",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo1",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556aefa",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556aef0",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c40",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556aef8",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ },
+ {
+ "base_class": "Foo2",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo2",
+ "address": "0x55555556af00",
+ "fields": [
+ {
+ "field": "c",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af0c",
+ "value": "3"
+ }
+ },
+ {
+ "field": "cc",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af10",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556af00",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af00",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c58",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556af08",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_d.json b/gdb/gdb_json_printer/test/objects2_85_d.json
new file mode 100644
index 0000000..53210de
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_d.json
@@ -0,0 +1,54 @@
+{
+ "type": "struct",
+ "ctype": "Foo1",
+ "address": "0x7fffffffd700",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd70a",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd700",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x7fffffffd700",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c88",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd708",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_e.json b/gdb/gdb_json_printer/test/objects2_85_e.json
new file mode 100644
index 0000000..2617f5a
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_e.json
@@ -0,0 +1,150 @@
+{
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x7fffffffd738",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo6",
+ "address": "0x55555556af68",
+ "fields": [
+ {
+ "field": "d",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af60",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo4",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo4",
+ "address": "0x55555556af40",
+ "fields": [
+ {
+ "field": "_vptr.Foo4",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af40",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557b30",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556af48",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556af68",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af68",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557b70",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556af70",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ },
+ {
+ "base_class": "Foo5",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo5",
+ "address": "0x55555556af50",
+ "fields": [
+ {
+ "field": "_vptr.Foo5",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af50",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557b50",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "c",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af58",
+ "value": "3"
+ }
+ },
+ {
+ "field": "cc",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af5c",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "visited",
+ "ctype": "Foo",
+ "address": "0x55555556af68"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_f.json b/gdb/gdb_json_printer/test/objects2_85_f.json
new file mode 100644
index 0000000..8ef76cd
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_f.json
@@ -0,0 +1,150 @@
+{
+ "type": "pointer",
+ "ctype": "Foo4 *",
+ "address": "0x7fffffffd730",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo6",
+ "address": "0x55555556af40",
+ "fields": [
+ {
+ "field": "d",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af60",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo4",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo4",
+ "address": "0x55555556af40",
+ "fields": [
+ {
+ "field": "_vptr.Foo4",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af40",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557b30",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556af48",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556af68",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af68",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557b70",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556af70",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ },
+ {
+ "base_class": "Foo5",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo5",
+ "address": "0x55555556af50",
+ "fields": [
+ {
+ "field": "_vptr.Foo5",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af50",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557b50",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "c",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af58",
+ "value": "3"
+ }
+ },
+ {
+ "field": "cc",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af5c",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "visited",
+ "ctype": "Foo",
+ "address": "0x55555556af68"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_w.json b/gdb/gdb_json_printer/test/objects2_85_w.json
new file mode 100644
index 0000000..cf9037b
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_w.json
@@ -0,0 +1,146 @@
+{
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x7fffffffd750",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo3",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "d",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af14",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo1",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo1",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556aefa",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556aef0",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c40",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556aef8",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ },
+ {
+ "base_class": "Foo2",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo2",
+ "address": "0x55555556af00",
+ "fields": [
+ {
+ "field": "c",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af0c",
+ "value": "3"
+ }
+ },
+ {
+ "field": "cc",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af10",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556af00",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af00",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c58",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556af08",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_x.json b/gdb/gdb_json_printer/test/objects2_85_x.json
new file mode 100644
index 0000000..a2b8fad
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_x.json
@@ -0,0 +1,59 @@
+{
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x7fffffffd768",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo1",
+ "address": "0x55555556aeb0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556aeba",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556aeb0",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556aeb0",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c88",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556aeb8",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_y.json b/gdb/gdb_json_printer/test/objects2_85_y.json
new file mode 100644
index 0000000..4f12cef
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_y.json
@@ -0,0 +1,68 @@
+{
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x7fffffffd760",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo2",
+ "address": "0x55555556aed0",
+ "fields": [
+ {
+ "field": "c",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556aedc",
+ "value": "3"
+ }
+ },
+ {
+ "field": "cc",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556aee0",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556aed0",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556aed0",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c70",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556aed8",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_z.json b/gdb/gdb_json_printer/test/objects2_85_z.json
new file mode 100644
index 0000000..c77c9b5
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_z.json
@@ -0,0 +1,146 @@
+{
+ "type": "pointer",
+ "ctype": "Foo1 *",
+ "address": "0x7fffffffd758",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo3",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "d",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af14",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo1",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo1",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556aefa",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556aef0",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556aef0",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c40",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556aef8",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ },
+ {
+ "base_class": "Foo2",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo2",
+ "address": "0x55555556af00",
+ "fields": [
+ {
+ "field": "c",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af0c",
+ "value": "3"
+ }
+ },
+ {
+ "field": "cc",
+ "value": {
+ "type": "int",
+ "ctype": "uint32_t",
+ "address": "0x55555556af10",
+ "value": "4"
+ }
+ }
+ ],
+ "base_classes": [
+ {
+ "base_class": "Foo",
+ "value": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556af00",
+ "fields": [
+ {
+ "field": "_vptr.Foo",
+ "value": {
+ "type": "pointer",
+ "ctype": "int (**)(void)",
+ "address": "0x55555556af00",
+ "reference": {
+ "type": "pointer",
+ "ctype": "int (*)(void)",
+ "address": "0x555555557c58",
+ "reference": {
+ "type": "extract failed"
+ }
+ }
+ }
+ },
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556af08",
+ "value": "1"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects_37_bar.json b/gdb/gdb_json_printer/test/objects_37_bar.json
new file mode 100644
index 0000000..38cb376
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects_37_bar.json
@@ -0,0 +1,22 @@
+{
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd760",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x55555556ded0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556ded0",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects_37_foo.json b/gdb/gdb_json_printer/test/objects_37_foo.json
new file mode 100644
index 0000000..58202f7
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects_37_foo.json
@@ -0,0 +1,47 @@
+{
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x7fffffffd768",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x55555556deb0",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x55555556deb0",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x55555556deb8",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x55555556ded0",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x55555556ded0",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_bar.json b/gdb/gdb_json_printer/test/reference_41_bar.json
new file mode 100644
index 0000000..22d33f7
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_bar.json
@@ -0,0 +1,17 @@
+{
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd74e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd74e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_bar_ptr.json b/gdb/gdb_json_printer/test/reference_41_bar_ptr.json
new file mode 100644
index 0000000..3fd919d
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_bar_ptr.json
@@ -0,0 +1,22 @@
+{
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd760",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd74e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd74e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_bar_ref.json b/gdb/gdb_json_printer/test/reference_41_bar_ref.json
new file mode 100644
index 0000000..d5515f3
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_bar_ref.json
@@ -0,0 +1,22 @@
+{
+ "type": "reference",
+ "ctype": "Bar &",
+ "address": "0x7fffffffd74e",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd74e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd74e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_foo.json b/gdb/gdb_json_printer/test/reference_41_foo.json
new file mode 100644
index 0000000..9fec7d5
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_foo.json
@@ -0,0 +1,42 @@
+{
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd750",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd750",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd758",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd74e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd74e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_foo_ptr.json b/gdb/gdb_json_printer/test/reference_41_foo_ptr.json
new file mode 100644
index 0000000..9d965e8
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_foo_ptr.json
@@ -0,0 +1,47 @@
+{
+ "type": "pointer",
+ "ctype": "Foo *",
+ "address": "0x7fffffffd768",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd750",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd750",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd758",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd74e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd74e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_foo_ref.json b/gdb/gdb_json_printer/test/reference_41_foo_ref.json
new file mode 100644
index 0000000..76975dc
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_foo_ref.json
@@ -0,0 +1,47 @@
+{
+ "type": "reference",
+ "ctype": "Foo &",
+ "address": "0x7fffffffd750",
+ "reference": {
+ "type": "struct",
+ "ctype": "Foo",
+ "address": "0x7fffffffd750",
+ "fields": [
+ {
+ "field": "a",
+ "value": {
+ "type": "int",
+ "ctype": "uint8_t",
+ "address": "0x7fffffffd750",
+ "value": "1"
+ }
+ },
+ {
+ "field": "bar",
+ "value": {
+ "type": "pointer",
+ "ctype": "Bar *",
+ "address": "0x7fffffffd758",
+ "reference": {
+ "type": "struct",
+ "ctype": "Bar",
+ "address": "0x7fffffffd74e",
+ "fields": [
+ {
+ "field": "b",
+ "value": {
+ "type": "int",
+ "ctype": "uint16_t",
+ "address": "0x7fffffffd74e",
+ "value": "2"
+ }
+ }
+ ],
+ "base_classes": []
+ }
+ }
+ }
+ ],
+ "base_classes": []
+ }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/array.cpp b/gdb/gdb_json_printer/test_examples/array.cpp
new file mode 100644
index 0000000..d2a9b85
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/array.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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 <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Bar {
+public:
+ uint16_t b = 2;
+};
+
+class Foo {
+public:
+ uint8_t a = 1;
+ Bar *bar = nullptr;
+};
+
+int main() {
+ int16_t a[5] = {1, 2, 3, 4, 5};
+ int16_t* b = &a[2];
+ Foo foo[3];
+ Bar bar[3];
+ foo[0].bar = &bar[0];
+ foo[1].bar = &bar[1];
+ foo[2].bar = &bar[2];
+ Foo& foo1 = foo[0];
+
+ return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/basic_types.cpp b/gdb/gdb_json_printer/test_examples/basic_types.cpp
new file mode 100644
index 0000000..dd13c02
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/basic_types.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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 <cstdint>
+#include <cstdlib>
+#include <iostream>
+
+enum Animal { CAT, DOG, TIGER };
+
+int main() {
+ {
+ uint8_t a = 1;
+ int8_t b = -2;
+ uint16_t c = 3;
+ int16_t d = -4;
+ uint32_t e = 5;
+ int32_t f = -6;
+ uint64_t g = 7;
+ int64_t h = -8;
+ float i = 9.0;
+ double j = -10.0;
+ const char *k = "Hello";
+ void *l = nullptr;
+ char *m = nullptr;
+ bool n = rand() % 2 == 0;
+ Animal o = CAT;
+ if (n) {
+ a += b;
+ }
+ std::cout << a + b + c + d + e + f + g + h + i + j << std::endl;
+ }
+ {
+ {
+ const uint8_t a = 1;
+ const int8_t b = -2;
+ const uint16_t c = 3;
+ const int16_t d = -4;
+ const uint32_t e = 5;
+ const int32_t f = -6;
+ const uint64_t g = 7;
+ const int64_t h = -8;
+ const float i = 9.0;
+ const double j = -10.0;
+ const char *k = "Hello";
+ const void *l = nullptr;
+ const char *m = nullptr;
+ const bool n = rand() % 2 == 0;
+ const Animal o = DOG;
+ if (n) {
+ std::cout << a + b + c + d + e + f + g + h + i + j << std::endl;
+ }
+ }
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/objects.cpp b/gdb/gdb_json_printer/test_examples/objects.cpp
new file mode 100644
index 0000000..9f3bb92
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/objects.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 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 <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Bar {
+public:
+ uint16_t b = 2;
+};
+
+class Foo {
+public:
+ uint8_t a = 1;
+ Bar *bar = nullptr;
+};
+
+int main() {
+ {
+ Foo *foo = new Foo();
+ Bar *bar = new Bar();
+ foo->bar = bar;
+ delete foo;
+ delete bar;
+ }
+ {
+ std::unique_ptr<Foo> foo = std::make_unique<Foo>();
+ std::unique_ptr<Bar> bar = std::make_unique<Bar>();
+ foo->bar = bar.get();
+ foo->bar->b++;
+ }
+ {
+ std::shared_ptr<Foo> foo = std::make_shared<Foo>();
+ std::shared_ptr<Bar> bar = std::make_shared<Bar>();
+ foo->bar = bar.get();
+ foo->bar->b++;
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/objects1.cpp b/gdb/gdb_json_printer/test_examples/objects1.cpp
new file mode 100644
index 0000000..dc4e4d4
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/objects1.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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 <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Foo;
+
+class Bar {
+public:
+ uint16_t b = 2;
+ Foo *foo = nullptr;
+};
+
+class Foo {
+public:
+ uint8_t a = 1;
+ Bar *bar = nullptr;
+};
+
+int main() {
+ {
+ Foo *foo = new Foo();
+ Bar *bar = new Bar();
+ foo->bar = bar;
+ bar->foo = foo;
+ delete foo;
+ delete bar;
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/objects2.cpp b/gdb/gdb_json_printer/test_examples/objects2.cpp
new file mode 100644
index 0000000..7985cff
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/objects2.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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 <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Foo {
+public:
+ uint8_t a = 1;
+ virtual int get() = 0;
+};
+
+class Foo1 : public Foo {
+ uint16_t b = 2;
+ virtual int get() override { return b; }
+};
+
+class Foo2 : public Foo {
+public:
+ uint32_t c = 3;
+ uint32_t cc = 4;
+ virtual int get() override { return c; }
+};
+
+class Foo3 : public Foo1, public Foo2 {
+ uint32_t d = 4;
+ virtual int get() override { return d; }
+};
+
+class Foo4 : virtual public Foo {
+ uint16_t b = 2;
+ virtual int get() override { return b; }
+};
+
+class Foo5 : virtual public Foo {
+public:
+ uint32_t c = 3;
+ uint32_t cc = 4;
+ virtual int get() override { return c; }
+};
+
+class Foo6 : public Foo4, public Foo5 {
+ uint32_t d = 4;
+ virtual int get() override { return d; }
+};
+
+class Bar {
+public:
+ uint8_t e = 5;
+};
+
+class Bar1 : virtual public Bar {
+public:
+ uint8_t f = 6;
+};
+
+int main() {
+ {
+ Foo *x = new Foo1();
+ Foo *y = new Foo2();
+ Foo1 *z = new Foo3();
+ Foo *w = z;
+ Bar *a = new Bar1();
+ Foo2 b;
+ Foo &c = *w;
+ Foo1 d = *z;
+ b.c += 1;
+ Foo *e = new Foo6();
+ Foo4 *f = dynamic_cast<Foo6 *>(e);
+
+ delete a;
+ delete x;
+ delete y;
+ delete z;
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/reference.cpp b/gdb/gdb_json_printer/test_examples/reference.cpp
new file mode 100644
index 0000000..e86b7b4
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/reference.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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 <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Bar {
+public:
+ uint16_t b = 2;
+};
+
+class Foo {
+public:
+ uint8_t a = 1;
+ Bar *bar = nullptr;
+};
+
+int main() {
+ Foo foo;
+ Bar bar;
+ foo.bar = &bar;
+ Foo &foo_ref = foo;
+ Bar &bar_ref = bar;
+ Foo *foo_ptr = &foo;
+ Bar *bar_ptr = &bar;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/gdb/heap_print/README.md b/gdb/heap_print/README.md
new file mode 100644
index 0000000..63a767c
--- /dev/null
+++ b/gdb/heap_print/README.md
@@ -0,0 +1,44 @@
+Script supports 2 custom commands:
+
+1) watch_heap : sets break point at dynamic memory allocation and keeps track of it
+2) print_ptr : prints the memory pointed by raw pointer in hex format.
+
+ eg:
+ (gdb) print_ptr malloc_ptr
+ Type : int *
+ Starting Address: 0x55555556aeb0
+ Length : 40
+ 0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x03 0x00 0x00 0x00
+ 0x04 0x00 0x00 0x00 0x05 0x00 0x00 0x00 0x06 0x00 0x00 0x00
+ 0x07 0x00 0x00 0x00 0x08 0x00 0x00 0x00 0x09 0x00 0x00 0x00
+ 0x0a 0x00 0x00 0x00
+
+ If print_ptr is used after free/delete[], then it would print "No address mapping found!"
+
+
+Tests:
+
+To run the test
+
+In the heap_print dir,
+
+Compile :
+
+g++ -O0 -g test/sample_heap_test.cc -o test/sample_heap_test.o
+
+And then Run:
+
+$ gdb
+$ source test/test_heap_print_script.py
+
+
+Future Goals:
+
+To handle pointer offset, for eg, (gdb) print_ptr malloc_ptr + 3
+
+To handle custom allacator, may be watch_heap command could take in arguements
+and sets additional break points.
+
+
+
+
diff --git a/gdb/heap_print/heap_print_script.py b/gdb/heap_print/heap_print_script.py
new file mode 100644
index 0000000..f65d56b
--- /dev/null
+++ b/gdb/heap_print/heap_print_script.py
@@ -0,0 +1,239 @@
+import gdb
+
+
+def parse_address_to_int(address):
+ int_address_string = gdb.execute(
+ 'p/d {}'.format(address), to_string=True)
+ int_address = int(int_address_string.split('=')[1].strip())
+ return int_address
+
+
+def parse_gdb_equals(str):
+ """
+ str is $1 = value. so it returns value
+ """
+ return str.split("=")[1].strip()
+
+
+class HeapMapping:
+ """
+ Wrapper class for dictionary to have customization for the dictionary
+ and one entry point
+ """
+
+ address_length_mapping = {}
+ address_set = set()
+
+ @staticmethod
+ def put(address, length):
+ HeapMapping.address_length_mapping[address] = length
+ HeapMapping.address_set.add(address)
+
+ @staticmethod
+ def get(address):
+ """
+ Gets the length of the dynamic array corresponding to address. Suppose dynamic
+ array is {1,2,3,4,5} and starting address is 400 which is passed as address to this
+ method, then method would return 20(i.e. 5 * sizeof(int)). When this address
+ is offsetted for eg 408 is passed to this method, then it will return remainder
+ number of bytes allocated, here it would be 12 (i.e. 420 - 408)
+ Algorithm tries to find address in address_length_apping, if it doesn't find it
+ then it tries to find the range that can fit the address. if it fails to find such
+ mapping then it would return None.
+ """
+
+ length_found = HeapMapping.address_length_mapping.get(address)
+ if length_found:
+ return length_found
+ else:
+ address_list = list(HeapMapping.address_set)
+ address_list.sort()
+ left = 0
+ right = len(address_list) - 1
+ while left <= right:
+ mid = int((left + right) / 2)
+ if address > address_list[mid]:
+ left = mid + 1
+ # only < case would be accounted in else.
+ # As == would be handled in the if-check above (outside while)
+ else:
+ right = mid - 1
+
+ index = left - 1
+ if index == -1:
+ return None
+ base_address = address_list[index]
+ base_len = HeapMapping.address_length_mapping.get(base_address)
+ if base_address + base_len > address:
+ return base_address + base_len - address
+ else:
+ return None
+
+ @staticmethod
+ def remove(address):
+ HeapMapping.address_length_mapping.pop(address, None)
+ HeapMapping.address_set.discard(address)
+
+
+class AllocationFinishedBreakpoint(gdb.FinishBreakpoint):
+ """
+ Sets temporary breakpoints on returns (specifically returns of memory allocations)
+ to record address allocated.
+ It get instantiated from AllocationBreakpoint and ReallocationBreakpoint. When it is
+ instantiated from ReallocationBreakPoint, it carries prev_address.
+ """
+
+ def __init__(self, length, prev_address=None):
+ super().__init__(internal=True)
+ self.length = length
+ self.prev_address = prev_address
+
+ def stop(self):
+ """
+ Called when the return address in the current frame is hit. It parses hex address
+ into int address. If return address is not null then it stores address and length
+ into the address_length_mapping dictionary.
+ """
+
+ return_address = self.return_value
+ if return_address is not None or return_address == 0x0:
+ if self.prev_address != None:
+ HeapMapping.remove(self.prev_address)
+
+ # Converting hex address to int address
+ int_address = parse_address_to_int(return_address)
+ HeapMapping.put(int_address, self.length)
+ return False
+
+
+class AllocationBreakpoint(gdb.Breakpoint):
+ """
+ Handler class when malloc and operator new[] gets hit
+ """
+
+ def __init__(self, spec):
+ super().__init__(spec, internal=True)
+
+ def stop(self):
+ # handle malloc and new
+ func_args_string = gdb.execute('info args', to_string=True)
+ if func_args_string.find("=") != -1:
+ # There will be just 1 argument to malloc. So no need to handle multiline
+ length = int(parse_gdb_equals(func_args_string))
+ AllocationFinishedBreakpoint(length)
+ return False
+
+
+class ReallocationBreakpoint(gdb.Breakpoint):
+ """
+ Handler class when realloc gets hit
+ """
+
+ def __init__(self, spec):
+ super().__init__(spec, internal=True)
+
+ def stop(self):
+ # handle realloc
+ func_args_string = gdb.execute('info args', to_string=True)
+ if func_args_string.find("=") != -1:
+ args = func_args_string.split("\n")
+ address = parse_gdb_equals(args[0])
+ int_address = parse_address_to_int(address)
+ length = int(parse_gdb_equals(args[1]))
+ AllocationFinishedBreakpoint(length, int_address)
+ return False
+
+
+class DeallocationBreakpoint(gdb.Breakpoint):
+ """
+ Handler class when free and operator delete[] gets hit
+ """
+
+ def __init__(self, spec):
+ super().__init__(spec, internal=True)
+
+ def stop(self):
+ func_args_string = gdb.execute('info args', to_string=True)
+ if func_args_string.find("=") != -1:
+ address = parse_gdb_equals(func_args_string)
+ int_address = parse_address_to_int(address)
+ HeapMapping.remove(int_address)
+ return False
+
+
+class WatchHeap(gdb.Command):
+ """
+ Custom Command to keep track of Heap Memory Allocation.
+ Currently keeps tracks of memory allocated/deallocated using
+ malloc, realloc, free, operator new[] and operator delete[]
+ """
+
+ def __init__(self):
+ super(WatchHeap, self).__init__("watch_heap", gdb.COMMAND_USER)
+
+ def complete(self, text, word):
+ return gdb.COMPLETE_COMMAND
+
+ def invoke(self, args, from_tty):
+ # TODO : Check whether break location methods are defined
+ AllocationBreakpoint("malloc")
+ AllocationBreakpoint("operator new[]")
+ ReallocationBreakpoint("realloc")
+ DeallocationBreakpoint("free")
+ DeallocationBreakpoint("operator delete[]")
+
+
+class PrintHeapPointer(gdb.Command):
+ """
+ Custom command to print memory allocated at dynamic time
+ """
+
+ def __init__(self):
+ super(PrintHeapPointer, self).__init__("print_ptr", gdb.COMMAND_USER)
+
+ def complete(self, text, word):
+ return gdb.COMPLETE_COMMAND
+
+ def invoke(self, args, from_tty=True):
+ try:
+ value = gdb.parse_and_eval(args)
+ if value.type.code == gdb.TYPE_CODE_PTR:
+ print("Type : ", value.type)
+ starting_address_string = gdb.execute(
+ 'p/x {}'.format(value), to_string=True)
+ print("Address: ",
+ parse_gdb_equals(starting_address_string))
+ int_address = parse_address_to_int(value)
+ # print memory
+ self.print_heap(int_address)
+ except Exception:
+ print('No symbol found!')
+
+ def print_heap(self, address):
+ """
+ Prints the memory that is being pointed by address in hex format
+
+ Parameters
+ ---------
+ address : raw pointer
+ """
+
+ memory_size = HeapMapping.get(address)
+ if memory_size:
+ print('Length :', memory_size)
+ result = ''
+ i = 0
+ while i < memory_size:
+ byte_string = gdb.execute(
+ 'x/1bx {}'.format(address), to_string=True)
+ result += byte_string.split(':')[1].strip() + " "
+ address += 1
+ i += 1
+ print(result)
+ else:
+ print("No address mapping found!")
+
+
+if __name__ == '__main__':
+ WatchHeap()
+ PrintHeapPointer()
diff --git a/gdb/heap_print/test/sample_heap_test.cc b/gdb/heap_print/test/sample_heap_test.cc
new file mode 100644
index 0000000..783c471
--- /dev/null
+++ b/gdb/heap_print/test/sample_heap_test.cc
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <new>
+
+int main()
+{
+ int n = 10;
+
+ // Dynamically allocate memory using malloc()
+ int *malloc_ptr = (int *)malloc(n * sizeof(int));
+
+ if (malloc_ptr != NULL)
+ {
+ //Just Feeding data
+ for (int i = 0; i < n; ++i)
+ {
+ malloc_ptr[i] = i + 1;
+ }
+ //For checking realloc
+ int new_n = 20;
+ malloc_ptr = (int *)realloc(malloc_ptr, new_n * sizeof(int));
+ for (int i = 0; i < new_n; ++i)
+ {
+ malloc_ptr[i] = i + 1;
+ }
+ //For checking free
+ free(malloc_ptr);
+ }
+
+ // Dynamically allocating memory using operator new[]
+ int *new_ptr = new int[n];
+ if (new_ptr != NULL)
+ {
+ //Just feeding data
+ for (int i = 0; i < n; ++i)
+ {
+ new_ptr[i] = i + 1;
+ }
+
+ //For checking operator delete[]
+ delete[] new_ptr;
+ }
+ printf("Done");
+ return 0;
+}
\ No newline at end of file
diff --git a/gdb/heap_print/test/test_heap_print_script.py b/gdb/heap_print/test/test_heap_print_script.py
new file mode 100644
index 0000000..5518527
--- /dev/null
+++ b/gdb/heap_print/test/test_heap_print_script.py
@@ -0,0 +1,113 @@
+import unittest
+import gdb
+
+
+def get_n(n_str):
+ return int(n_str.split("=")[1].strip())
+
+
+class HeapMemoryTest(unittest.TestCase):
+
+ def setUp(self):
+ gdb.execute('set pagination on')
+ gdb.execute("file test/sample_heap_test.o")
+ gdb.execute("source heap_print_script.py")
+ gdb.execute("delete")
+ gdb.execute("watch_heap")
+
+ def check_memory(self, n, array_ptr_str, offset=1):
+ """
+ It is used to test what we got from 'print_ptr' is what we expect.
+ Sample test program allocates array of n int's using malloc and then
+ assigns 1 to n values to that array. So checking that malloc_ptr_str
+ is 1 to n, following big endian size and size of int as 32 bits
+
+ Parameters
+ ----------
+ n : int
+ array length
+ array_ptr_str : str
+ whole output from print_ptr command including memory content
+ offset : int
+ checking memory content starts from offset value. By default it is 1
+ """
+
+ data = array_ptr_str.split("\n")[3]
+ bytes_from_heap = data.split(" ")
+ actual_start = offset
+ for i in range(0, n * 4, 4):
+ hex_str = bytes_from_heap[i+3][2:]
+ hex_str += bytes_from_heap[i+2][2:]
+ hex_str += bytes_from_heap[i+1][2:]
+ hex_str += bytes_from_heap[i][2:]
+ int_of_hex = int(hex_str, 16)
+ self.assertEqual(actual_start, int_of_hex)
+ actual_start += 1
+
+ def test_malloc(self):
+ print("malloc test")
+ gdb.execute("b 20")
+ gdb.execute("r")
+ n_str = gdb.execute("print n", to_string=True)
+ n = get_n(n_str)
+ malloc_ptr_array_str = gdb.execute(
+ "print_ptr malloc_ptr", to_string=True)
+ print(malloc_ptr_array_str)
+ self.check_memory(n, malloc_ptr_array_str)
+ self.assertTrue(True)
+
+ def test_realloc(self):
+ print("realloc test")
+ gdb.execute("b 27")
+ gdb.execute("r")
+ new_n = gdb.execute("print new_n", to_string=True)
+ n = get_n(new_n)
+ malloc_ptr_str = gdb.execute("print_ptr malloc_ptr", to_string=True)
+ print(malloc_ptr_str)
+ self.check_memory(n, malloc_ptr_str)
+
+ def test_offset(self):
+ """
+ Testcase to test raw_pointers that are offset
+ """
+
+ print("offset test. we have array of 20 (80 bytes) and \
+ we offset it by 3, so new length should be 68")
+ offset = 3
+ gdb.execute("b 27")
+ gdb.execute("r")
+ new_n = gdb.execute("print new_n", to_string=True)
+ n = get_n(new_n)
+ malloc_ptr_str = gdb.execute(
+ "print_ptr malloc_ptr + {}".format(offset), to_string=True)
+ print(malloc_ptr_str)
+ self.check_memory(n - offset, malloc_ptr_str, offset+1)
+
+ def test_free(self):
+ print("free test")
+ gdb.execute("b 28")
+ gdb.execute("r")
+ malloc_ptr_str = gdb.execute("print_ptr malloc_ptr", to_string=True)
+ data = malloc_ptr_str.split("\n")[2].strip()
+ self.assertEqual(data, "No address mapping found!")
+
+ def test_new(self):
+ print("operator new[] test")
+ gdb.execute("b 41")
+ gdb.execute("r")
+ n_str = gdb.execute("print n", to_string=True)
+ n = get_n(n_str)
+ new_ptr_array_str = gdb.execute("print_ptr new_ptr", to_string=True)
+ self.check_memory(n, new_ptr_array_str)
+
+ def test_delete(self):
+ print("operator delete[]")
+ gdb.execute("b 42")
+ gdb.execute("r")
+ new_ptr_array_str = gdb.execute("print_ptr new_ptr", to_string=True)
+ data = new_ptr_array_str.split("\n")[2].strip()
+ self.assertEqual(data, "No address mapping found!")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/gdb/parameters_extract.py b/gdb/parameters_extract.py
new file mode 100644
index 0000000..b1af70c
--- /dev/null
+++ b/gdb/parameters_extract.py
@@ -0,0 +1,288 @@
+import os
+import re
+
+# If doing it on device with gdbserver
+DEVICE = os.environ.get('GDBSCRIPT_ON_DEVICE', False)
+# Path of the file on device
+DEVICE_FILEPATH = os.environ.get('GDBSCRIPT_FILENAME', None)
+# GDBServer's port
+DEVICE_PORT = os.environ.get('GDBSCRIPT_DEVICE_PORT', 4444)
+# Serial number of device for adb
+DEVICE_SERIAL = os.environ.get('GDBSCRIPT_DEVICE_SERIAL', None)
+
+def check_device_args():
+ """
+ Checks if FILEPATH is provided if the execution is on device
+ """
+ if not DEVICE:
+ return
+
+ if not DEVICE_FILEPATH:
+ raise ValueError("Filename (GDBSCRIPT_FILEPATH) not provided")
+
+class RecordPoint(gdb.Breakpoint):
+ """
+ A custom breakpoint that records the arguments when the breakpoint is hit and continues
+ Also enables the next breakpoint and disables all the ones after it
+ """
+ def stop(self):
+ """
+ The function that's called when a breakpoint is hit. If we return true,
+ it halts otherwise it continues
+ We always return false because we just need to record the value and we
+ can do it without halting the program
+ """
+ self.args[self.times_hit % self.count] = get_function_args()
+ self.times_hit += 1
+
+ if self.next_bp != None:
+ self.next_bp.previous_hit()
+
+ return False
+
+ def previous_hit(self):
+ """
+ This function is called if the previous breakpoint is hit so it can enable
+ itself and disable the next ones
+ """
+ self.enabled = True
+
+ if self.next_bp != None:
+ self.next_bp.propagate_disable()
+
+ def propagate_disable(self):
+ """
+ Disabled all the breakpoints after itself
+ """
+ self.enabled = False
+ if self.next_bp != None:
+ self.next_bp.propagate_disable()
+
+ def process_arguments(self):
+ """
+ Orders the recorded arguments into the right order (oldest to newest)
+ """
+ current_hit_point = self.times_hit % self.count
+ # Split at the point of current_hit_point because all the entries after it
+ # are older than the ones before it
+ self.processed_args = self.args[current_hit_point:] + self.args[:current_hit_point]
+ self.current_arg_idx = 0
+
+ def get_arguments(self):
+ """
+ Gets the current argument value.
+ Should be called the same amount of times as the function was called
+ in the stacktrace
+ First call returns the arguments recorded for the first call in the stacktrace
+ and so on.
+ """
+ if self.current_arg_idx >= len(self.processed_args):
+ raise ValueError("Cannot get arguments more times than the function \
+ was present in stacktrace")
+
+ cur = self.processed_args[self.current_arg_idx]
+ self.current_arg_idx += 1
+ return cur
+
+def init_gdb():
+ """
+ Initialized the GDB specific stuff
+ """
+ gdb.execute('set pagination off')
+ gdb.execute('set print frame-arguments all')
+ if DEVICE:
+ gdb.execute('target extended-remote :{}'.format(DEVICE_PORT))
+ gdb.execute('set remote exec-file /data/local/tmp/{}'.format(DEVICE_FILEPATH))
+
+def initial_run():
+ """
+ The initial run of the program which captures the stacktrace in init.log file
+ """
+ gdb.execute('r > init.log 2>&1',from_tty=True, to_string=True)
+ if DEVICE:
+ if DEVICE_SERIAL:
+ os.system('adb -s "{}" pull /data/local/tmp/init.log'.format(DEVICE_SERIAL))
+ else:
+ os.system("adb pull /data/local/tmp/init.log")
+ with open("init.log", "rb") as f:
+ out = f.read().decode()
+ return out
+
+def gdb_exit():
+ """
+ Exits the GDB instance
+ """
+ gdb.execute('q')
+
+def get_stacktrace_functions(stacktrace):
+ """
+ Gets the functions from ASAN/HWASAN's stacktrace
+ Args:
+ stacktrace: (string) ASAN/HWASAN's stacktrace output
+ Returns:
+ functions: (list) functions in the stacktrace
+ """
+ stacktrace_start = stacktrace[stacktrace.index('==ERROR: '):].split("\n")
+ functions = []
+
+ # skip the first two lines of stacktrace
+ for line in stacktrace_start[2:]:
+ if line == "":
+ break
+
+ # Extracts the function name from a line like this
+ # "#0 0xaddress in function_name() file/path.cc:xx:yy"
+ func_name = line.strip().split(" ")[3]
+ if '(' in func_name:
+ func_name = func_name[:func_name.index('(')]
+
+ functions.append(func_name)
+
+ #remove last function from stacktrace because it would be _start
+ return functions
+
+def parse_function_arguments(func_info):
+ """
+ Parses the output of 'whatis' command into a list of arguments
+ "void (teststruct)" --> ["teststruct"]
+ "int (int (*)(int, char **, char **), int, char **, int (*)(int, char **, char **),
+ void (*)(void), void (*)(void), void *)" --> ['int (*)(int, char **, char **)',
+ 'int', 'char **', 'int (*)(int, char **, char **)', 'void (*)(void)',
+ 'void (*)(void)', ' void *']
+
+ Args:
+ func_info: (string) output of gdb's 'whatis' command for a function
+ Returns:
+ parsed_params: (list) parsed parameters of the function
+ """
+ if '(' not in func_info:
+ return []
+ func_params = func_info[func_info.index('(')+1:-1]
+ parentheses_count = 0
+ current_param = ""
+ parsed_params = []
+
+ for token in func_params:
+ # Essentially trying to get the data types from a function declaration
+ if token == '(':
+ parentheses_count += 1
+ elif token == ')':
+ parentheses_count -= 1
+
+ # If we are not inside any paren and see a ',' it signals the start of
+ #the next parameter
+ if token == ',' and parentheses_count == 0:
+ parsed_params.append(current_param.strip())
+ current_param = ""
+ else:
+ current_param += token
+
+ parsed_params.append(current_param)
+ return parsed_params
+
+def parse_stacktrace(stacktrace):
+ """
+ Parses the ASAN/HWASAN's stacktrace to a list of functions, their addresses
+ and argument types
+ Args:
+ stacktrace: (string) ASAN/HWASAN's stacktrace output
+ Returns:
+ functions_info: (list) parsed function information as a dictionary
+ """
+ stacktrace_functions = get_stacktrace_functions(stacktrace)[:-1]
+ functions_info = []
+ for function in stacktrace_functions:
+ # Gets the value right hand side of gdb's whatis command.
+ # "type = {function info}" -> "{function info}"
+ func_info = gdb.execute('whatis {}'.format(function),
+ to_string=True).split(' = ')[1].strip()
+ # Uses gdb's x/i to print its address and parse it from hex to int
+ address = int(gdb.execute("x/i {}".format(function),
+ to_string=True).strip().split(" ")[0], 16)
+ functions_info.append({'name': function, 'address':address,
+ 'arguments' : parse_function_arguments(func_info)})
+ #In the order they are called in the execution
+ return functions_info[::-1]
+
+def get_function_args():
+ """
+ Gets the current function arguments
+ """
+ args = gdb.execute('info args -q', to_string=True).strip()
+ return args
+
+def functions_to_breakpoint(parsed_functions):
+ """
+ Sets the breakpoint at every function and returns a dictionary mapping the
+ function to it's breakpoint
+ Args:
+ parsed_functions: (list) functions in the stacktrace (in the same order) as
+ dictionary with "name" referring to the function name
+ ({"name" : function_name})
+ Returns:
+ function_breakpoints: (dictionary) maps the function name to its
+ breakpoint object
+ """
+ function_breakpoints = {}
+ last_bp = None
+
+ for function in reversed(parsed_functions):
+ function_name = function['name']
+ if function_name in function_breakpoints:
+ function_breakpoints[function_name].count += 1
+ function_breakpoints[function_name].args.append(None)
+ continue
+
+ cur_bp = RecordPoint("{}".format(function_name))
+ cur_bp.count = 1
+ cur_bp.times_hit = 0
+ cur_bp.args = []
+ cur_bp.args.append(None)
+ cur_bp.next_bp = last_bp
+
+ function_breakpoints[function['name']] = cur_bp
+ last_bp = cur_bp
+
+ return function_breakpoints
+
+def run(parsed_functions):
+ """
+ Runs the whole thing by setting up breakpoints and printing them after
+ excecution is done
+ Args:
+ parsed_functions: A list of functions in the stacktrace (in the same order)
+ as dictionary with "name" referring to the function name
+ ({"name" : function_name})
+ """
+ names = [function['name'] for function in parsed_functions]
+ breakpoints = functions_to_breakpoint(parsed_functions)
+
+ #Disable all breakpoints at start
+ for bp in breakpoints:
+ breakpoints[bp].enabled = False
+
+ breakpoints[names[0]].enabled = True
+
+ gdb.execute('r')
+ for breakpoint in breakpoints:
+ breakpoints[breakpoint].process_arguments()
+
+ function_args = []
+ for name in names:
+ print("-----------")
+ print("Function -> {}".format(name))
+
+ function_args.append({'function':name,
+ 'arguments' : breakpoints[name].get_arguments()})
+ print(function_args[-1]['arguments'])
+
+ return function_args
+
+
+if __name__ == '__main__':
+ check_device_args()
+ init_gdb()
+ initial_out = initial_run()
+ function_data = parse_stacktrace(initial_out)
+ run(function_data)
+ gdb_exit()
diff --git a/remote_provisioning/OWNERS b/remote_provisioning/OWNERS
new file mode 100644
index 0000000..78a6711
--- /dev/null
+++ b/remote_provisioning/OWNERS
@@ -0,0 +1,3 @@
+jbires@google.com
+swillden@google.com
+wedsonaf@google.com
diff --git a/remote_provisioning/attestation_testing/Android.bp b/remote_provisioning/attestation_testing/Android.bp
new file mode 100644
index 0000000..341f7c0
--- /dev/null
+++ b/remote_provisioning/attestation_testing/Android.bp
@@ -0,0 +1,16 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "AttestationTestTool",
+ srcs: [
+ "java/**/*.java",
+ ],
+ manifest: "AndroidManifest.xml",
+ resource_dirs: ["res"],
+ static_libs: ["androidx.appcompat_appcompat",
+ "bouncycastle-unbundled",
+ "guava"],
+ platform_apis: true,
+}
diff --git a/remote_provisioning/attestation_testing/AndroidManifest.xml b/remote_provisioning/attestation_testing/AndroidManifest.xml
new file mode 100644
index 0000000..9af01e5
--- /dev/null
+++ b/remote_provisioning/attestation_testing/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.attestationexample">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher">
+ <activity
+ android:name=".AttestationActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/remote_provisioning/attestation_testing/README b/remote_provisioning/attestation_testing/README
new file mode 100644
index 0000000..fc92654
--- /dev/null
+++ b/remote_provisioning/attestation_testing/README
@@ -0,0 +1,8 @@
+Run the following commands to run this attestation test on device. From the root of the tree:
+> . build/envsetup.sh
+> lunch <<your_device_target>>
+> m AttestationTestTool
+> python tools/security/remote_provisioning/attestation_testing/attestation_test_host.py
+
+Any failures found during execution will be printed to the terminal in the format of:
+> AttestationFail: <<Description of failure>>
diff --git a/remote_provisioning/attestation_testing/attestation_test_host.py b/remote_provisioning/attestation_testing/attestation_test_host.py
new file mode 100644
index 0000000..417842a
--- /dev/null
+++ b/remote_provisioning/attestation_testing/attestation_test_host.py
@@ -0,0 +1,38 @@
+from sys import argv
+import os
+import subprocess
+import time
+
+APK_DIR = '${ANDROID_PRODUCT_OUT}/system/app/AttestationTestTool/AttestationTestTool.apk'
+FAILURE_TAG = 'AttestationFail'
+FAILURE_PREFIX = 'Failure: '
+FINISHED_TAG = 'AttestationFinished'
+INFO_TAG = 'AttestationFailInfo'
+INFO_PREFIX = ' ' * len(FAILURE_PREFIX)
+devnull = open(os.devnull, 'wb')
+
+# Clear logcat
+subprocess.call('adb logcat -c', shell=True, stdout=devnull)
+subprocess.call('adb install -r ' + APK_DIR, shell=True, stdout=devnull)
+subprocess.call('adb shell am start -a android.intent.action.MAIN -n com.google.attestationexample/.AttestationActivity',
+ shell=True, stdout=devnull)
+finished = False
+read_retry = 0
+failures = 0
+while not finished and read_retry < 5:
+ time.sleep(1)
+ logcat = subprocess.check_output(['adb', 'logcat', '-d'], stderr=subprocess.STDOUT)
+ for line in logcat.split('\n'):
+ if INFO_TAG in line:
+ print INFO_PREFIX + line[line.index('AttestationFailInfo') + len('AttestationFailInfo:'):]
+ elif FAILURE_TAG in line:
+ failures += 1
+ print FAILURE_PREFIX + line[line.index('AttestationFail') + len('AttestationFail:'):]
+ elif FINISHED_TAG in line and not finished:
+ print 'Finished. Failures: ' + str(failures)
+ finished = True
+ break
+ read_retry += 1
+ if read_retry is 5:
+ print 'Attestation test did not complete, check logcat to determine the source of the error'
+subprocess.call('adb uninstall com.google.attestationexample', shell=True, stdout=devnull)
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/Asn1Utils.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Asn1Utils.java
new file mode 100644
index 0000000..c3dc62b
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Asn1Utils.java
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+package com.google.attestationexample;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.bouncycastle.asn1.ASN1Boolean;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DEROctetString;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.String;
+import java.math.BigInteger;
+import java.security.cert.CertificateParsingException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Set;
+
+public class Asn1Utils {
+
+ public static int getIntegerFromAsn1(ASN1Encodable asn1Value)
+ throws CertificateParsingException {
+ if (asn1Value instanceof ASN1Integer) {
+ return bigIntegerToInt(((ASN1Integer) asn1Value).getValue());
+ } else if (asn1Value instanceof ASN1Enumerated) {
+ return bigIntegerToInt(((ASN1Enumerated) asn1Value).getValue());
+ } else {
+ throw new CertificateParsingException(
+ "Integer value expected, " + asn1Value.getClass().getName() + " found.");
+ }
+ }
+
+ public static Long getLongFromAsn1(ASN1Encodable asn1Value) throws CertificateParsingException {
+ if (asn1Value instanceof ASN1Integer) {
+ return bigIntegerToLong(((ASN1Integer) asn1Value).getValue());
+ } else {
+ throw new CertificateParsingException(
+ "Integer value expected, " + asn1Value.getClass().getName() + " found.");
+ }
+ }
+
+ public static byte[] getByteArrayFromAsn1(ASN1Encodable asn1Encodable)
+ throws CertificateParsingException {
+ if (asn1Encodable == null || !(asn1Encodable instanceof DEROctetString)) {
+ throw new CertificateParsingException("Expected DEROctetString");
+ }
+ ASN1OctetString derOctectString = (ASN1OctetString) asn1Encodable;
+ return derOctectString.getOctets();
+ }
+
+ public static ASN1Encodable getAsn1EncodableFromBytes(byte[] bytes)
+ throws CertificateParsingException {
+ try (ASN1InputStream asn1InputStream = new ASN1InputStream(bytes)) {
+ return asn1InputStream.readObject();
+ } catch (IOException e) {
+ throw new CertificateParsingException("Failed to parse Encodable", e);
+ }
+ }
+
+ public static ASN1Sequence getAsn1SequenceFromBytes(byte[] bytes)
+ throws CertificateParsingException {
+ try (ASN1InputStream asn1InputStream = new ASN1InputStream(bytes)) {
+ return getAsn1SequenceFromStream(asn1InputStream);
+ } catch (IOException e) {
+ throw new CertificateParsingException("Failed to parse SEQUENCE", e);
+ }
+ }
+
+ public static ASN1Sequence getAsn1SequenceFromStream(final ASN1InputStream asn1InputStream)
+ throws IOException, CertificateParsingException {
+ ASN1Primitive asn1Primitive = asn1InputStream.readObject();
+ if (!(asn1Primitive instanceof ASN1OctetString)) {
+ throw new CertificateParsingException(
+ "Expected octet stream, found " + asn1Primitive.getClass().getName());
+ }
+ try (ASN1InputStream seqInputStream = new ASN1InputStream(
+ ((ASN1OctetString) asn1Primitive).getOctets())) {
+ asn1Primitive = seqInputStream.readObject();
+ if (!(asn1Primitive instanceof ASN1Sequence)) {
+ throw new CertificateParsingException(
+ "Expected sequence, found " + asn1Primitive.getClass().getName());
+ }
+ return (ASN1Sequence) asn1Primitive;
+ }
+ }
+
+ public static Set<Integer> getIntegersFromAsn1Set(ASN1Encodable set)
+ throws CertificateParsingException {
+ if (!(set instanceof ASN1Set)) {
+ throw new CertificateParsingException(
+ "Expected set, found " + set.getClass().getName());
+ }
+
+ ImmutableSet.Builder<Integer> builder = ImmutableSet.builder();
+ for (Enumeration<?> e = ((ASN1Set) set).getObjects(); e.hasMoreElements();) {
+ builder.add(getIntegerFromAsn1((ASN1Integer) e.nextElement()));
+ }
+ return builder.build();
+ }
+
+ public static String getStringFromAsn1OctetStreamAssumingUTF8(ASN1Encodable encodable)
+ throws CertificateParsingException, UnsupportedEncodingException {
+ if (!(encodable instanceof ASN1OctetString)) {
+ throw new CertificateParsingException(
+ "Expected octet string, found " + encodable.getClass().getName());
+ }
+
+ ASN1OctetString octetString = (ASN1OctetString) encodable;
+ return new String(octetString.getOctets(), "UTF-8");
+ }
+
+ public static Date getDateFromAsn1(ASN1Primitive value) throws CertificateParsingException {
+ return new Date(getLongFromAsn1(value));
+ }
+
+ public static boolean getBooleanFromAsn1(ASN1Encodable value)
+ throws CertificateParsingException {
+ if (!(value instanceof ASN1Boolean)) {
+ throw new CertificateParsingException(
+ "Expected boolean, found " + value.getClass().getName());
+ }
+ return ((ASN1Boolean) value).isTrue();
+ }
+
+ private static int bigIntegerToInt(BigInteger bigInt) throws CertificateParsingException {
+ if (bigInt.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0
+ || bigInt.compareTo(BigInteger.ZERO) < 0) {
+ throw new CertificateParsingException("INTEGER out of bounds");
+ }
+ return bigInt.intValue();
+ }
+
+ private static long bigIntegerToLong(BigInteger bigInt) throws CertificateParsingException {
+ if (bigInt.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0
+ || bigInt.compareTo(BigInteger.ZERO) < 0) {
+ throw new CertificateParsingException("INTEGER out of bounds");
+ }
+ return bigInt.longValue();
+ }
+}
\ No newline at end of file
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/Attestation.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Attestation.java
new file mode 100644
index 0000000..c94ff3f
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Attestation.java
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+package com.google.attestationexample;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.io.BaseEncoding;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Parses an attestation certificate and provides an easy-to-use interface for examining the
+ * contents.
+ */
+public class Attestation {
+ static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";
+ static final int ATTESTATION_VERSION_INDEX = 0;
+ static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
+ static final int KEYMASTER_VERSION_INDEX = 2;
+ static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
+ static final int ATTESTATION_CHALLENGE_INDEX = 4;
+ static final int UNIQUE_ID_INDEX = 5;
+ static final int SW_ENFORCED_INDEX = 6;
+ static final int TEE_ENFORCED_INDEX = 7;
+
+ public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
+ public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
+ public static final int KM_SECURITY_LEVEL_STRONGBOX = 2;
+
+ private final boolean haveAttestation;
+ private final int attestationVersion;
+ private final int attestationSecurityLevel;
+ private final int keymasterVersion;
+ private final int keymasterSecurityLevel;
+ private final byte[] attestationChallenge;
+ private final byte[] uniqueId;
+ private final AuthorizationList softwareEnforced;
+ private final AuthorizationList teeEnforced;
+
+
+ /**
+ * Constructs an {@code Attestation} object from the provided {@link X509Certificate},
+ * extracting the attestation data from the attestation extension.
+ *
+ * @throws CertificateParsingException if the certificate does not contain a properly-formatted
+ * attestation extension.
+ */
+ public Attestation(X509Certificate x509Cert) throws CertificateParsingException {
+ ASN1Sequence seq = getAttestationSequence(x509Cert);
+ if (seq == null) {
+ haveAttestation = false;
+ attestationVersion = 0;
+ attestationSecurityLevel = 0;
+ keymasterVersion = 0;
+ keymasterSecurityLevel = 0;
+ attestationChallenge = null;
+ uniqueId = null;
+ softwareEnforced = null;
+ teeEnforced = null;
+ return;
+ }
+
+ haveAttestation = true;
+ attestationVersion =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_VERSION_INDEX));
+ attestationSecurityLevel =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX));
+ keymasterVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_VERSION_INDEX));
+ keymasterSecurityLevel =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX));
+
+ attestationChallenge =
+ Asn1Utils.getByteArrayFromAsn1(
+ seq.getObjectAt(Attestation.ATTESTATION_CHALLENGE_INDEX));
+
+ uniqueId = Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(Attestation.UNIQUE_ID_INDEX));
+
+ softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX));
+ teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX));
+ }
+
+ public static String securityLevelToString(int attestationSecurityLevel) {
+ switch (attestationSecurityLevel) {
+ case KM_SECURITY_LEVEL_SOFTWARE:
+ return "Software";
+ case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+ return "TEE";
+ case KM_SECURITY_LEVEL_STRONGBOX:
+ return "StrongBox";
+ default:
+ return "Unknown";
+ }
+ }
+
+ public int getAttestationVersion() {
+ return attestationVersion;
+ }
+
+ public int getAttestationSecurityLevel() {
+ return attestationSecurityLevel;
+ }
+
+ public int getKeymasterVersion() {
+ return keymasterVersion;
+ }
+
+ public int getKeymasterSecurityLevel() {
+ return keymasterSecurityLevel;
+ }
+
+ public byte[] getAttestationChallenge() {
+ return attestationChallenge;
+ }
+
+ public byte[] getUniqueId() {
+ return uniqueId;
+ }
+
+ public AuthorizationList getSoftwareEnforced() {
+ return softwareEnforced;
+ }
+
+ public AuthorizationList getTeeEnforced() {
+ return teeEnforced;
+ }
+
+ @Override
+ public String toString() {
+ if (!haveAttestation) {
+ return "No attestation";
+ }
+
+ StringBuilder s = new StringBuilder();
+ s.append("Attestation version: " + attestationVersion);
+ s.append("\nAttestation security: " + securityLevelToString(attestationSecurityLevel));
+ s.append("\nKM version: " + keymasterVersion);
+ s.append("\nKM security: " + securityLevelToString(keymasterSecurityLevel));
+
+ s.append("\nChallenge");
+ String stringChallenge = new String(attestationChallenge);
+ if (CharMatcher.ascii().matchesAllOf(stringChallenge)) {
+ s.append(": [" + stringChallenge + "]");
+ } else {
+ s.append(" (base64): [" + BaseEncoding.base64().encode(attestationChallenge) + "]");
+ }
+ if (uniqueId != null) {
+ s.append("\nUnique ID (base64): [" + BaseEncoding.base64().encode(uniqueId) + "]");
+ }
+
+ s.append("\n\n-- SW enforced --");
+ s.append(softwareEnforced);
+ s.append("\n\n-- TEE enforced --");
+ s.append(teeEnforced);
+ s.append("\n");
+
+ return s.toString();
+ }
+
+ private ASN1Sequence getAttestationSequence(X509Certificate x509Cert)
+ throws CertificateParsingException {
+ byte[] attestationExtensionBytes = x509Cert.getExtensionValue(KEY_DESCRIPTION_OID);
+ if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
+ return null;
+ }
+ return Asn1Utils.getAsn1SequenceFromBytes(attestationExtensionBytes);
+ }
+
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationActivity.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationActivity.java
new file mode 100644
index 0000000..0fb8cf4
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationActivity.java
@@ -0,0 +1,21 @@
+package com.google.attestationexample;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class AttestationActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ runTests();
+ }
+
+ private void runTests() {
+ try {
+ new AttestationTest().execute();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationApplicationId.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationApplicationId.java
new file mode 100644
index 0000000..b0bd257
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationApplicationId.java
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+package com.google.attestationexample;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+
+import java.security.cert.CertificateParsingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
+
+public class AttestationApplicationId implements java.lang.Comparable<AttestationApplicationId> {
+ private static final int PACKAGE_INFOS_INDEX = 0;
+ private static final int SIGNATURE_DIGESTS_INDEX = 1;
+
+ private final List<AttestationPackageInfo> packageInfos;
+ private final List<byte[]> signatureDigests;
+
+ public AttestationApplicationId(Context context)
+ throws NoSuchAlgorithmException, NameNotFoundException {
+ PackageManager pm = context.getPackageManager();
+ int uid = context.getApplicationInfo().uid;
+ String[] packageNames = pm.getPackagesForUid(uid);
+ if (packageNames == null || packageNames.length == 0) {
+ throw new NameNotFoundException("No names found for uid");
+ }
+ packageInfos = new ArrayList<AttestationPackageInfo>();
+ for (String packageName : packageNames) {
+ // get the package info for the given package name including
+ // the signatures
+ PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+ packageInfos.add(new AttestationPackageInfo(packageName, packageInfo.versionCode));
+ }
+ // The infos must be sorted, the implementation of Comparable relies on it.
+ packageInfos.sort(null);
+
+ // compute the sha256 digests of the signature blobs
+ signatureDigests = new ArrayList<byte[]>();
+ PackageInfo packageInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
+ for (Signature signature : packageInfo.signatures) {
+ MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+ signatureDigests.add(sha256.digest(signature.toByteArray()));
+ }
+ // The digests must be sorted. the implementation of Comparable relies on it
+ signatureDigests.sort(new ByteArrayComparator());
+ }
+
+ public AttestationApplicationId(ASN1Encodable asn1Encodable)
+ throws CertificateParsingException {
+ if (!(asn1Encodable instanceof ASN1Sequence)) {
+ throw new CertificateParsingException(
+ "Expected sequence for AttestationApplicationId, found "
+ + asn1Encodable.getClass().getName());
+ }
+
+ ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+ packageInfos = parseAttestationPackageInfos(sequence.getObjectAt(PACKAGE_INFOS_INDEX));
+ // The infos must be sorted, the implementation of Comparable relies on it.
+ packageInfos.sort(null);
+ signatureDigests = parseSignatures(sequence.getObjectAt(SIGNATURE_DIGESTS_INDEX));
+ // The digests must be sorted. the implementation of Comparable relies on it
+ signatureDigests.sort(new ByteArrayComparator());
+ }
+
+ public List<AttestationPackageInfo> getAttestationPackageInfos() {
+ return packageInfos;
+ }
+
+ public List<byte[]> getSignatureDigests() {
+ return signatureDigests;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ int noOfInfos = packageInfos.size();
+ int i = 1;
+ for (AttestationPackageInfo info : packageInfos) {
+ sb.append("\n### Package info " + i + "/" + noOfInfos + " ###\n");
+ sb.append(info);
+ }
+ i = 1;
+ int noOfSigs = signatureDigests.size();
+ for (byte[] sig : signatureDigests) {
+ sb.append("\nSignature digest " + i++ + "/" + noOfSigs + ":");
+ for (byte b : sig) {
+ sb.append(String.format(" %02X", b));
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public int compareTo(AttestationApplicationId other) {
+ int res = Integer.compare(packageInfos.size(), other.packageInfos.size());
+ if (res != 0) return res;
+ for (int i = 0; i < packageInfos.size(); ++i) {
+ res = packageInfos.get(i).compareTo(other.packageInfos.get(i));
+ if (res != 0) return res;
+ }
+ res = Integer.compare(signatureDigests.size(), other.signatureDigests.size());
+ if (res != 0) return res;
+ ByteArrayComparator cmp = new ByteArrayComparator();
+ for (int i = 0; i < signatureDigests.size(); ++i) {
+ res = cmp.compare(signatureDigests.get(i), other.signatureDigests.get(i));
+ if (res != 0) return res;
+ }
+ return res;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof AttestationApplicationId)
+ && (0 == compareTo((AttestationApplicationId) o));
+ }
+
+ private List<AttestationPackageInfo> parseAttestationPackageInfos(ASN1Encodable asn1Encodable)
+ throws CertificateParsingException {
+ if (!(asn1Encodable instanceof ASN1Set)) {
+ throw new CertificateParsingException(
+ "Expected set for AttestationApplicationsInfos, found "
+ + asn1Encodable.getClass().getName());
+ }
+
+ ASN1Set set = (ASN1Set) asn1Encodable;
+ List<AttestationPackageInfo> result = new ArrayList<AttestationPackageInfo>();
+ for (ASN1Encodable e : set) {
+ result.add(new AttestationPackageInfo(e));
+ }
+ return result;
+ }
+
+ private List<byte[]> parseSignatures(ASN1Encodable asn1Encodable)
+ throws CertificateParsingException {
+ if (!(asn1Encodable instanceof ASN1Set)) {
+ throw new CertificateParsingException("Expected set for Signature digests, found "
+ + asn1Encodable.getClass().getName());
+ }
+
+ ASN1Set set = (ASN1Set) asn1Encodable;
+ List<byte[]> result = new ArrayList<byte[]>();
+
+ for (ASN1Encodable e : set) {
+ result.add(Asn1Utils.getByteArrayFromAsn1(e));
+ }
+ return result;
+ }
+
+ private class ByteArrayComparator implements java.util.Comparator<byte[]> {
+ @Override
+ public int compare(byte[] a, byte[] b) {
+ int res = Integer.compare(a.length, b.length);
+ if (res != 0) return res;
+ for (int i = 0; i < a.length; ++i) {
+ res = Byte.compare(a[i], b[i]);
+ if (res != 0) return res;
+ }
+ return res;
+ }
+ }
+}
\ No newline at end of file
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationPackageInfo.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationPackageInfo.java
new file mode 100644
index 0000000..3ccaf7a
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationPackageInfo.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+package com.google.attestationexample;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+
+import java.io.UnsupportedEncodingException;
+
+public class AttestationPackageInfo implements java.lang.Comparable<AttestationPackageInfo> {
+ private static final int PACKAGE_NAME_INDEX = 0;
+ private static final int VERSION_INDEX = 1;
+
+ private final String packageName;
+ private final int version;
+
+ public AttestationPackageInfo(String packageName, int version) {
+ this.packageName = packageName;
+ this.version = version;
+ }
+
+ public AttestationPackageInfo(ASN1Encodable asn1Encodable) throws CertificateParsingException {
+ if (!(asn1Encodable instanceof ASN1Sequence)) {
+ throw new CertificateParsingException(
+ "Expected sequence for AttestationPackageInfo, found "
+ + asn1Encodable.getClass().getName());
+ }
+
+ ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+ try {
+ packageName = Asn1Utils.getStringFromAsn1OctetStreamAssumingUTF8(
+ sequence.getObjectAt(PACKAGE_NAME_INDEX));
+ } catch (UnsupportedEncodingException e) {
+ throw new CertificateParsingException(
+ "Converting octet stream to String triggered an UnsupportedEncodingException",
+ e);
+ }
+ version = Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERSION_INDEX));
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder().append("Package name: ").append(getPackageName())
+ .append("\nVersion: " + getVersion()).toString();
+ }
+
+ @Override
+ public int compareTo(AttestationPackageInfo other) {
+ int res = packageName.compareTo(other.packageName);
+ if (res != 0) return res;
+ res = Integer.compare(version, other.version);
+ if (res != 0) return res;
+ return res;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof AttestationPackageInfo)
+ && (0 == compareTo((AttestationPackageInfo) o));
+ }
+}
\ No newline at end of file
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationTest.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationTest.java
new file mode 100644
index 0000000..287d065
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationTest.java
@@ -0,0 +1,317 @@
+package com.google.attestationexample;
+
+import android.os.AsyncTask;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Base64;
+import android.util.Log;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.io.ByteArrayInputStream;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static android.security.keystore.KeyProperties.DIGEST_SHA256;
+import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC;
+import static com.google.attestationexample.RootOfTrust.KM_VERIFIED_BOOT_VERIFIED;
+
+/**
+ * AttestationTest generates an EC Key pair, with attestation, and displays the result in the
+ * TextView provided to its constructor.
+ */
+public class AttestationTest extends AsyncTask<Void, String, Void> {
+ private static final int ORIGINATION_TIME_OFFSET = 1000000;
+ private static final int CONSUMPTION_TIME_OFFSET = 2000000;
+
+ private static final int KEY_USAGE_BITSTRING_LENGTH = 9;
+ private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0;
+ private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2;
+ private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3;
+
+ private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1;
+ private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2;
+ private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3;
+ private static final Pattern OS_VERSION_STRING_PATTERN = Pattern
+ .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?");
+
+ private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1;
+ private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2;
+ private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern
+ .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
+
+ private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
+
+ private static final String FINISHED = "AttestationFinished";
+ private static final String FAIL = "AttestationFail";
+ private static final String INFO = "AttestationInfo";
+ private static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";
+ private static final String KEY_USAGE_OID = "2.5.29.15"; // Standard key usage extension.
+
+ private static final String GOOGLE_ROOT_CERTIFICATE =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV"
+ + "BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy"
+ + "ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B"
+ + "AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS"
+ + "Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7"
+ + "tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj"
+ + "nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq"
+ + "C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ"
+ + "oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O"
+ + "JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg"
+ + "sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi"
+ + "igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M"
+ + "RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E"
+ + "aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um"
+ + "AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD"
+ + "VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO"
+ + "BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk"
+ + "Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD"
+ + "ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB"
+ + "Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m"
+ + "qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY"
+ + "DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm"
+ + "QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u"
+ + "JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD"
+ + "CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy"
+ + "ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD"
+ + "qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic"
+ + "MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1"
+ + "wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk\n"
+ + "-----END CERTIFICATE-----";
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ try {
+ testEcAttestation();
+ } catch (Exception e) {
+ Log.e(FAIL, "Something is wrong, check detailed logcat logs:\n", e);
+ }
+ return null;
+ }
+
+ private void testEcAttestation() throws Exception {
+ String ecCurve = "secp256r1";
+ int keySize = 256;
+ byte[] challenge = "challenge".getBytes();
+ String keystoreAlias = "test_key";
+
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ keyStore.deleteEntry(keystoreAlias);
+
+ Log.d(INFO,"Generating key pair...");
+ Date startTime = new Date(new Date().getTime() - 1000);
+ Log.d("****", "Start Time is: " + startTime.toString());
+ Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET);
+ Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET);
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias,
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve))
+ .setDigests(DIGEST_SHA256)
+ .setAttestationChallenge(challenge);
+
+ builder.setKeyValidityStart(startTime)
+ .setKeyValidityForOriginationEnd(originationEnd)
+ .setKeyValidityForConsumptionEnd(consumptionEnd);
+
+ generateKeyPair(KEY_ALGORITHM_EC, builder.build());
+ Log.d(INFO, "Key pair generated\n\n");
+
+ Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
+ Log.d(INFO, "Retrieved certificate chain of length " + certificates.length + "\n");
+ try {
+ verifyCertificateSignatures(certificates);
+ } catch (GeneralSecurityException e) {
+ Log.e(FAIL, "Certificate chain does not verify.", e);
+ }
+
+ X509Certificate attestationCert = (X509Certificate) certificates[0];
+ X509Certificate secureRoot = (X509Certificate) CertificateFactory
+ .getInstance("X.509").generateCertificate(
+ new ByteArrayInputStream(
+ GOOGLE_ROOT_CERTIFICATE.getBytes()));
+ X509Certificate rootCert = (X509Certificate) certificates[certificates.length - 1];
+ if (!Arrays.equals(secureRoot.getPublicKey().getEncoded(),
+ rootCert.getPublicKey().getEncoded())) {
+ Log.e(FAIL, "root certificate public key does not match Google public key");
+ }
+ printKeyUsage(attestationCert);
+
+ ImmutableSet<String> unexpectedExtensionOids =
+ (ImmutableSet) retrieveUnexpectedExtensionOids(attestationCert);
+ if (!unexpectedExtensionOids.isEmpty()) {
+ Log.e(FAIL, "attestation certificate contains unexpected OIDs");
+ for (String oid : unexpectedExtensionOids.toArray(new String[unexpectedExtensionOids.size()])) {
+ Log.e(FAIL, "Unexpected OID: " + oid);
+ }
+ }
+
+ Attestation attestation = new Attestation(attestationCert);
+ if (!Arrays.equals(attestation.getAttestationChallenge(), challenge)) {
+ Utils.logError("challenge mismatch\nExpected:",
+ challenge, attestation.getAttestationChallenge());
+ }
+
+ if (attestation.getAttestationSecurityLevel() != 1) {
+ Utils.logError("Attestation cert reporting non-TEE security level",
+ 1, attestation.getAttestationSecurityLevel());
+ }
+ if (attestation.getKeymasterSecurityLevel() != 1) {
+ Utils.logError("Keymaster reporting non-TEE security level",
+ 1, attestation.getKeymasterSecurityLevel());
+ }
+
+ checkRootOfTrust(attestation);
+
+ Signature signer = Signature.getInstance("SHA256WithECDSA");
+ KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
+ keystore.load(null);
+
+ PrivateKey key = (PrivateKey) keystore.getKey(keystoreAlias, null);
+ try {
+ signer.initSign(key);
+ signer.update("Hello".getBytes());
+ signer.sign();
+ } catch(Exception e) {
+ Log.e(FAIL,"Failed to sign with generated key", e);
+ }
+ Log.d(FINISHED, "Signing completed");
+ }
+
+ private void generateKeyPair(String algorithm, KeyGenParameterSpec spec)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidAlgorithmParameterException {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm,
+ "AndroidKeyStore");
+ keyPairGenerator.initialize(spec);
+ keyPairGenerator.generateKeyPair();
+ }
+
+ private void verifyCertificateSignatures(Certificate[] certChain)
+ throws GeneralSecurityException {
+
+ for (Certificate cert : certChain) {
+ final byte[] derCert = cert.getEncoded();
+ final String pemCertPre = Base64.encodeToString(derCert, Base64.NO_WRAP);
+ Log.e("****", pemCertPre);
+ }
+
+ for (int i = 1; i < certChain.length; ++i) {
+ PublicKey pubKey = certChain[i].getPublicKey();
+ try {
+ certChain[i - 1].verify(pubKey);
+ } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException
+ | NoSuchProviderException | SignatureException e) {
+ throw new GeneralSecurityException("Failed to verify certificate "
+ + certChain[i - 1] + " with public key " + certChain[i].getPublicKey(), e);
+ }
+ if (i == certChain.length - 1) {
+ // Last cert is self-signed.
+ try {
+ certChain[i].verify(pubKey);
+ } catch (CertificateException e) {
+ throw new GeneralSecurityException(
+ "Root cert " + certChain[i] + " is not correctly self-signed", e);
+ }
+ }
+ }
+ }
+
+ private void printKeyUsage(X509Certificate attestationCert) {
+ Log.d(INFO, "Key usage:");
+ if (attestationCert.getKeyUsage() == null) {
+ Log.d(INFO, " NONE\n");
+ return;
+ }
+ if (attestationCert.getKeyUsage()[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET]) {
+ Log.d(INFO, " sign");
+ }
+ if (attestationCert.getKeyUsage()[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET]) {
+ Log.d(INFO, " encrypt_data");
+ }
+ if (attestationCert.getKeyUsage()[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET]) {
+ Log.d(INFO, " encrypt_keys");
+ }
+ Log.d(INFO, "\n");
+ }
+
+ private Set<String> retrieveUnexpectedExtensionOids(X509Certificate x509Cert) {
+ return new ImmutableSet.Builder<String>()
+ .addAll(x509Cert.getCriticalExtensionOIDs()
+ .stream()
+ .filter(s -> !KEY_USAGE_OID.equals(s))
+ .iterator())
+ .addAll(x509Cert.getNonCriticalExtensionOIDs()
+ .stream()
+ .filter(s -> !KEY_DESCRIPTION_OID.equals(s))
+ .iterator())
+ .build();
+ }
+
+
+ private void checkRootOfTrust(Attestation attestation) {
+ RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
+ if (rootOfTrust == null) {
+ Log.e(FAIL, "Root of trust is null");
+ return;
+ }
+ if (rootOfTrust.getVerifiedBootKey() == null) {
+ Log.e(FAIL, "Verified boot key is null");
+ return;
+ }
+ if (rootOfTrust.getVerifiedBootKey().length < 32) {
+ Log.e(FAIL, "Verified boot key is less than 32 bytes");
+ }
+ if (isAllZeroes(rootOfTrust.getVerifiedBootKey())) {
+ Log.e(FAIL, "Verified boot key is all zeros.");
+ }
+ if (!rootOfTrust.isDeviceLocked()) {
+ Log.e(FAIL, "Device isn't locked");
+ }
+ if (KM_VERIFIED_BOOT_VERIFIED != rootOfTrust.getVerifiedBootState()) {
+ Utils.logError("Root of trust isn't reporting boot verified.",
+ KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
+ }
+ if (rootOfTrust.getVerifiedBootHash() == null) {
+ Log.e(FAIL, "Verified boot hash is null");
+ return;
+ }
+ if (rootOfTrust.getVerifiedBootHash().length != 32) {
+ Log.e(FAIL, "Verified boot hash isn't 32 bytes");
+ }
+ if (isAllZeroes(rootOfTrust.getVerifiedBootHash())) {
+ Log.e(FAIL, "Verified boot hash is all zeros.");
+ }
+ }
+
+ private boolean isAllZeroes(byte[] checkArray) {
+ for (byte b : checkArray) {
+ if (b != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AuthorizationList.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AuthorizationList.java
new file mode 100644
index 0000000..29b317e
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AuthorizationList.java
@@ -0,0 +1,610 @@
+/*
+ * 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.
+ */
+
+package com.google.attestationexample;
+
+import android.security.keystore.KeyProperties;
+import android.util.Log;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1SequenceParser;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+
+import java.io.IOException;
+import java.security.cert.CertificateParsingException;
+import java.text.DateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.base.Functions.forMap;
+import static com.google.common.collect.Collections2.transform;
+
+public class AuthorizationList {
+ // Algorithm values.
+ public static final int KM_ALGORITHM_RSA = 1;
+ public static final int KM_ALGORITHM_EC = 3;
+
+ // EC Curves
+ public static final int KM_EC_CURVE_P224 = 0;
+ public static final int KM_EC_CURVE_P256 = 1;
+ public static final int KM_EC_CURVE_P384 = 2;
+ public static final int KM_EC_CURVE_P521 = 3;
+
+ // Padding modes.
+ public static final int KM_PAD_NONE = 1;
+ public static final int KM_PAD_RSA_OAEP = 2;
+ public static final int KM_PAD_RSA_PSS = 3;
+ public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
+ public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
+
+ // Digest modes.
+ public static final int KM_DIGEST_NONE = 0;
+ public static final int KM_DIGEST_MD5 = 1;
+ public static final int KM_DIGEST_SHA1 = 2;
+ public static final int KM_DIGEST_SHA_2_224 = 3;
+ public static final int KM_DIGEST_SHA_2_256 = 4;
+ public static final int KM_DIGEST_SHA_2_384 = 5;
+ public static final int KM_DIGEST_SHA_2_512 = 6;
+
+ // Key origins.
+ public static final int KM_ORIGIN_GENERATED = 0;
+ public static final int KM_ORIGIN_IMPORTED = 2;
+ public static final int KM_ORIGIN_UNKNOWN = 3;
+
+ // Operation Purposes.
+ public static final int KM_PURPOSE_ENCRYPT = 0;
+ public static final int KM_PURPOSE_DECRYPT = 1;
+ public static final int KM_PURPOSE_SIGN = 2;
+ public static final int KM_PURPOSE_VERIFY = 3;
+ public static final int KM_PURPOSE_DERIVE_KEY = 4;
+ public static final int KM_PURPOSE_WRAP_KEY = 5;
+
+ // User authenticators.
+ public static final int HW_AUTH_PASSWORD = 1 << 0;
+ public static final int HW_AUTH_FINGERPRINT = 1 << 1;
+
+ // Keymaster tag classes
+ private static final int KM_ENUM = 1 << 28;
+ private static final int KM_ENUM_REP = 2 << 28;
+ private static final int KM_UINT = 3 << 28;
+ private static final int KM_ULONG = 5 << 28;
+ private static final int KM_DATE = 6 << 28;
+ private static final int KM_BOOL = 7 << 28;
+ private static final int KM_BYTES = 9 << 28;
+
+ // Tag class removal mask
+ private static final int KEYMASTER_TAG_TYPE_MASK = 0x0FFFFFFF;
+
+ // Keymaster tags
+ private static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
+ private static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
+ private static final int KM_TAG_KEY_SIZE = KM_UINT | 3;
+ private static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
+ private static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
+ private static final int KM_TAG_EC_CURVE = KM_ENUM | 10;
+ private static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200;
+ private static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
+ private static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
+ private static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
+ private static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
+ private static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
+ private static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
+ private static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
+ private static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
+ private static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
+ private static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
+ private static final int KM_TAG_ORIGIN = KM_ENUM | 702;
+ private static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
+ private static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
+ private static final int KM_TAG_OS_VERSION = KM_UINT | 705;
+ private static final int KM_TAG_OS_PATCHLEVEL = KM_UINT | 706;
+ private static final int KM_TAG_ATTESTATION_APPLICATION_ID = KM_BYTES | 709;
+ private static final int KM_TAG_VENDOR_PATCHLEVEL = KM_UINT | 718;
+ private static final int KM_TAG_BOOT_PATCHLEVEL = KM_UINT | 719;
+
+ // Map for converting padding values to strings
+ private static final ImmutableMap<Integer, String> paddingMap = ImmutableMap
+ .<Integer, String> builder()
+ .put(KM_PAD_NONE, "NONE")
+ .put(KM_PAD_RSA_OAEP, "OAEP")
+ .put(KM_PAD_RSA_PSS, "PSS")
+ .put(KM_PAD_RSA_PKCS1_1_5_ENCRYPT, "PKCS1 ENCRYPT")
+ .put(KM_PAD_RSA_PKCS1_1_5_SIGN, "PKCS1 SIGN")
+ .build();
+
+ // Map for converting digest values to strings
+ private static final ImmutableMap<Integer, String> digestMap = ImmutableMap
+ .<Integer, String> builder()
+ .put(KM_DIGEST_NONE, "NONE")
+ .put(KM_DIGEST_MD5, "MD5")
+ .put(KM_DIGEST_SHA1, "SHA1")
+ .put(KM_DIGEST_SHA_2_224, "SHA224")
+ .put(KM_DIGEST_SHA_2_256, "SHA256")
+ .put(KM_DIGEST_SHA_2_384, "SHA384")
+ .put(KM_DIGEST_SHA_2_512, "SHA512")
+ .build();
+
+ // Map for converting purpose values to strings
+ private static final ImmutableMap<Integer, String> purposeMap = ImmutableMap
+ .<Integer, String> builder()
+ .put(KM_PURPOSE_DECRYPT, "DECRYPT")
+ .put(KM_PURPOSE_ENCRYPT, "ENCRYPT")
+ .put(KM_PURPOSE_SIGN, "SIGN")
+ .put(KM_PURPOSE_VERIFY, "VERIFY")
+ .build();
+
+ private Set<Integer> purposes;
+ private Integer algorithm;
+ private Integer keySize;
+ private Set<Integer> digests;
+ private Set<Integer> paddingModes;
+ private Integer ecCurve;
+ private Long rsaPublicExponent;
+ private Date activeDateTime;
+ private Date originationExpireDateTime;
+ private Date usageExpireDateTime;
+ private boolean noAuthRequired;
+ private Integer userAuthType;
+ private Integer authTimeout;
+ private boolean allowWhileOnBody;
+ private boolean allApplications;
+ private byte[] applicationId;
+ private Date creationDateTime;
+ private Integer origin;
+ private boolean rollbackResistant;
+ private RootOfTrust rootOfTrust;
+ private Integer osVersion;
+ private Integer osPatchLevel;
+ private Integer vendorPatchLevel;
+ private Integer bootPatchLevel;
+ private AttestationApplicationId attestationApplicationId;
+
+ public AuthorizationList(ASN1Encodable sequence) throws CertificateParsingException {
+ if (!(sequence instanceof ASN1Sequence)) {
+ throw new CertificateParsingException("Expected sequence for authorization list, found "
+ + sequence.getClass().getName());
+ }
+
+ ASN1SequenceParser parser = ((ASN1Sequence) sequence).parser();
+ ASN1TaggedObject entry = parseAsn1TaggedObject(parser);
+ for (; entry != null; entry = parseAsn1TaggedObject(parser)) {
+ int tag = entry.getTagNo();
+ ASN1Primitive value = entry.getObject();
+ Log.i("Attestation", "Parsing tag: [" + tag + "], value: [" + value + "]");
+ switch (tag) {
+ default:
+ throw new CertificateParsingException("Unknown tag " + tag + " found");
+
+ case KM_TAG_PURPOSE & KEYMASTER_TAG_TYPE_MASK:
+ purposes = Asn1Utils.getIntegersFromAsn1Set(value);
+ break;
+ case KM_TAG_ALGORITHM & KEYMASTER_TAG_TYPE_MASK:
+ algorithm = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_KEY_SIZE & KEYMASTER_TAG_TYPE_MASK:
+ keySize = Asn1Utils.getIntegerFromAsn1(value);
+ Log.i("Attestation", "Found KEY SIZE, value: " + keySize);
+ break;
+ case KM_TAG_DIGEST & KEYMASTER_TAG_TYPE_MASK:
+ digests = Asn1Utils.getIntegersFromAsn1Set(value);
+ break;
+ case KM_TAG_PADDING & KEYMASTER_TAG_TYPE_MASK:
+ paddingModes = Asn1Utils.getIntegersFromAsn1Set(value);
+ break;
+ case KM_TAG_RSA_PUBLIC_EXPONENT & KEYMASTER_TAG_TYPE_MASK:
+ rsaPublicExponent = Asn1Utils.getLongFromAsn1(value);
+ break;
+ case KM_TAG_NO_AUTH_REQUIRED & KEYMASTER_TAG_TYPE_MASK:
+ noAuthRequired = true;
+ break;
+ case KM_TAG_CREATION_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+ creationDateTime = Asn1Utils.getDateFromAsn1(value);
+ break;
+ case KM_TAG_ORIGIN & KEYMASTER_TAG_TYPE_MASK:
+ origin = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_OS_VERSION & KEYMASTER_TAG_TYPE_MASK:
+ osVersion = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_OS_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
+ osPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_VENDOR_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
+ vendorPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_BOOT_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
+ bootPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_ACTIVE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+ activeDateTime = Asn1Utils.getDateFromAsn1(value);
+ break;
+ case KM_TAG_ORIGINATION_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+ originationExpireDateTime = Asn1Utils.getDateFromAsn1(value);
+ break;
+ case KM_TAG_USAGE_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+ usageExpireDateTime = Asn1Utils.getDateFromAsn1(value);
+ break;
+ case KM_TAG_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK:
+ applicationId = Asn1Utils.getByteArrayFromAsn1(value);
+ break;
+ case KM_TAG_ROLLBACK_RESISTANT & KEYMASTER_TAG_TYPE_MASK:
+ rollbackResistant = true;
+ break;
+ case KM_TAG_AUTH_TIMEOUT & KEYMASTER_TAG_TYPE_MASK:
+ authTimeout = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_ALLOW_WHILE_ON_BODY & KEYMASTER_TAG_TYPE_MASK:
+ allowWhileOnBody = true;
+ break;
+ case KM_TAG_EC_CURVE & KEYMASTER_TAG_TYPE_MASK:
+ ecCurve = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_USER_AUTH_TYPE & KEYMASTER_TAG_TYPE_MASK:
+ userAuthType = Asn1Utils.getIntegerFromAsn1(value);
+ break;
+ case KM_TAG_ROOT_OF_TRUST & KEYMASTER_TAG_TYPE_MASK:
+ try {
+ rootOfTrust = new RootOfTrust(value);
+ } catch (CertificateParsingException e) {
+ Log.e("AttestationFail", "Root of trust parsing failure" + e);
+ rootOfTrust = null;
+ }
+ break;
+ case KM_TAG_ATTESTATION_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK:
+ attestationApplicationId = new AttestationApplicationId(Asn1Utils
+ .getAsn1EncodableFromBytes(Asn1Utils.getByteArrayFromAsn1(value)));
+ break;
+ case KM_TAG_ALL_APPLICATIONS & KEYMASTER_TAG_TYPE_MASK:
+ allApplications = true;
+ break;
+ }
+ }
+
+ }
+
+ public static String algorithmToString(int algorithm) {
+ switch (algorithm) {
+ case KM_ALGORITHM_RSA:
+ return "RSA";
+ case KM_ALGORITHM_EC:
+ return "ECDSA";
+ default:
+ return "Unknown";
+ }
+ }
+
+ public static String paddingModesToString(final Set<Integer> paddingModes) {
+ return joinStrings(transform(paddingModes, forMap(paddingMap, "Unknown")));
+ }
+
+ public static String paddingModeToString(int paddingMode) {
+ return forMap(paddingMap, "Unknown").apply(paddingMode);
+ }
+
+ public static String digestsToString(Set<Integer> digests) {
+ return joinStrings(transform(digests, forMap(digestMap, "Unknown")));
+ }
+
+ public static String digestToString(int digest) {
+ return forMap(digestMap, "Unknown").apply(digest);
+ }
+
+ public static String purposesToString(Set<Integer> purposes) {
+ return joinStrings(transform(purposes, forMap(purposeMap, "Unknown")));
+ }
+
+ public static String userAuthTypeToString(int userAuthType) {
+ List<String> types = Lists.newArrayList();
+ if ((userAuthType & HW_AUTH_FINGERPRINT) != 0)
+ types.add("Fingerprint");
+ if ((userAuthType & HW_AUTH_PASSWORD) != 0)
+ types.add("Password");
+ return joinStrings(types);
+ }
+
+ public static String originToString(int origin) {
+ switch (origin) {
+ case KM_ORIGIN_GENERATED:
+ return "Generated";
+ case KM_ORIGIN_IMPORTED:
+ return "Imported";
+ case KM_ORIGIN_UNKNOWN:
+ return "Unknown (KM0)";
+ default:
+ return "Unknown";
+ }
+ }
+
+ private static String joinStrings(Collection<String> collection) {
+ return new StringBuilder()
+ .append("[")
+ .append(Joiner.on(", ").join(collection))
+ .append("]")
+ .toString();
+ }
+
+ private static String formatDate(Date date) {
+ return DateFormat.getDateTimeInstance().format(date);
+ }
+
+ private static ASN1TaggedObject parseAsn1TaggedObject(ASN1SequenceParser parser)
+ throws CertificateParsingException {
+ ASN1Encodable asn1Encodable = parseAsn1Encodable(parser);
+ if (asn1Encodable == null || asn1Encodable instanceof ASN1TaggedObject) {
+ return (ASN1TaggedObject) asn1Encodable;
+ }
+ throw new CertificateParsingException(
+ "Expected tagged object, found " + asn1Encodable.getClass().getName());
+ }
+
+ private static ASN1Encodable parseAsn1Encodable(ASN1SequenceParser parser)
+ throws CertificateParsingException {
+ try {
+ return parser.readObject();
+ } catch (IOException e) {
+ throw new CertificateParsingException("Failed to parse ASN1 sequence", e);
+ }
+ }
+
+ public Set<Integer> getPurposes() {
+ return purposes;
+ }
+
+ public Integer getAlgorithm() {
+ return algorithm;
+ }
+
+ public Integer getKeySize() {
+ return keySize;
+ }
+
+ public Set<Integer> getDigests() {
+ return digests;
+ }
+
+ public Set<Integer> getPaddingModes() {
+ return paddingModes;
+ }
+
+ public Set<String> getPaddingModesAsStrings() throws CertificateParsingException {
+ if (paddingModes == null) {
+ return ImmutableSet.of();
+ }
+
+ ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+ for (int paddingMode : paddingModes) {
+ switch (paddingMode) {
+ case KM_PAD_NONE:
+ builder.add(KeyProperties.ENCRYPTION_PADDING_NONE);
+ break;
+ case KM_PAD_RSA_OAEP:
+ builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
+ break;
+ case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+ builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+ break;
+ case KM_PAD_RSA_PKCS1_1_5_SIGN:
+ builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+ break;
+ case KM_PAD_RSA_PSS:
+ builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+ break;
+ default:
+ throw new CertificateParsingException("Invalid padding mode " + paddingMode);
+ }
+ }
+ return builder.build();
+ }
+
+ public Integer getEcCurve() {
+ return ecCurve;
+ }
+
+ public String ecCurveAsString() {
+ if (ecCurve == null)
+ return "NULL";
+
+ switch (ecCurve) {
+ case KM_EC_CURVE_P224:
+ return "secp224r1";
+ case KM_EC_CURVE_P256:
+ return "secp256r1";
+ case KM_EC_CURVE_P384:
+ return "secp384r1";
+ case KM_EC_CURVE_P521:
+ return "secp521r1";
+ default:
+ return "unknown";
+ }
+ }
+
+ public Long getRsaPublicExponent() {
+ return rsaPublicExponent;
+ }
+
+ public Date getActiveDateTime() {
+ return activeDateTime;
+ }
+
+ public Date getOriginationExpireDateTime() {
+ return originationExpireDateTime;
+ }
+
+ public Date getUsageExpireDateTime() {
+ return usageExpireDateTime;
+ }
+
+ public boolean isNoAuthRequired() {
+ return noAuthRequired;
+ }
+
+ public Integer getUserAuthType() {
+ return userAuthType;
+ }
+
+ public Integer getAuthTimeout() {
+ return authTimeout;
+ }
+
+ public boolean isAllowWhileOnBody() {
+ return allowWhileOnBody;
+ }
+
+ public boolean isAllApplications() {
+ return allApplications;
+ }
+
+ public byte[] getApplicationId() {
+ return applicationId;
+ }
+
+ public Date getCreationDateTime() {
+ return creationDateTime;
+ }
+
+ public Integer getOrigin() {
+ return origin;
+ }
+
+ public boolean isRollbackResistant() {
+ return rollbackResistant;
+ }
+
+ public RootOfTrust getRootOfTrust() {
+ return rootOfTrust;
+ }
+
+ public Integer getOsVersion() {
+ return osVersion;
+ }
+
+ public Integer getOsPatchLevel() {
+ return osPatchLevel;
+ }
+
+ public Integer getVendorPatchLevel() { return vendorPatchLevel; }
+
+ public Integer getBootPatchLevel() { return bootPatchLevel; }
+
+ public AttestationApplicationId getAttestationApplicationId() {
+ return attestationApplicationId;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+
+ if (algorithm != null) {
+ s.append("\nAlgorithm: ").append(algorithmToString(algorithm));
+ }
+
+ if (keySize != null) {
+ s.append("\nKeySize: ").append(keySize);
+ }
+
+ if (purposes != null && !purposes.isEmpty()) {
+ s.append("\nPurposes: ").append(purposesToString(purposes));
+ }
+
+ if (digests != null && !digests.isEmpty()) {
+ s.append("\nDigests: ").append(digestsToString(digests));
+ }
+
+ if (paddingModes != null && !paddingModes.isEmpty()) {
+ s.append("\nPadding modes: ").append(paddingModesToString(paddingModes));
+ }
+
+ if (ecCurve != null) {
+ s.append("\nEC Curve: ").append(ecCurveAsString());
+ }
+
+ String label = "\nRSA exponent: ";
+ if (rsaPublicExponent != null) {
+ s.append(label).append(rsaPublicExponent);
+ }
+
+ if (activeDateTime != null) {
+ s.append("\nActive: ").append(formatDate(activeDateTime));
+ }
+
+ if (originationExpireDateTime != null) {
+ s.append("\nOrigination expire: ").append(formatDate(originationExpireDateTime));
+ }
+
+ if (usageExpireDateTime != null) {
+ s.append("\nUsage expire: ").append(formatDate(usageExpireDateTime));
+ }
+
+ if (!noAuthRequired && userAuthType != null) {
+ s.append("\nAuth types: ").append(userAuthTypeToString(userAuthType));
+ if (authTimeout != null) {
+ s.append("\nAuth timeout: ").append(authTimeout);
+ }
+ }
+
+ if (applicationId != null) {
+ s.append("\nApplication ID: ").append(new String(applicationId));
+ }
+
+ if (creationDateTime != null) {
+ s.append("\nCreated: ").append(formatDate(creationDateTime));
+ }
+
+ if (origin != null) {
+ s.append("\nOrigin: ").append(originToString(origin));
+ }
+
+ if (rollbackResistant) {
+ s.append("\nRollback resistant: true");
+ }
+
+ if (rootOfTrust != null) {
+ s.append("\nRoot of Trust:\n");
+ s.append(rootOfTrust);
+ }
+
+ if (osVersion != null) {
+ s.append("\nOS Version: ").append(osVersion);
+ }
+
+ if (osPatchLevel != null) {
+ s.append("\nOS Patchlevel: ").append(osPatchLevel);
+ }
+
+ if (vendorPatchLevel != null) {
+ s.append("\nVendor Patchlevel: ").append(vendorPatchLevel);
+ }
+
+ if (bootPatchLevel != null) {
+ s.append("\nBoot Patchlevel: ").append(bootPatchLevel);
+ }
+
+ if (attestationApplicationId != null) {
+ s.append("\nApplication ID:").append(attestationApplicationId.toString());
+ }
+
+ return s.toString();
+ }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/RootOfTrust.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/RootOfTrust.java
new file mode 100644
index 0000000..7821a94
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/RootOfTrust.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package com.google.attestationexample;
+
+import com.google.common.io.BaseEncoding;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+
+public class RootOfTrust {
+ private static final int VERIFIED_BOOT_KEY_INDEX = 0;
+ private static final int DEVICE_LOCKED_INDEX = 1;
+ private static final int VERIFIED_BOOT_STATE_INDEX = 2;
+ private static final int VERIFIED_BOOT_HASH_INDEX = 3;
+
+ public static final int KM_VERIFIED_BOOT_VERIFIED = 0;
+ public static final int KM_VERIFIED_BOOT_SELF_SIGNED = 1;
+ public static final int KM_VERIFIED_BOOT_UNVERIFIED = 2;
+ public static final int KM_VERIFIED_BOOT_FAILED = 3;
+
+ private final byte[] verifiedBootKey;
+ private final byte[] verifiedBootHash;
+ private final boolean deviceLocked;
+ private final int verifiedBootState;
+
+ public RootOfTrust(ASN1Encodable asn1Encodable) throws CertificateParsingException {
+ if (!(asn1Encodable instanceof ASN1Sequence)) {
+ throw new CertificateParsingException("Expected sequence for root of trust, found "
+ + asn1Encodable.getClass().getName());
+ }
+
+ ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+ if (sequence.size() != 4) {
+ throw new CertificateParsingException(
+ "Incorrect size, actual size is:" + sequence.size());
+ }
+ verifiedBootKey =
+ Asn1Utils.getByteArrayFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_KEY_INDEX));
+ deviceLocked = Asn1Utils.getBooleanFromAsn1(sequence.getObjectAt(DEVICE_LOCKED_INDEX));
+ verifiedBootState =
+ Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_STATE_INDEX));
+ verifiedBootHash =
+ Asn1Utils.getByteArrayFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_HASH_INDEX));
+ }
+
+ public static String verifiedBootStateToString(int verifiedBootState) {
+ switch (verifiedBootState) {
+ case KM_VERIFIED_BOOT_VERIFIED:
+ return "Verified";
+ case KM_VERIFIED_BOOT_SELF_SIGNED:
+ return "Self-signed";
+ case KM_VERIFIED_BOOT_UNVERIFIED:
+ return "Unverified";
+ case KM_VERIFIED_BOOT_FAILED:
+ return "Failed";
+ default:
+ return "Unknown";
+ }
+ }
+
+ public byte[] getVerifiedBootKey() {
+ return verifiedBootKey;
+ }
+
+ public boolean isDeviceLocked() {
+ return deviceLocked;
+ }
+
+ public int getVerifiedBootState() {
+ return verifiedBootState;
+ }
+
+ public byte[] getVerifiedBootHash() { return verifiedBootHash; }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("Verified boot Key: ")
+ .append(BaseEncoding.base64().encode(verifiedBootKey))
+ .append("\nDevice locked: ")
+ .append(deviceLocked)
+ .append("\nVerified boot state: ")
+ .append(verifiedBootStateToString(verifiedBootState))
+ .append("\nVerified boot hash: ")
+ .append(BaseEncoding.base64().encode(verifiedBootHash))
+ .toString();
+ }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/Utils.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Utils.java
new file mode 100644
index 0000000..e13d8a8
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Utils.java
@@ -0,0 +1,22 @@
+package com.google.attestationexample;
+
+import android.util.Log;
+
+import java.util.Arrays;
+
+public class Utils {
+ public static final String FAIL = "AttestationFail";
+ public static final String FAIL_INFO = "AttestationFailInfo";
+
+ public static void logError(String message, int expected, int actual) {
+ Log.e(FAIL, message);
+ Log.e(FAIL_INFO, "Expected: " + expected);
+ Log.e(FAIL_INFO, "Actual: " + actual);
+ }
+
+ public static void logError(String message, byte[] expected, byte[] actual) {
+ Log.e(FAIL, message);
+ Log.e(FAIL_INFO, "Expected: " + Arrays.toString(expected));
+ Log.e(FAIL_INFO, "Actual: " + Arrays.toString(actual));
+ }
+}
diff --git a/remote_provisioning/attestation_testing/res/layout/activity_attestation.xml b/remote_provisioning/attestation_testing/res/layout/activity_attestation.xml
new file mode 100644
index 0000000..4aaffed
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/layout/activity_attestation.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
+ tools:context="com.google.attestationexample.AttestationActivity">
+
+ <android.support.design.widget.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="@style/AppTheme.AppBarOverlay">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+ </android.support.design.widget.AppBarLayout>
+
+ <include layout="@layout/content_attestation" />
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_margin="@dimen/fab_margin"
+ app:srcCompat="@android:drawable/btn_star_big_on" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/remote_provisioning/attestation_testing/res/layout/content_attestation.xml b/remote_provisioning/attestation_testing/res/layout/content_attestation.xml
new file mode 100644
index 0000000..9759ef2
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/layout/content_attestation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/content_attestation"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ tools:context="com.google.attestationexample.AttestationActivity"
+ tools:showIn="@layout/activity_attestation">
+
+ <TextView
+ android:id="@+id/textview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="10000"
+ android:scrollbars="vertical"
+ android:text=""
+ android:scrollbarAlwaysDrawVerticalTrack="false"
+ android:scrollbarAlwaysDrawHorizontalTrack="false"
+ android:scrollHorizontally="false" />
+</RelativeLayout>
diff --git a/remote_provisioning/attestation_testing/res/menu/menu_attestation.xml b/remote_provisioning/attestation_testing/res/menu/menu_attestation.xml
new file mode 100644
index 0000000..9a34152
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/menu/menu_attestation.xml
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="com.google.attestationexample.AttestationActivity">
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:title="@string/action_settings"
+ app:showAsAction="never" />
+</menu>
diff --git a/remote_provisioning/attestation_testing/res/mipmap-hdpi/ic_launcher.png b/remote_provisioning/attestation_testing/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/remote_provisioning/attestation_testing/res/values-v21/styles.xml b/remote_provisioning/attestation_testing/res/values-v21/styles.xml
new file mode 100644
index 0000000..dbbdd40
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values-v21/styles.xml
@@ -0,0 +1,9 @@
+<resources>
+
+ <style name="AppTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ </style>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values-w820dp/dimens.xml b/remote_provisioning/attestation_testing/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/colors.xml b/remote_provisioning/attestation_testing/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/dimens.xml b/remote_provisioning/attestation_testing/res/values/dimens.xml
new file mode 100644
index 0000000..812cb7b
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/strings.xml b/remote_provisioning/attestation_testing/res/values/strings.xml
new file mode 100644
index 0000000..e6cb24b
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+ <string name="app_name">AttestationExample</string>
+ <string name="action_settings">Settings</string>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/styles.xml b/remote_provisioning/attestation_testing/res/values/styles.xml
new file mode 100644
index 0000000..545b9c6
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+ <style name="AppTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+ <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/sanitizer-status/Android.bp b/sanitizer-status/Android.bp
index 86501df..74f863c 100644
--- a/sanitizer-status/Android.bp
+++ b/sanitizer-status/Android.bp
@@ -1,37 +1,31 @@
-cc_defaults {
- name: "sanitizer-status_defaults",
+package {
+ default_applicable_licenses: ["tools_security_sanitizer-status_license"],
+}
- c_std: "c11",
+// Added automatically by a large-scale-change
+// http://go/android-license-faq
+license {
+ name: "tools_security_sanitizer-status_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
+cc_binary {
+ name: "sanitizer-status",
+
+ srcs: ["sanitizer-status.cpp"],
cflags: [
"-Wall",
"-Werror",
"-O0",
],
-}
-sanitizer_status_library_shared {
- name: "libsanitizer-status",
- defaults: ["sanitizer-status_defaults"],
-
- srcs: ["sanitizer-status.c"],
-}
-
-cc_binary {
- name: "sanitizer-status",
- defaults: ["sanitizer-status_defaults"],
-
- srcs: ["main.c"],
- shared_libs: ["libsanitizer-status"],
-}
-
-bootstrap_go_package {
- name: "soong-sanitizer_status",
- pkgPath: "android/soong/security/santizers_status",
- deps: [
- "blueprint",
- "soong-android",
- "soong-cc",
+ header_libs: [
+ "bionic_libc_platform_headers",
],
- srcs: ["sanitizer-status.go"],
- pluginFor: ["soong_build"],
}
diff --git a/sanitizer-status/main.c b/sanitizer-status/main.c
deleted file mode 100644
index 2186ccd..0000000
--- a/sanitizer-status/main.c
+++ /dev/null
@@ -1,5 +0,0 @@
-int sanitizer_status(int argc, char** argv);
-
-int main(int argc, char** argv) {
- return sanitizer_status(argc, argv);
-}
diff --git a/sanitizer-status/sanitizer-status.c b/sanitizer-status/sanitizer-status.cpp
similarity index 73%
rename from sanitizer-status/sanitizer-status.c
rename to sanitizer-status/sanitizer-status.cpp
index 14730f1..9e07e61 100644
--- a/sanitizer-status/sanitizer-status.c
+++ b/sanitizer-status/sanitizer-status.cpp
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
+#include <malloc.h>
#include <paths.h>
#include <pthread.h>
#include <pwd.h>
@@ -27,14 +28,25 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
-// crashes if built with -fsanitize=address
-void test_crash_malloc() {
- volatile char* heap = malloc(32);
+#include <bionic/mte.h>
+
+// crashes if built with -fsanitize={address,hwaddress}
+void test_crash_malloc_overflow() {
+ volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
heap[32] = heap[32];
- printf("(HW)ASAN: Heap Test Failed\n");
+ printf("Heap Overflow Test Failed\n");
+}
+
+// crashes if built with -fsanitize={address,hwaddresss}
+void test_crash_malloc_uaf() {
+ volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
+ free((void *)heap);
+ heap[0] = heap[0];
+ printf("Heap UAF Test Failed\n");
}
// crashes if built with -fsanitize=address
@@ -46,8 +58,8 @@
}
void test_crash_pthread_mutex_unlock() {
- volatile char* heap = malloc(32);
- pthread_mutex_unlock((void*)&heap[32]);
+ volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
+ pthread_mutex_unlock((pthread_mutex_t*)&heap[32]);
printf("HWASAN: Libc Test Failed\n");
}
@@ -65,7 +77,7 @@
void test_msan_crash_stack() {
volatile int stack[10];
stack[5] = 0;
- if (stack[0]) {
+ if (stack[0]) { // NOLINT
stack[0] = 1;
}
printf("MSAN: Stack Test Failed\n");
@@ -110,7 +122,7 @@
// crashes with GWP-ASan
void test_crash_gwp_asan() {
for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i ) {
- volatile char *x = malloc(1);
+ volatile char* x = reinterpret_cast<volatile char *>(malloc(1));
free((void*) x);
*x = 0;
}
@@ -157,7 +169,7 @@
return 0;
}
-int sanitizer_status(int argc, const char** argv) {
+int main(int argc, const char** argv) {
int test_everything = 0;
int failures = 0;
@@ -167,12 +179,13 @@
if (test_everything || have_option("asan", argv, argc)) {
int asan_failures = 0;
-#if !defined(ANDROID_SANITIZE_ADDRESS)
+#if !__has_feature(address_sanitizer)
asan_failures += 1;
printf("ASAN: Compiler flags failed!\n");
#endif
- asan_failures += test(test_crash_malloc);
+ asan_failures += test(test_crash_malloc_overflow);
+ asan_failures += test(test_crash_malloc_uaf);
asan_failures += test(test_crash_stack);
asan_failures += data_asan_exists();
@@ -185,12 +198,13 @@
if (test_everything || have_option("hwasan", argv, argc)) {
int hwasan_failures = 0;
-#if !defined(ANDROID_SANITIZE_HWADDRESS)
+#if !__has_feature(hwaddress_sanitizer)
hwasan_failures += 1;
printf("HWASAN: Compiler flags failed!\n");
#endif
- hwasan_failures += test(test_crash_malloc);
+ hwasan_failures += test(test_crash_malloc_overflow);
+ hwasan_failures += test(test_crash_malloc_uaf);
hwasan_failures += test(test_crash_stack);
hwasan_failures += test(test_crash_pthread_mutex_unlock);
@@ -200,20 +214,6 @@
failures += hwasan_failures;
}
- if(test_everything || have_option("cov", argv, argc)) {
- int cov_failures = 0;
-
-#ifndef ANDROID_SANITIZE_COVERAGE
- printf("COV: Compiler flags failed!\n");
- cov_failures += 1;
-#endif
-
- if (!cov_failures)
- printf("COV: OK\n");
-
- failures += cov_failures;
- }
-
if (test_everything || have_option("msan", argv, argc)) {
int msan_failures = 0;
@@ -269,5 +269,38 @@
failures += gwp_asan_failures;
}
+ if (test_everything || have_option("mte", argv, argc)) {
+ int mte_failures = 0;
+
+ if (!(mte_supported() && !__has_feature(address_sanitizer) &&
+ !__has_feature(hwaddress_sanitizer))) {
+ mte_failures += 1;
+ printf("MTE: Not supported\n");
+ }
+
+ mte_failures += test(test_crash_malloc_overflow);
+ mte_failures += test(test_crash_malloc_uaf);
+
+ int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+ if (tagged_addr_ctrl < 0) {
+ mte_failures += 1;
+ printf("MTE: PR_GET_TAGGED_ADDR_CTRL failed\n");
+ }
+
+ HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
+ if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level) == 0) {
+ mte_failures += 1;
+ printf("MTE: mallopt failed\n");
+ }
+
+ mte_failures += test(test_crash_malloc_overflow);
+ mte_failures += test(test_crash_malloc_uaf);
+
+ if (!mte_failures)
+ printf("MTE: OK\n");
+
+ failures += mte_failures;
+ }
+
return failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/sanitizer-status/sanitizer-status.go b/sanitizer-status/sanitizer-status.go
deleted file mode 100644
index 2c75e9f..0000000
--- a/sanitizer-status/sanitizer-status.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package sanitizer_status
-
-import (
- "android/soong/android"
- "android/soong/cc"
-)
-
-func init() {
- android.RegisterModuleType("sanitizer_status_library_shared",
- libraryFactory)
-}
-
-func libraryFactory() android.Module {
- module := cc.LibrarySharedFactory()
- android.AddLoadHook(module, loadHook)
- return module
-}
-
-func loadHook(ctx android.LoadHookContext) {
- type props struct {
- Cflags []string
- }
-
- p := &props{}
-
- sanitizers := ctx.Config().SanitizeDevice()
-
- if android.InList("address", sanitizers) {
- p.Cflags = append(p.Cflags, "-DANDROID_SANITIZE_ADDRESS=1")
- }
- if android.InList("hwaddress", sanitizers) {
- p.Cflags = append(p.Cflags, "-DANDROID_SANITIZE_HWADDRESS=1")
- }
- if android.InList("coverage", sanitizers) {
- p.Cflags = append(p.Cflags, "-DANDROID_SANITIZE_COVERAGE=1")
- }
-
- ctx.AppendProperties(p)
-}