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