• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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