Merge "Added keystore2_unsafe_fuzzer"

This commit is contained in:
Treehugger Robot 2022-08-22 05:42:53 +00:00 committed by Gerrit Code Review
commit 65f8bf69c5
4 changed files with 278 additions and 28 deletions

View file

@ -17,13 +17,23 @@ package {
}
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,
},
}

View file

@ -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
```

View file

@ -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());
}
}
}
});

View file

@ -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);
}
});