1 // Copyright 2020, 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 //! Error handling tests.
16
17 use super::*;
18 use android_system_keystore2::binder::{
19 ExceptionCode, Result as BinderResult, Status as BinderStatus,
20 };
21 use anyhow::{anyhow, Context};
22
nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()>23 fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
24 Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
25 }
26
nested_rc(rc: ResponseCode) -> anyhow::Result<()>27 fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
28 nested_nested_rc(rc).context("nested rc")
29 }
30
nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()>31 fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
32 Err(anyhow!(Error::Km(ec))).context("nested nested ec")
33 }
34
nested_ec(ec: ErrorCode) -> anyhow::Result<()>35 fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
36 nested_nested_ec(ec).context("nested ec")
37 }
38
nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode>39 fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
40 Ok(rc)
41 }
42
nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode>43 fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
44 nested_nested_ok(rc).context("nested ok")
45 }
46
nested_nested_selinux_perm() -> anyhow::Result<()>47 fn nested_nested_selinux_perm() -> anyhow::Result<()> {
48 Err(anyhow!(selinux::Error::perm())).context("nested nexted selinux permission denied")
49 }
50
nested_selinux_perm() -> anyhow::Result<()>51 fn nested_selinux_perm() -> anyhow::Result<()> {
52 nested_nested_selinux_perm().context("nested selinux permission denied")
53 }
54
55 #[derive(Debug, thiserror::Error)]
56 enum TestError {
57 #[error("TestError::Fail")]
58 Fail = 0,
59 }
60
nested_nested_other_error() -> anyhow::Result<()>61 fn nested_nested_other_error() -> anyhow::Result<()> {
62 Err(anyhow!(TestError::Fail)).context("nested nested other error")
63 }
64
nested_other_error() -> anyhow::Result<()>65 fn nested_other_error() -> anyhow::Result<()> {
66 nested_nested_other_error().context("nested other error")
67 }
68
binder_sse_error(sse: i32) -> BinderResult<()>69 fn binder_sse_error(sse: i32) -> BinderResult<()> {
70 Err(BinderStatus::new_service_specific_error(sse, None))
71 }
72
binder_exception(ex: ExceptionCode) -> BinderResult<()>73 fn binder_exception(ex: ExceptionCode) -> BinderResult<()> {
74 Err(BinderStatus::new_exception(ex, None))
75 }
76
77 #[test]
keystore_error_test() -> anyhow::Result<(), String>78 fn keystore_error_test() -> anyhow::Result<(), String> {
79 android_logger::init_once(
80 android_logger::Config::default()
81 .with_tag("keystore_error_tests")
82 .with_max_level(log::LevelFilter::Debug),
83 );
84 // All Error::Rc(x) get mapped on a service specific error
85 // code of x.
86 for rc in ResponseCode::LOCKED.0..ResponseCode::BACKEND_BUSY.0 {
87 assert_eq!(
88 Result::<(), i32>::Err(rc),
89 nested_rc(ResponseCode(rc))
90 .map_err(into_logged_binder)
91 .map_err(|s| s.service_specific_error())
92 );
93 }
94
95 // All Keystore Error::Km(x) get mapped on a service
96 // specific error of x.
97 for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
98 assert_eq!(
99 Result::<(), i32>::Err(ec),
100 nested_ec(ErrorCode(ec))
101 .map_err(into_logged_binder)
102 .map_err(|s| s.service_specific_error())
103 );
104 }
105
106 // All Keymint errors x received through a Binder Result get mapped on
107 // a service specific error of x.
108 for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
109 assert_eq!(
110 Result::<(), i32>::Err(ec),
111 map_km_error(binder_sse_error(ec))
112 .with_context(|| format!("Km error code: {}.", ec))
113 .map_err(into_logged_binder)
114 .map_err(|s| s.service_specific_error())
115 );
116 }
117
118 // map_km_error creates an Error::Binder variant storing
119 // ExceptionCode::SERVICE_SPECIFIC and the given
120 // service specific error.
121 let sse = map_km_error(binder_sse_error(1));
122 assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse);
123 // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
124 assert_eq!(
125 Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
126 sse.context("Non negative service specific error.")
127 .map_err(into_logged_binder)
128 .map_err(|s| ResponseCode(s.service_specific_error()))
129 );
130
131 // map_km_error creates a Error::Binder variant storing the given exception code.
132 let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED));
133 assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception);
134 // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
135 assert_eq!(
136 Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
137 binder_exception
138 .context("Binder Exception.")
139 .map_err(into_logged_binder)
140 .map_err(|s| ResponseCode(s.service_specific_error()))
141 );
142
143 // selinux::Error::Perm() needs to be mapped to ResponseCode::PERMISSION_DENIED
144 assert_eq!(
145 Result::<(), ResponseCode>::Err(ResponseCode::PERMISSION_DENIED),
146 nested_selinux_perm()
147 .map_err(into_logged_binder)
148 .map_err(|s| ResponseCode(s.service_specific_error()))
149 );
150
151 // All other errors get mapped on System Error.
152 assert_eq!(
153 Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
154 nested_other_error()
155 .map_err(into_logged_binder)
156 .map_err(|s| ResponseCode(s.service_specific_error()))
157 );
158
159 // Result::Ok variants get passed to the ok handler.
160 assert_eq!(
161 Ok(ResponseCode::LOCKED),
162 nested_ok(ResponseCode::LOCKED).map_err(into_logged_binder)
163 );
164 assert_eq!(
165 Ok(ResponseCode::SYSTEM_ERROR),
166 nested_ok(ResponseCode::SYSTEM_ERROR).map_err(into_logged_binder)
167 );
168
169 Ok(())
170 }
171
172 //Helper function to test whether error cases are handled as expected.
check_result_contains_error_string<T>( result: anyhow::Result<T>, expected_error_string: &str, )173 pub fn check_result_contains_error_string<T>(
174 result: anyhow::Result<T>,
175 expected_error_string: &str,
176 ) {
177 let error_str = format!(
178 "{:#?}",
179 result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string))
180 );
181 assert!(
182 error_str.contains(expected_error_string),
183 "The string \"{}\" should contain \"{}\"",
184 error_str,
185 expected_error_string
186 );
187 }
188
189 #[test]
rkpd_error_is_in_sync_with_response_code()190 fn rkpd_error_is_in_sync_with_response_code() {
191 let error_mapping = [
192 (RkpdError::RequestCancelled, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
193 (RkpdError::GetRegistrationFailed, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
194 (
195 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_UNKNOWN),
196 ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
197 ),
198 (
199 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PERMANENT),
200 ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
201 ),
202 (
203 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY),
204 ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
205 ),
206 (
207 RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH),
208 ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
209 ),
210 (RkpdError::StoreUpgradedKeyFailed, ResponseCode::SYSTEM_ERROR),
211 (RkpdError::RetryableTimeout, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
212 (RkpdError::Timeout, ResponseCode::SYSTEM_ERROR),
213 ];
214 for (rkpd_error, expected_response_code) in error_mapping {
215 let e: Error = rkpd_error.into();
216 assert_eq!(e, Error::Rc(expected_response_code));
217 }
218 }
219