• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Fuzzes unsafe APIs of libkeystore2 module
16 
17 #![no_main]
18 
19 use binder::get_declared_instances;
20 use keystore2::{legacy_blob::LegacyBlobLoader, utils::ui_opts_2_compat};
21 use keystore2_aaid::get_aaid;
22 use keystore2_apc_compat::ApcHal;
23 use keystore2_crypto::{
24     aes_gcm_decrypt, aes_gcm_encrypt, ec_key_generate_key, ec_key_get0_public_key,
25     ec_key_marshal_private_key, ec_key_parse_private_key, ec_point_oct_to_point,
26     ec_point_point_to_oct, ecdh_compute_key, generate_random_data, hkdf_expand, hkdf_extract,
27     hmac_sha256, parse_subject_from_certificate, Password, ZVec,
28 };
29 use keystore2_selinux::{check_access, getpidcon, setcon, Backend, Context, KeystoreKeyBackend};
30 use keystore2_vintf::get_hidl_instances;
31 use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
32 use std::{ffi::CString, sync::Arc};
33 
34 // Avoid allocating too much memory and crashing the fuzzer.
35 const MAX_SIZE_MODIFIER: usize = 1024;
36 
37 /// CString does not contain any internal 0 bytes
get_valid_cstring_data(data: &[u8]) -> &[u8]38 fn get_valid_cstring_data(data: &[u8]) -> &[u8] {
39     match data.iter().position(|&b| b == 0) {
40         Some(idx) => &data[0..idx],
41         None => data,
42     }
43 }
44 
45 #[derive(Arbitrary, Debug)]
46 enum FuzzCommand<'a> {
47     DecodeAlias {
48         string: String,
49     },
50     TryFrom {
51         vector_data: Vec<u8>,
52     },
53     GenerateRandomData {
54         size: usize,
55     },
56     HmacSha256 {
57         key_hmac: &'a [u8],
58         msg: &'a [u8],
59     },
60     AesGcmDecrypt {
61         data: &'a [u8],
62         iv: &'a [u8],
63         tag: &'a [u8],
64         key_aes_decrypt: &'a [u8],
65     },
66     AesGcmEecrypt {
67         plaintext: &'a [u8],
68         key_aes_encrypt: &'a [u8],
69     },
70     Password {
71         pw: &'a [u8],
72         salt: &'a [u8],
73         key_length: usize,
74     },
75     HkdfExtract {
76         hkdf_secret: &'a [u8],
77         hkdf_salt: &'a [u8],
78     },
79     HkdfExpand {
80         out_len: usize,
81         hkdf_prk: &'a [u8],
82         hkdf_info: &'a [u8],
83     },
84     PublicPrivateKey {
85         ec_priv_buf: &'a [u8],
86         ec_oct_buf: &'a [u8],
87     },
88     ParseSubjectFromCertificate {
89         parse_buf: &'a [u8],
90     },
91     GetHidlInstances {
92         hidl_package: &'a str,
93         major_version: usize,
94         minor_version: usize,
95         hidl_interface_name: &'a str,
96     },
97     GetAidlInstances {
98         aidl_package: &'a str,
99         aidl_interface_name: &'a str,
100     },
101     GetAaid {
102         aaid_uid: u32,
103     },
104     Hal {
105         opt: i32,
106         prompt_text: &'a str,
107         locale: &'a str,
108         extra_data: &'a [u8],
109     },
110     Context {
111         context: &'a str,
112     },
113     Backend {
114         namespace: &'a str,
115     },
116     GetPidCon {
117         pid: i32,
118     },
119     CheckAccess {
120         source: &'a [u8],
121         target: &'a [u8],
122         tclass: &'a str,
123         perm: &'a str,
124     },
125     SetCon {
126         set_target: &'a [u8],
127     },
128 }
129 
130 fuzz_target!(|commands: Vec<FuzzCommand>| {
131     for command in commands {
132         match command {
133             FuzzCommand::DecodeAlias { string } => {
134                 let _res = LegacyBlobLoader::decode_alias(&string);
135             }
136             FuzzCommand::TryFrom { vector_data } => {
137                 let _res = ZVec::try_from(vector_data);
138             }
139             FuzzCommand::GenerateRandomData { size } => {
140                 let _res = generate_random_data(size % MAX_SIZE_MODIFIER);
141             }
142             FuzzCommand::HmacSha256 { key_hmac, msg } => {
143                 let _res = hmac_sha256(key_hmac, msg);
144             }
145             FuzzCommand::AesGcmDecrypt { data, iv, tag, key_aes_decrypt } => {
146                 let _res = aes_gcm_decrypt(data, iv, tag, key_aes_decrypt);
147             }
148             FuzzCommand::AesGcmEecrypt { plaintext, key_aes_encrypt } => {
149                 let _res = aes_gcm_encrypt(plaintext, key_aes_encrypt);
150             }
151             FuzzCommand::Password { pw, salt, key_length } => {
152                 let _res = Password::from(pw).derive_key(salt, key_length % MAX_SIZE_MODIFIER);
153             }
154             FuzzCommand::HkdfExtract { hkdf_secret, hkdf_salt } => {
155                 let _res = hkdf_extract(hkdf_secret, hkdf_salt);
156             }
157             FuzzCommand::HkdfExpand { out_len, hkdf_prk, hkdf_info } => {
158                 let _res = hkdf_expand(out_len % MAX_SIZE_MODIFIER, hkdf_prk, hkdf_info);
159             }
160             FuzzCommand::PublicPrivateKey { ec_priv_buf, ec_oct_buf } => {
161                 let check_private_key = {
162                     let mut check_private_key = ec_key_parse_private_key(ec_priv_buf);
163                     if check_private_key.is_err() {
164                         check_private_key = ec_key_generate_key();
165                     };
166                     check_private_key
167                 };
168                 let check_ecpoint = ec_point_oct_to_point(ec_oct_buf);
169                 if check_private_key.is_ok() {
170                     let private_key = check_private_key.unwrap();
171                     ec_key_get0_public_key(&private_key);
172                     let _res = ec_key_marshal_private_key(&private_key);
173 
174                     if check_ecpoint.is_ok() {
175                         let public_key = check_ecpoint.unwrap();
176                         let _res = ec_point_point_to_oct(public_key.get_point());
177                         let _res = ecdh_compute_key(public_key.get_point(), &private_key);
178                     }
179                 }
180             }
181             FuzzCommand::ParseSubjectFromCertificate { parse_buf } => {
182                 let _res = parse_subject_from_certificate(parse_buf);
183             }
184             FuzzCommand::GetHidlInstances {
185                 hidl_package,
186                 major_version,
187                 minor_version,
188                 hidl_interface_name,
189             } => {
190                 get_hidl_instances(hidl_package, major_version, minor_version, hidl_interface_name);
191             }
192             FuzzCommand::GetAidlInstances { aidl_package, aidl_interface_name } => {
193                 get_declared_instances(
194                     format!("{}.{}", aidl_package, aidl_interface_name).as_str(),
195                 )
196                 .unwrap();
197             }
198             FuzzCommand::GetAaid { aaid_uid } => {
199                 let _res = get_aaid(aaid_uid);
200             }
201             FuzzCommand::Hal { opt, prompt_text, locale, extra_data } => {
202                 let hal = ApcHal::try_get_service();
203                 if hal.is_some() {
204                     let hal = Arc::new(hal.unwrap());
205                     let apc_compat_options = ui_opts_2_compat(opt);
206                     let prompt_text =
207                         std::str::from_utf8(get_valid_cstring_data(prompt_text.as_bytes()))
208                             .unwrap();
209                     let locale =
210                         std::str::from_utf8(get_valid_cstring_data(locale.as_bytes())).unwrap();
211                     let _res = hal.prompt_user_confirmation(
212                         prompt_text,
213                         extra_data,
214                         locale,
215                         apc_compat_options,
216                         move |_, _, _| {},
217                     );
218                 }
219             }
220             FuzzCommand::Context { context } => {
221                 let _res = Context::new(context);
222             }
223             FuzzCommand::Backend { namespace } => {
224                 let backend = KeystoreKeyBackend::new();
225                 if let Ok(backend) = backend {
226                     let _res = backend.lookup(namespace);
227                 }
228             }
229             FuzzCommand::GetPidCon { pid } => {
230                 let _res = getpidcon(pid);
231             }
232             FuzzCommand::CheckAccess { source, target, tclass, perm } => {
233                 let source = get_valid_cstring_data(source);
234                 let target = get_valid_cstring_data(target);
235                 let _res = check_access(
236                     &CString::new(source).unwrap(),
237                     &CString::new(target).unwrap(),
238                     tclass,
239                     perm,
240                 );
241             }
242             FuzzCommand::SetCon { set_target } => {
243                 let _res = setcon(&CString::new(get_valid_cstring_data(set_target)).unwrap());
244             }
245         }
246     }
247 });
248