blob: 5950ac24d190702996af14e16f75c074d62f6c24 [file] [log] [blame]
Joel Galenson15b374f2021-11-09 10:39:12 -08001// 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
19use libfuzzer_sys::arbitrary::Arbitrary;
20use libfuzzer_sys::fuzz_target;
21use rustutils::system_properties;
22use std::cell::RefCell;
23use std::sync::Arc;
24use std::sync::atomic::{AtomicBool, Ordering};
25use std::{fmt, thread, time};
26
27thread_local! {
28 static COUNTER: RefCell<u64> = RefCell::new(0);
29}
30
31#[derive(Arbitrary, Clone, Debug)]
32enum WritableProperty {
33 Fuzzer1,
34 Fuzzer2,
35}
36
37#[derive(Arbitrary, Clone, Debug)]
38enum Property {
39 KeystoreBootLevel,
40 Random { name: String },
41 Unique,
42 Writable { prop: WritableProperty },
43}
44
45impl fmt::Display for Property {
46 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
60impl fmt::Display for WritableProperty {
61 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)]
70enum Command {
71 Read { prop: Property },
72 Write { prop: WritableProperty, value: String },
73 WatcherRead { prop: Property },
74 WatcherWait { value: u8 },
75}
76
77fuzz_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(),
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});