1 use android_hardware_security_see_storage::aidl::android::hardware::security::see::storage::{
2     DeleteOptions::DeleteOptions, IFile::IFile, ISecureStorage as SecureStorage,
3     IStorageSession::IStorageSession, ReadIntegrity::ReadIntegrity,
4 };
5 use binder::ExceptionCode;
6 
7 pub(crate) enum Exists {
8     Must,
9     MustNot,
10     Unknown,
11 }
12 
ensure_deleted( ss: &(impl IStorageSession + ?Sized), fname: &str, expectation: Exists, ) -> Result<(), String>13 pub(crate) fn ensure_deleted(
14     ss: &(impl IStorageSession + ?Sized),
15     fname: &str,
16     expectation: Exists,
17 ) -> Result<(), String> {
18     const DEFAULT_DELETE: &'static DeleteOptions = &DeleteOptions {
19         readIntegrity: ReadIntegrity::NO_TAMPER,
20         allowWritesDuringAbUpdate: false,
21     };
22 
23     // Try to delete file
24     let rc = ss.deleteFile(fname, DEFAULT_DELETE);
25     match rc {
26         Ok(()) => {
27             if let Exists::MustNot = expectation {
28                 return Err(format!(
29                     "deleteFile succeeded, but the file (name: {}) shouldn't have exisited",
30                     fname
31                 ));
32             }
33         }
34         Err(e)
35             if e.exception_code() == ExceptionCode::SERVICE_SPECIFIC
36                 && e.service_specific_error() == SecureStorage::ERR_NOT_FOUND =>
37         {
38             if let Exists::Must = expectation {
39                 return Err(format!(
40                     "deleteFile failed (for {}) with ERR_NOT_FOUND, but the file should have existed",
41                     fname
42                 ));
43             }
44             ss.commitChanges().map_err(|e| format!("commitChanges failed with: {}", e))?;
45             return Ok(());
46         }
47         Err(e) => {
48             return Err(format!("deleteFile failed (for {}) with unexpected error: {}", fname, e))
49         }
50     };
51     ss.commitChanges().map_err(|e| format!("commitChanges failed with: {}", e))?;
52 
53     // If delete succeeded, try again to make sure it doesn't exist now
54     ensure_deleted(ss, fname, Exists::MustNot)
55         .map_err(|s| format!("while ensuring non-existence, {}", s))
56 }
57 
check_pattern32(offset: usize, buf: &[u8]) -> Result<(), String>58 fn check_pattern32(offset: usize, buf: &[u8]) -> Result<(), String> {
59     const U32_SIZE: usize = std::mem::size_of::<u32>();
60     let mut pattern: u32 = (offset / U32_SIZE).try_into().unwrap();
61 
62     let mut chunks = buf.chunks_exact(U32_SIZE);
63     for chunk in &mut chunks {
64         let actual = u32::from_ne_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
65         if actual != pattern {
66             return Err(format!("Expected to read {}, but found {}", pattern, actual));
67         }
68         pattern += 1;
69     }
70 
71     let rem = chunks.remainder();
72     for byte in rem {
73         if *byte != 0 {
74             return Err(format!(
75                 "Expected unpatterned portion of read to be zeroed; found {:x?}",
76                 rem
77             ));
78         }
79     }
80     Ok(())
81 }
82 
fill_pattern32(offset: usize, buf: &mut [u8])83 fn fill_pattern32(offset: usize, buf: &mut [u8]) {
84     const U32_SIZE: usize = std::mem::size_of::<u32>();
85     let mut pattern: u32 = (offset / U32_SIZE).try_into().unwrap();
86 
87     for chunk in buf.chunks_exact_mut(U32_SIZE) {
88         let bytes = pattern.to_ne_bytes();
89         for i in 0..U32_SIZE {
90             chunk[i] = bytes[i];
91         }
92         pattern += 1;
93     }
94 }
95 
check_valid_size(chunk_len: usize) -> Result<(), String>96 fn check_valid_size(chunk_len: usize) -> Result<(), String> {
97     if chunk_len % std::mem::size_of::<u32>() != 0 {
98         return Err(format!("Chunk size ({}) not 32-bit aligned.", chunk_len));
99     }
100     Ok(())
101 }
102 
write_pattern( file: &dyn IFile, offset: usize, chunks: usize, chunk_len: usize, ) -> Result<(), String>103 pub(crate) fn write_pattern(
104     file: &dyn IFile,
105     offset: usize,
106     chunks: usize,
107     chunk_len: usize,
108 ) -> Result<(), String> {
109     check_valid_size(chunk_len)?;
110     let mut buf = vec![0; chunk_len];
111 
112     for i in 0..chunks {
113         let chunk_offset = offset + i * chunk_len;
114         fill_pattern32(chunk_offset, &mut buf);
115         let written = file
116             .write(chunk_offset.try_into().unwrap(), &buf)
117             .map_err(|e| format!("Encountered error calling write (chunk {}): {}", i, e))?;
118         if written != chunk_len.try_into().unwrap() {
119             return Err(format!(
120                 "Wrote {} bytes to chunk {}, but expected to write {}",
121                 written, i, chunk_len,
122             ));
123         }
124     }
125 
126     Ok(())
127 }
128 
read_pattern( file: &dyn IFile, offset: usize, chunks: usize, chunk_len: usize, ) -> Result<(), String>129 pub(crate) fn read_pattern(
130     file: &dyn IFile,
131     offset: usize,
132     chunks: usize,
133     chunk_len: usize,
134 ) -> Result<(), String> {
135     check_valid_size(chunk_len)?;
136 
137     for i in 0..chunks {
138         let chunk_offset = offset + i * chunk_len;
139         let read = file
140             .read(chunk_len.try_into().unwrap(), chunk_offset.try_into().unwrap())
141             .map_err(|e| format!("Encountered error calling read (chunk {}): {}", i, e))?;
142         if read.len() != chunk_len {
143             return Err(format!(
144                 "Read {} bytes from chunk {}, but expected to read {}",
145                 read.len(),
146                 i,
147                 chunk_len,
148             ));
149         }
150         check_pattern32(chunk_offset, &*read).map_err(|e| format!("For chunk {}: {}", i, e))?;
151     }
152 
153     Ok(())
154 }
155