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