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