1 // Copyright 2021, 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 #![allow(missing_docs)] 16 #![allow(unused_must_use)] 17 #![no_main] 18 19 use libfuzzer_sys::arbitrary::Arbitrary; 20 use libfuzzer_sys::fuzz_target; 21 use rustutils::system_properties; 22 use std::cell::RefCell; 23 use std::sync::Arc; 24 use std::sync::atomic::{AtomicBool, Ordering}; 25 use std::{fmt, thread, time}; 26 27 thread_local! { 28 static COUNTER: RefCell<u64> = const{RefCell::new(0)}; 29 } 30 31 #[derive(Arbitrary, Clone, Debug)] 32 enum WritableProperty { 33 Fuzzer1, 34 Fuzzer2, 35 } 36 37 #[derive(Arbitrary, Clone, Debug)] 38 enum Property { 39 KeystoreBootLevel, 40 Random { name: String }, 41 Unique, 42 Writable { prop: WritableProperty }, 43 } 44 45 impl fmt::Display for Property { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 47 write!(f, "{}", match self { 48 Property::KeystoreBootLevel => "keystore.boot_level".to_string(), 49 Property::Random { name } => name.to_string(), 50 Property::Unique => COUNTER.with(|counter| { 51 let val = *counter.borrow(); 52 *counter.borrow_mut() += 1; 53 format!("unique.fuzz.prop.{}", val) 54 }), 55 Property::Writable { prop } => prop.to_string(), 56 }) 57 } 58 } 59 60 impl fmt::Display for WritableProperty { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 62 write!(f, "{}", match self { 63 WritableProperty::Fuzzer1 => "unique.fuzz.prop".to_string(), 64 WritableProperty::Fuzzer2 => "unique.fuzz.two.prop".to_string(), 65 }) 66 } 67 } 68 69 #[derive(Arbitrary, Debug)] 70 enum Command { 71 Read { prop: Property }, 72 Write { prop: WritableProperty, value: String }, 73 WatcherRead { prop: Property }, 74 WatcherWait { value: u8 }, 75 } 76 77 fuzz_target!(|commands: Vec<Command>| { 78 for command in commands { 79 match command { 80 Command::Read { prop } => { 81 system_properties::read(&prop.to_string()); 82 } 83 Command::Write { prop, value } => { 84 system_properties::write(&prop.to_string(), &value); 85 } 86 Command::WatcherRead { prop } => { 87 if let Ok(mut watcher) = system_properties::PropertyWatcher::new(&prop.to_string()) { 88 watcher.read(|_n, v| Ok(v.to_string())); 89 } 90 } 91 Command::WatcherWait { value } => { 92 // We want to ensure that we choose a property that can be written, 93 // or else we'd just have to implement a timeout and do nothing, 94 // so we use a hardcoded valid property. 95 let prop_str = "keystore.boot_level"; 96 let waited = Arc::new(AtomicBool::new(false)); 97 let waited_clone = waited.clone(); 98 // Spawn a thread that will wait for a change to the property. 99 let waiter = thread::spawn(move || { 100 let result = match system_properties::PropertyWatcher::new(prop_str) { 101 Ok(mut watcher) => watcher.wait(None), 102 Err(e) => Err(e), 103 }; 104 waited_clone.store(true, Ordering::Relaxed); 105 result 106 }); 107 // Write the property in a loop (so we're sure to follow the wait call). 108 let mut cur_value = value; 109 while !waited.load(Ordering::Relaxed) { 110 thread::sleep(time::Duration::from_millis(1)); 111 system_properties::write(prop_str, &cur_value.to_string()); 112 cur_value = cur_value.wrapping_add(1); 113 } 114 waiter.join(); 115 } 116 } 117 } 118 }); 119