| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 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 | //! Keystore error provides convenience methods and types for Keystore error handling. | 
 | 16 | //! Clients of Keystore expect one of two error codes, i.e., a Keystore ResponseCode as | 
 | 17 | //! defined by the Keystore AIDL interface, or a Keymint ErrorCode as defined by | 
 | 18 | //! the Keymint HAL specification. | 
 | 19 | //! This crate provides `Error` which can wrap both. It is to be used | 
 | 20 | //! internally by Keystore to diagnose error conditions that need to be reported to | 
 | 21 | //! the client. To report the error condition to the client the Keystore AIDL | 
 | 22 | //! interface defines a wire type `Result` which is distinctly different from Rust's | 
 | 23 | //! `enum Result<T,E>`. | 
 | 24 | //! | 
 | 25 | //! This crate provides the convenience method `map_or_log_err` to convert `anyhow::Error` | 
 | 26 | //! into this wire type. In addition to handling the conversion of `Error` | 
 | 27 | //! to the `Result` wire type it handles any other error by mapping it to | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 28 | //! `ResponseCode::SYSTEM_ERROR` and logs any error condition. | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 29 | //! | 
 | 30 | //! Keystore functions should use `anyhow::Result` to return error conditions, and | 
 | 31 | //! context should be added every time an error is forwarded. | 
 | 32 |  | 
 | 33 | use std::cmp::PartialEq; | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 34 |  | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 35 | pub use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode::ErrorCode; | 
 | 36 | pub use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode; | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 37 |  | 
| Janis Danisevskis | ce99543 | 2020-07-21 12:22:34 -0700 | [diff] [blame] | 38 | use keystore2_selinux as selinux; | 
 | 39 |  | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 40 | use android_system_keystore2::binder::{ | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 41 |     ExceptionCode, Result as BinderResult, Status as BinderStatus, | 
 | 42 | }; | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 43 |  | 
 | 44 | /// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated | 
 | 45 | /// from AIDL in the `Rc` variant and Keymint `ErrorCode` in the Km variant. | 
 | 46 | #[derive(Debug, thiserror::Error, PartialEq)] | 
 | 47 | pub enum Error { | 
 | 48 |     /// Wraps a Keystore `ResponseCode` as defined by the Keystore AIDL interface specification. | 
 | 49 |     #[error("Error::Rc({0:?})")] | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 50 |     Rc(ResponseCode), | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 51 |     /// Wraps a Keymint `ErrorCode` as defined by the Keymint AIDL interface specification. | 
 | 52 |     #[error("Error::Km({0:?})")] | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 53 |     Km(ErrorCode), | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 54 |     /// Wraps a Binder exception code other than a service specific exception. | 
 | 55 |     #[error("Binder exception code {0:?}, {1:?}")] | 
 | 56 |     Binder(ExceptionCode, i32), | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 57 | } | 
 | 58 |  | 
 | 59 | impl Error { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 60 |     /// Short hand for `Error::Rc(ResponseCode::SYSTEM_ERROR)` | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 61 |     pub fn sys() -> Self { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 62 |         Error::Rc(ResponseCode::SYSTEM_ERROR) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 63 |     } | 
 | 64 |  | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 65 |     /// Short hand for `Error::Rc(ResponseCode::PERMISSION_DENIED` | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 66 |     pub fn perm() -> Self { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 67 |         Error::Rc(ResponseCode::PERMISSION_DENIED) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 68 |     } | 
 | 69 | } | 
 | 70 |  | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 71 | /// Helper function to map the binder status we get from calls into KeyMint | 
 | 72 | /// to a Keystore Error. We don't create an anyhow error here to make | 
 | 73 | /// it easier to evaluate KeyMint errors, which we must do in some cases, e.g., | 
 | 74 | /// when diagnosing authentication requirements, update requirements, and running | 
 | 75 | /// out of operation slots. | 
 | 76 | pub fn map_km_error<T>(r: BinderResult<T>) -> Result<T, Error> { | 
 | 77 |     r.map_err(|s| { | 
 | 78 |         match s.exception_code() { | 
 | 79 |             ExceptionCode::SERVICE_SPECIFIC => { | 
 | 80 |                 let se = s.service_specific_error(); | 
 | 81 |                 if se < 0 { | 
 | 82 |                     // Negative service specific errors are KM error codes. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 83 |                     Error::Km(ErrorCode(s.service_specific_error())) | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 84 |                 } else { | 
 | 85 |                     // Non negative error codes cannot be KM error codes. | 
 | 86 |                     // So we create an `Error::Binder` variant to preserve | 
 | 87 |                     // the service specific error code for logging. | 
 | 88 |                     // `map_or_log_err` will map this on a system error, | 
 | 89 |                     // but not before logging the details to logcat. | 
 | 90 |                     Error::Binder(ExceptionCode::SERVICE_SPECIFIC, se) | 
 | 91 |                 } | 
 | 92 |             } | 
 | 93 |             // We create `Error::Binder` to preserve the exception code | 
 | 94 |             // for logging. | 
 | 95 |             // `map_or_log_err` will map this on a system error. | 
 | 96 |             e_code => Error::Binder(e_code, 0), | 
 | 97 |         } | 
 | 98 |     }) | 
 | 99 | } | 
 | 100 |  | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 101 | /// This function should be used by Keystore service calls to translate error conditions | 
| Janis Danisevskis | 8ea5f55 | 2020-11-20 11:22:59 -0800 | [diff] [blame] | 102 | /// into service specific exceptions. | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 103 | /// | 
| Janis Danisevskis | 8ea5f55 | 2020-11-20 11:22:59 -0800 | [diff] [blame] | 104 | /// All error conditions get logged by this function. | 
 | 105 | /// | 
 | 106 | /// All `Error::Rc(x)` and `Error::Km(x)` variants get mapped onto a service specific error | 
 | 107 | /// code of x. This is possible because KeyMint `ErrorCode` errors are always negative and | 
 | 108 | /// `ResponseCode` codes are always positive. | 
 | 109 | /// `selinux::Error::PermissionDenied` is mapped on `ResponseCode::PERMISSION_DENIED`. | 
 | 110 | /// | 
 | 111 | /// All non `Error` error conditions and the Error::Binder variant get mapped onto | 
 | 112 | /// ResponseCode::SYSTEM_ERROR`. | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 113 | /// | 
 | 114 | /// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed | 
| Janis Danisevskis | 8ea5f55 | 2020-11-20 11:22:59 -0800 | [diff] [blame] | 115 | /// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it | 
 | 116 | /// typically returns Ok(value). | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 117 | /// | 
 | 118 | /// # Examples | 
 | 119 | /// | 
 | 120 | /// ``` | 
| Janis Danisevskis | 8ea5f55 | 2020-11-20 11:22:59 -0800 | [diff] [blame] | 121 | /// fn loadKey() -> anyhow::Result<Vec<u8>> { | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 122 | ///     if (good_but_auth_required) { | 
| Janis Danisevskis | 8ea5f55 | 2020-11-20 11:22:59 -0800 | [diff] [blame] | 123 | ///         Ok(vec!['k', 'e', 'y']) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 124 | ///     } else { | 
| Janis Danisevskis | 8ea5f55 | 2020-11-20 11:22:59 -0800 | [diff] [blame] | 125 | ///         Err(anyhow!(Error::Rc(ResponseCode::KEY_NOT_FOUND))) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 126 | ///     } | 
 | 127 | /// } | 
 | 128 | /// | 
| Janis Danisevskis | 8ea5f55 | 2020-11-20 11:22:59 -0800 | [diff] [blame] | 129 | /// map_or_log_err(loadKey(), Ok) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 130 | /// ``` | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 131 | pub fn map_or_log_err<T, U, F>(result: anyhow::Result<U>, handle_ok: F) -> BinderResult<T> | 
 | 132 | where | 
 | 133 |     F: FnOnce(U) -> BinderResult<T>, | 
 | 134 | { | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 135 |     result.map_or_else( | 
 | 136 |         |e| { | 
 | 137 |             log::error!("{:?}", e); | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 138 |             let root_cause = e.root_cause(); | 
 | 139 |             let rc = match root_cause.downcast_ref::<Error>() { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 140 |                 Some(Error::Rc(rcode)) => rcode.0, | 
 | 141 |                 Some(Error::Km(ec)) => ec.0, | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 142 |                 // If an Error::Binder reaches this stage we report a system error. | 
 | 143 |                 // The exception code and possible service specific error will be | 
 | 144 |                 // printed in the error log above. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 145 |                 Some(Error::Binder(_, _)) => ResponseCode::SYSTEM_ERROR.0, | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 146 |                 None => match root_cause.downcast_ref::<selinux::Error>() { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 147 |                     Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0, | 
 | 148 |                     _ => ResponseCode::SYSTEM_ERROR.0, | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 149 |                 }, | 
 | 150 |             }; | 
 | 151 |             Err(BinderStatus::new_service_specific_error(rc, None)) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 152 |         }, | 
 | 153 |         handle_ok, | 
 | 154 |     ) | 
 | 155 | } | 
 | 156 |  | 
 | 157 | #[cfg(test)] | 
| Hasini Gunasinghe | af99366 | 2020-07-24 18:40:20 +0000 | [diff] [blame] | 158 | pub mod tests { | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 159 |  | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 160 |     use super::*; | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 161 |     use android_system_keystore2::binder::{ | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 162 |         ExceptionCode, Result as BinderResult, Status as BinderStatus, | 
 | 163 |     }; | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 164 |     use anyhow::{anyhow, Context}; | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 165 |  | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 166 |     fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> { | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 167 |         Err(anyhow!(Error::Rc(rc))).context("nested nested rc") | 
 | 168 |     } | 
 | 169 |  | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 170 |     fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> { | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 171 |         nested_nested_rc(rc).context("nested rc") | 
 | 172 |     } | 
 | 173 |  | 
 | 174 |     fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> { | 
 | 175 |         Err(anyhow!(Error::Km(ec))).context("nested nested ec") | 
 | 176 |     } | 
 | 177 |  | 
 | 178 |     fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> { | 
 | 179 |         nested_nested_ec(ec).context("nested ec") | 
 | 180 |     } | 
 | 181 |  | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 182 |     fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> { | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 183 |         Ok(rc) | 
 | 184 |     } | 
 | 185 |  | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 186 |     fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> { | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 187 |         nested_nested_ok(rc).context("nested ok") | 
 | 188 |     } | 
 | 189 |  | 
| Janis Danisevskis | ce99543 | 2020-07-21 12:22:34 -0700 | [diff] [blame] | 190 |     fn nested_nested_selinux_perm() -> anyhow::Result<()> { | 
 | 191 |         Err(anyhow!(selinux::Error::perm())).context("nested nexted selinux permission denied") | 
 | 192 |     } | 
 | 193 |  | 
 | 194 |     fn nested_selinux_perm() -> anyhow::Result<()> { | 
 | 195 |         nested_nested_selinux_perm().context("nested selinux permission denied") | 
 | 196 |     } | 
 | 197 |  | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 198 |     #[derive(Debug, thiserror::Error)] | 
 | 199 |     enum TestError { | 
 | 200 |         #[error("TestError::Fail")] | 
 | 201 |         Fail = 0, | 
 | 202 |     } | 
 | 203 |  | 
 | 204 |     fn nested_nested_other_error() -> anyhow::Result<()> { | 
 | 205 |         Err(anyhow!(TestError::Fail)).context("nested nested other error") | 
 | 206 |     } | 
 | 207 |  | 
 | 208 |     fn nested_other_error() -> anyhow::Result<()> { | 
 | 209 |         nested_nested_other_error().context("nested other error") | 
 | 210 |     } | 
 | 211 |  | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 212 |     fn binder_sse_error(sse: i32) -> BinderResult<()> { | 
 | 213 |         Err(BinderStatus::new_service_specific_error(sse, None)) | 
 | 214 |     } | 
 | 215 |  | 
 | 216 |     fn binder_exception(ex: ExceptionCode) -> BinderResult<()> { | 
 | 217 |         Err(BinderStatus::new_exception(ex, None)) | 
 | 218 |     } | 
 | 219 |  | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 220 |     #[test] | 
 | 221 |     fn keystore_error_test() -> anyhow::Result<(), String> { | 
 | 222 |         android_logger::init_once( | 
 | 223 |             android_logger::Config::default() | 
 | 224 |                 .with_tag("keystore_error_tests") | 
 | 225 |                 .with_min_level(log::Level::Debug), | 
 | 226 |         ); | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 227 |         // All Error::Rc(x) get mapped on a service specific error | 
 | 228 |         // code of x. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 229 |         for rc in ResponseCode::LOCKED.0..ResponseCode::BACKEND_BUSY.0 { | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 230 |             assert_eq!( | 
 | 231 |                 Result::<(), i32>::Err(rc), | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 232 |                 map_or_log_err(nested_rc(ResponseCode(rc)), |_| Err(BinderStatus::ok())) | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 233 |                     .map_err(|s| s.service_specific_error()) | 
 | 234 |             ); | 
 | 235 |         } | 
 | 236 |  | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 237 |         // All Keystore Error::Km(x) get mapped on a service | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 238 |         // specific error of x. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 239 |         for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 { | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 240 |             assert_eq!( | 
 | 241 |                 Result::<(), i32>::Err(ec), | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 242 |                 map_or_log_err(nested_ec(ErrorCode(ec)), |_| Err(BinderStatus::ok())) | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 243 |                     .map_err(|s| s.service_specific_error()) | 
 | 244 |             ); | 
 | 245 |         } | 
 | 246 |  | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 247 |         // All Keymint errors x received through a Binder Result get mapped on | 
 | 248 |         // a service specific error of x. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 249 |         for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 { | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 250 |             assert_eq!( | 
 | 251 |                 Result::<(), i32>::Err(ec), | 
 | 252 |                 map_or_log_err( | 
 | 253 |                     map_km_error(binder_sse_error(ec)) | 
 | 254 |                         .with_context(|| format!("Km error code: {}.", ec)), | 
 | 255 |                     |_| Err(BinderStatus::ok()) | 
 | 256 |                 ) | 
 | 257 |                 .map_err(|s| s.service_specific_error()) | 
 | 258 |             ); | 
 | 259 |         } | 
 | 260 |  | 
 | 261 |         // map_km_error creates an Error::Binder variant storing | 
 | 262 |         // ExceptionCode::SERVICE_SPECIFIC and the given | 
 | 263 |         // service specific error. | 
 | 264 |         let sse = map_km_error(binder_sse_error(1)); | 
 | 265 |         assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse); | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 266 |         // map_or_log_err then maps it on a service specific error of ResponseCode::SYSTEM_ERROR. | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 267 |         assert_eq!( | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 268 |             Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR), | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 269 |             map_or_log_err(sse.context("Non negative service specific error."), |_| Err( | 
 | 270 |                 BinderStatus::ok() | 
 | 271 |             )) | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 272 |             .map_err(|s| ResponseCode(s.service_specific_error())) | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 273 |         ); | 
 | 274 |  | 
 | 275 |         // map_km_error creates a Error::Binder variant storing the given exception code. | 
 | 276 |         let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED)); | 
 | 277 |         assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception); | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 278 |         // map_or_log_err then maps it on a service specific error of ResponseCode::SYSTEM_ERROR. | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 279 |         assert_eq!( | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 280 |             Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR), | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 281 |             map_or_log_err(binder_exception.context("Binder Exception."), |_| Err( | 
 | 282 |                 BinderStatus::ok() | 
 | 283 |             )) | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 284 |             .map_err(|s| ResponseCode(s.service_specific_error())) | 
| Janis Danisevskis | 017d209 | 2020-09-02 10:15:52 -0700 | [diff] [blame] | 285 |         ); | 
 | 286 |  | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 287 |         // selinux::Error::Perm() needs to be mapped to ResponseCode::PERMISSION_DENIED | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 288 |         assert_eq!( | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 289 |             Result::<(), ResponseCode>::Err(ResponseCode::PERMISSION_DENIED), | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 290 |             map_or_log_err(nested_selinux_perm(), |_| Err(BinderStatus::ok())) | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 291 |                 .map_err(|s| ResponseCode(s.service_specific_error())) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 292 |         ); | 
 | 293 |  | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 294 |         // All other errors get mapped on System Error. | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 295 |         assert_eq!( | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 296 |             Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR), | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 297 |             map_or_log_err(nested_other_error(), |_| Err(BinderStatus::ok())) | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 298 |                 .map_err(|s| ResponseCode(s.service_specific_error())) | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 299 |         ); | 
 | 300 |  | 
 | 301 |         // Result::Ok variants get passed to the ok handler. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 302 |         assert_eq!(Ok(ResponseCode::LOCKED), map_or_log_err(nested_ok(ResponseCode::LOCKED), Ok)); | 
 | 303 |         assert_eq!( | 
 | 304 |             Ok(ResponseCode::SYSTEM_ERROR), | 
 | 305 |             map_or_log_err(nested_ok(ResponseCode::SYSTEM_ERROR), Ok) | 
 | 306 |         ); | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 307 |  | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 308 |         Ok(()) | 
 | 309 |     } | 
| Hasini Gunasinghe | af99366 | 2020-07-24 18:40:20 +0000 | [diff] [blame] | 310 |  | 
 | 311 |     //Helper function to test whether error cases are handled as expected. | 
| Janis Danisevskis | e24f347 | 2020-08-12 17:58:49 -0700 | [diff] [blame] | 312 |     pub fn check_result_contains_error_string<T>( | 
 | 313 |         result: anyhow::Result<T>, | 
 | 314 |         expected_error_string: &str, | 
 | 315 |     ) { | 
| Hasini Gunasinghe | af99366 | 2020-07-24 18:40:20 +0000 | [diff] [blame] | 316 |         let error_str = format!( | 
 | 317 |             "{:#?}", | 
 | 318 |             result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string)) | 
 | 319 |         ); | 
 | 320 |         assert!( | 
 | 321 |             error_str.contains(expected_error_string), | 
 | 322 |             "The string \"{}\" should contain \"{}\"", | 
 | 323 |             error_str, | 
 | 324 |             expected_error_string | 
 | 325 |         ); | 
 | 326 |     } | 
| Janis Danisevskis | 7d77a76 | 2020-07-20 13:03:31 -0700 | [diff] [blame] | 327 | } // mod tests |