Added keystore2_unsafe_fuzzer

Test: ./keystore2_unsafe_fuzzer
Bug: 240524901

Change-Id: Ibb6d2c649f982bc1b5fc8d4a259087e53bac79aa
diff --git a/keystore2/src/fuzzers/Android.bp b/keystore2/src/fuzzers/Android.bp
index 384ab77..3adb922 100644
--- a/keystore2/src/fuzzers/Android.bp
+++ b/keystore2/src/fuzzers/Android.bp
@@ -17,13 +17,23 @@
 }
 
 rust_fuzz {
-    name: "legacy_blob_fuzzer",
-    srcs: ["legacy_blob_fuzzer.rs"],
+    name: "keystore2_unsafe_fuzzer",
+    srcs: ["keystore2_unsafe_fuzzer.rs"],
     rustlibs: [
         "libkeystore2",
+        "libkeystore2_crypto_rust",
+        "libkeystore2_vintf_rust",
+        "libkeystore2_aaid-rust",
+        "libkeystore2_apc_compat-rust",
+        "libkeystore2_selinux",
+        "libarbitrary",
     ],
     fuzz_config: {
         fuzz_on_haiku_device: true,
         fuzz_on_haiku_host: false,
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 155276,
     },
 }
diff --git a/keystore2/src/fuzzers/README.md b/keystore2/src/fuzzers/README.md
new file mode 100644
index 0000000..a4ed095
--- /dev/null
+++ b/keystore2/src/fuzzers/README.md
@@ -0,0 +1,18 @@
+# Fuzzers for libkeystore2
+## Table of contents
++ [keystore2_unsafe_fuzzer](#Keystore2Unsafe)
+
+# <a name="Keystore2Unsafe"></a> Fuzzer for Keystore2Unsafe
+All the parameters of Keystore2Unsafe are populated randomly from libfuzzer. You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ m -j$(nproc) keystore2_unsafe_fuzzer
+```
+
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/${TARGET_ARCH}/keystore2_unsafe_fuzzer/keystore2_unsafe_fuzzer
+```
diff --git a/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
new file mode 100644
index 0000000..4c2419a
--- /dev/null
+++ b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
@@ -0,0 +1,248 @@
+// Copyright 2022, 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.
+
+//! Fuzzes unsafe APIs of libkeystore2 module
+
+#![feature(slice_internals)]
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+
+use core::slice::memchr;
+use keystore2::{legacy_blob::LegacyBlobLoader, utils::ui_opts_2_compat};
+use keystore2_aaid::get_aaid;
+use keystore2_apc_compat::ApcHal;
+use keystore2_crypto::{
+    aes_gcm_decrypt, aes_gcm_encrypt, ec_key_generate_key, ec_key_get0_public_key,
+    ec_key_marshal_private_key, ec_key_parse_private_key, ec_point_oct_to_point,
+    ec_point_point_to_oct, ecdh_compute_key, generate_random_data, hkdf_expand, hkdf_extract,
+    hmac_sha256, parse_subject_from_certificate, Password, ZVec,
+};
+use keystore2_selinux::{check_access, getpidcon, setcon, Backend, Context, KeystoreKeyBackend};
+use keystore2_vintf::{get_aidl_instances, get_hidl_instances};
+use libfuzzer_sys::arbitrary::Arbitrary;
+use std::{ffi::CString, sync::Arc};
+
+// Avoid allocating too much memory and crashing the fuzzer.
+const MAX_SIZE_MODIFIER: usize = 1024;
+
+/// CString does not contain any internal 0 bytes
+fn get_valid_cstring_data(data: &[u8]) -> &[u8] {
+    match memchr::memchr(0, data) {
+        Some(idx) => &data[0..idx],
+        None => data,
+    }
+}
+
+#[derive(Arbitrary, Debug)]
+enum FuzzCommand<'a> {
+    DecodeAlias {
+        string: String,
+    },
+    TryFrom {
+        vector_data: Vec<u8>,
+    },
+    GenerateRandomData {
+        size: usize,
+    },
+    HmacSha256 {
+        key_hmac: &'a [u8],
+        msg: &'a [u8],
+    },
+    AesGcmDecrypt {
+        data: &'a [u8],
+        iv: &'a [u8],
+        tag: &'a [u8],
+        key_aes_decrypt: &'a [u8],
+    },
+    AesGcmEecrypt {
+        plaintext: &'a [u8],
+        key_aes_encrypt: &'a [u8],
+    },
+    Password {
+        pw: &'a [u8],
+        salt: &'a [u8],
+        key_length: usize,
+    },
+    HkdfExtract {
+        hkdf_secret: &'a [u8],
+        hkdf_salt: &'a [u8],
+    },
+    HkdfExpand {
+        out_len: usize,
+        hkdf_prk: &'a [u8],
+        hkdf_info: &'a [u8],
+    },
+    PublicPrivateKey {
+        ec_priv_buf: &'a [u8],
+        ec_oct_buf: &'a [u8],
+    },
+    ParseSubjectFromCertificate {
+        parse_buf: &'a [u8],
+    },
+    GetHidlInstances {
+        hidl_package: &'a str,
+        major_version: usize,
+        minor_version: usize,
+        hidl_interface_name: &'a str,
+    },
+    GetAidlInstances {
+        aidl_package: &'a str,
+        version: usize,
+        aidl_interface_name: &'a str,
+    },
+    GetAaid {
+        aaid_uid: u32,
+    },
+    Hal {
+        opt: i32,
+        prompt_text: &'a str,
+        locale: &'a str,
+        extra_data: &'a [u8],
+    },
+    Context {
+        context: &'a str,
+    },
+    Backend {
+        namespace: &'a str,
+    },
+    GetPidCon {
+        pid: i32,
+    },
+    CheckAccess {
+        source: &'a [u8],
+        target: &'a [u8],
+        tclass: &'a str,
+        perm: &'a str,
+    },
+    SetCon {
+        set_target: &'a [u8],
+    },
+}
+
+fuzz_target!(|commands: Vec<FuzzCommand>| {
+    for command in commands {
+        match command {
+            FuzzCommand::DecodeAlias { string } => {
+                let _res = LegacyBlobLoader::decode_alias(&string);
+            }
+            FuzzCommand::TryFrom { vector_data } => {
+                let _res = ZVec::try_from(vector_data);
+            }
+            FuzzCommand::GenerateRandomData { size } => {
+                let _res = generate_random_data(size % MAX_SIZE_MODIFIER);
+            }
+            FuzzCommand::HmacSha256 { key_hmac, msg } => {
+                let _res = hmac_sha256(key_hmac, msg);
+            }
+            FuzzCommand::AesGcmDecrypt { data, iv, tag, key_aes_decrypt } => {
+                let _res = aes_gcm_decrypt(data, iv, tag, key_aes_decrypt);
+            }
+            FuzzCommand::AesGcmEecrypt { plaintext, key_aes_encrypt } => {
+                let _res = aes_gcm_encrypt(plaintext, key_aes_encrypt);
+            }
+            FuzzCommand::Password { pw, salt, key_length } => {
+                let _res = Password::from(pw).derive_key(salt, key_length % MAX_SIZE_MODIFIER);
+            }
+            FuzzCommand::HkdfExtract { hkdf_secret, hkdf_salt } => {
+                let _res = hkdf_extract(hkdf_secret, hkdf_salt);
+            }
+            FuzzCommand::HkdfExpand { out_len, hkdf_prk, hkdf_info } => {
+                let _res = hkdf_expand(out_len % MAX_SIZE_MODIFIER, hkdf_prk, hkdf_info);
+            }
+            FuzzCommand::PublicPrivateKey { ec_priv_buf, ec_oct_buf } => {
+                let check_private_key = {
+                    let mut check_private_key = ec_key_parse_private_key(ec_priv_buf);
+                    if check_private_key.is_err() {
+                        check_private_key = ec_key_generate_key();
+                    };
+                    check_private_key
+                };
+                let check_ecpoint = ec_point_oct_to_point(ec_oct_buf);
+                if check_private_key.is_ok() {
+                    let private_key = check_private_key.unwrap();
+                    ec_key_get0_public_key(&private_key);
+                    let _res = ec_key_marshal_private_key(&private_key);
+
+                    if check_ecpoint.is_ok() {
+                        let public_key = check_ecpoint.unwrap();
+                        let _res = ec_point_point_to_oct(public_key.get_point());
+                        let _res = ecdh_compute_key(public_key.get_point(), &private_key);
+                    }
+                }
+            }
+            FuzzCommand::ParseSubjectFromCertificate { parse_buf } => {
+                let _res = parse_subject_from_certificate(parse_buf);
+            }
+            FuzzCommand::GetHidlInstances {
+                hidl_package,
+                major_version,
+                minor_version,
+                hidl_interface_name,
+            } => {
+                get_hidl_instances(hidl_package, major_version, minor_version, hidl_interface_name);
+            }
+            FuzzCommand::GetAidlInstances { aidl_package, version, aidl_interface_name } => {
+                get_aidl_instances(aidl_package, version, aidl_interface_name);
+            }
+            FuzzCommand::GetAaid { aaid_uid } => {
+                let _res = get_aaid(aaid_uid);
+            }
+            FuzzCommand::Hal { opt, prompt_text, locale, extra_data } => {
+                let hal = ApcHal::try_get_service();
+                if hal.is_some() {
+                    let hal = Arc::new(hal.unwrap());
+                    let apc_compat_options = ui_opts_2_compat(opt);
+                    let prompt_text =
+                        std::str::from_utf8(get_valid_cstring_data(prompt_text.as_bytes()))
+                            .unwrap();
+                    let locale =
+                        std::str::from_utf8(get_valid_cstring_data(locale.as_bytes())).unwrap();
+                    let _res = hal.prompt_user_confirmation(
+                        prompt_text,
+                        extra_data,
+                        locale,
+                        apc_compat_options,
+                        move |_, _, _| {},
+                    );
+                }
+            }
+            FuzzCommand::Context { context } => {
+                let _res = Context::new(context);
+            }
+            FuzzCommand::Backend { namespace } => {
+                let backend = KeystoreKeyBackend::new();
+                if let Ok(backend) = backend {
+                    let _res = backend.lookup(namespace);
+                }
+            }
+            FuzzCommand::GetPidCon { pid } => {
+                let _res = getpidcon(pid);
+            }
+            FuzzCommand::CheckAccess { source, target, tclass, perm } => {
+                let source = get_valid_cstring_data(source);
+                let target = get_valid_cstring_data(target);
+                let _res = check_access(
+                    &CString::new(source).unwrap(),
+                    &CString::new(target).unwrap(),
+                    tclass,
+                    perm,
+                );
+            }
+            FuzzCommand::SetCon { set_target } => {
+                let _res = setcon(&CString::new(get_valid_cstring_data(set_target)).unwrap());
+            }
+        }
+    }
+});
diff --git a/keystore2/src/fuzzers/legacy_blob_fuzzer.rs b/keystore2/src/fuzzers/legacy_blob_fuzzer.rs
deleted file mode 100644
index 7e3e848..0000000
--- a/keystore2/src/fuzzers/legacy_blob_fuzzer.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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;
-use keystore2::legacy_blob::LegacyBlobLoader;
-
-fuzz_target!(|data: &[u8]| {
-    if !data.is_empty() {
-        let string = data.iter().filter_map(|c| std::char::from_u32(*c as u32)).collect::<String>();
-        let _res = LegacyBlobLoader::decode_alias(&string);
-    }
-});