summaryrefslogtreecommitdiff
path: root/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs')
-rw-r--r--keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs247
1 files changed, 247 insertions, 0 deletions
diff --git a/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
new file mode 100644
index 00000000..0dca3a24
--- /dev/null
+++ b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
@@ -0,0 +1,247 @@
+// 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
+
+#![no_main]
+
+use binder::get_declared_instances;
+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_hidl_instances;
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
+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 data.iter().position(|&b| b == 0) {
+ 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,
+ 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, aidl_interface_name } => {
+ get_declared_instances(
+ format!("{}.{}", aidl_package, aidl_interface_name).as_str(),
+ )
+ .unwrap();
+ }
+ 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());
+ }
+ }
+ }
+});