Skip to main content

optee_teec/
error.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::raw;
19use num_enum::{FromPrimitive, IntoPrimitive};
20use std::fmt;
21
22/// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
23/// type for TEE operations.
24///
25/// # Examples
26///
27/// ``` no_run
28/// use optee_teec::Context;
29///
30/// fn main() -> optee_teec::Result<()> {
31///     let mut ctx = Context::new()?;
32///     Ok(())
33/// }
34/// ````
35pub type Result<T> = std::result::Result<T, Error>;
36
37/// Checks the result of a TEE client API call, converting a non-success code
38/// into [`Error`].
39pub(crate) fn teec_check(code: raw::TEEC_Result) -> Result<()> {
40    match code {
41        raw::TEEC_SUCCESS => Ok(()),
42        code => Err(Error::from_raw_error(code)),
43    }
44}
45
46/// Like [`teec_check`], but attaches the error origin returned by the TEE
47/// client API on failure.
48pub(crate) fn teec_check_with_origin(code: raw::TEEC_Result, origin: u32) -> Result<()> {
49    match code {
50        raw::TEEC_SUCCESS => Ok(()),
51        code => Err(Error::from_raw_error(code).with_origin(origin.into())),
52    }
53}
54
55/// The error type for TEE operations of [`Context`] and [`Session`].
56///
57/// [`Context`]: struct.Context.html
58/// [`Session`]: struct.Session.html
59#[derive(Clone)]
60pub struct Error {
61    kind: ErrorKind,
62    origin: Option<ErrorOrigin>,
63}
64
65/// A list specifying general categories of TEE client error and its
66/// corresponding code in OP-TEE client library.
67#[derive(
68    Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, FromPrimitive, IntoPrimitive,
69)]
70#[repr(u32)]
71pub enum ErrorKind {
72    /// Non-specific cause.
73    Generic = raw::TEEC_ERROR_GENERIC,
74    /// Access privileges are not sufficient.
75    AccessDenied = raw::TEEC_ERROR_ACCESS_DENIED,
76    /// The operation was canceled.
77    Cancel = raw::TEEC_ERROR_CANCEL,
78    /// Concurrent accesses caused conflict.
79    AccessConflict = raw::TEEC_ERROR_ACCESS_CONFLICT,
80    /// Too much data for the requested operation was passed.
81    ExcessData = raw::TEEC_ERROR_EXCESS_DATA,
82    /// Input data was of invalid format.
83    BadFormat = raw::TEEC_ERROR_BAD_FORMAT,
84    /// Input parameters were invalid.
85    BadParameters = raw::TEEC_ERROR_BAD_PARAMETERS,
86    /// Operation is not valid in the current state.
87    BadState = raw::TEEC_ERROR_BAD_STATE,
88    /// The requested data item is not found.
89    ItemNotFound = raw::TEEC_ERROR_ITEM_NOT_FOUND,
90    /// The requested operation should exist but is not yet implemented.
91    NotImplemented = raw::TEEC_ERROR_NOT_IMPLEMENTED,
92    /// The requested operation is valid but is not supported in this implementation.
93    NotSupported = raw::TEEC_ERROR_NOT_SUPPORTED,
94    /// Expected data was missing.
95    NoData = raw::TEEC_ERROR_NO_DATA,
96    /// System ran out of resources.
97    OutOfMemory = raw::TEEC_ERROR_OUT_OF_MEMORY,
98    /// The system is busy working on something else.
99    Busy = raw::TEEC_ERROR_BUSY,
100    /// Communication with a remote party failed.
101    Communication = raw::TEEC_ERROR_COMMUNICATION,
102    /// A security fault was detected.
103    Security = raw::TEEC_ERROR_SECURITY,
104    /// The supplied buffer is too short for the generated output.
105    ShortBuffer = raw::TEEC_ERROR_SHORT_BUFFER,
106    /// Implementation defined error code.
107    ExternalCancel = raw::TEEC_ERROR_EXTERNAL_CANCEL,
108    /// Implementation defined error code: trusted Application has panicked during the operation.
109    TargetDead = raw::TEEC_ERROR_TARGET_DEAD,
110    /// Unknown error, holding the original raw code.
111    #[num_enum(catch_all)]
112    Unknown(u32),
113}
114
115impl ErrorKind {
116    pub(crate) fn as_str(&self) -> &'static str {
117        match self {
118            ErrorKind::Generic => "Non-specific cause.",
119            ErrorKind::AccessDenied => "Access privileges are not sufficient.",
120            ErrorKind::Cancel => "The operation was canceled.",
121            ErrorKind::AccessConflict => "Concurrent accesses caused conflict.",
122            ErrorKind::ExcessData => "Too much data for the requested operation was passed.",
123            ErrorKind::BadFormat => "Input data was of invalid format.",
124            ErrorKind::BadParameters => "Input parameters were invalid.",
125            ErrorKind::BadState => "Operation is not valid in the current state.",
126            ErrorKind::ItemNotFound => "The requested data item is not found.",
127            ErrorKind::NotImplemented => {
128                "The requested operation should exist but is not yet implemented."
129            }
130            ErrorKind::NotSupported => {
131                "The requested operation is valid but is not supported in this implementation."
132            }
133            ErrorKind::NoData => "Expected data was missing.",
134            ErrorKind::OutOfMemory => "System ran out of resources.",
135            ErrorKind::Busy => "The system is busy working on something else.",
136            ErrorKind::Communication => "Communication with a remote party failed.",
137            ErrorKind::Security => "A security fault was detected.",
138            ErrorKind::ShortBuffer => "The supplied buffer is too short for the generated output.",
139            ErrorKind::ExternalCancel => "Undocumented.",
140            ErrorKind::TargetDead => "Trusted Application has panicked during the operation.",
141            ErrorKind::Unknown(_) => "Unknown error.",
142        }
143    }
144}
145
146impl Error {
147    pub fn new(kind: ErrorKind) -> Error {
148        kind.into()
149    }
150    /// Creates a new instance of an `Error` from a particular TEE error code.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// use optee_teec::{Error, ErrorKind};
156    ///
157    /// let error = Error::from_raw_error(0xFFFF000F);
158    /// assert_eq!(error.kind(), ErrorKind::Security);
159    /// ```
160    pub fn from_raw_error(code: u32) -> Error {
161        ErrorKind::from(code).into()
162    }
163
164    pub fn with_origin(mut self, origin: ErrorOrigin) -> Self {
165        self.origin = Some(origin);
166        self
167    }
168
169    /// Returns the corresponding `ErrorKind` for this error.
170    ///
171    /// # Examples
172    ///
173    /// ```
174    /// use optee_teec::{Error, ErrorKind};
175    ///
176    /// let error = Error::new(ErrorKind::Security);
177    /// ```
178    pub fn kind(&self) -> ErrorKind {
179        self.kind
180    }
181
182    /// Returns the origin of this error.
183    pub fn origin(&self) -> Option<ErrorOrigin> {
184        self.origin.clone()
185    }
186
187    /// Returns raw code of this error.
188    pub fn raw_code(&self) -> u32 {
189        self.kind.into()
190    }
191
192    /// Returns corresponding error message of this error.
193    pub fn message(&self) -> &str {
194        self.kind().as_str()
195    }
196}
197
198impl fmt::Debug for Error {
199    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
200        write!(
201            fmt,
202            "{} (error code 0x{:x}, origin 0x{:x})",
203            self.message(),
204            self.raw_code(),
205            self.origin().map(|v| v.into()).unwrap_or(0_u32),
206        )
207    }
208}
209
210impl fmt::Display for Error {
211    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212        fmt::Debug::fmt(self, f)
213    }
214}
215
216impl std::error::Error for Error {
217    fn description(&self) -> &str {
218        self.message()
219    }
220}
221
222impl From<ErrorKind> for Error {
223    #[inline]
224    fn from(kind: ErrorKind) -> Error {
225        Error { kind, origin: None }
226    }
227}
228
229#[derive(Clone, Debug, Eq, PartialEq, FromPrimitive, IntoPrimitive)]
230#[repr(u32)]
231pub enum ErrorOrigin {
232    API = raw::TEEC_ORIGIN_API,
233    COMMS = raw::TEEC_ORIGIN_COMMS,
234    TEE = raw::TEEC_ORIGIN_TEE,
235    TA = raw::TEEC_ORIGIN_TRUSTED_APP,
236    #[default]
237    UNKNOWN,
238}
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243
244    /// Guarantees: unrecognized codes are preserved in the catch-all variant
245    /// and round-trip through `Error`.
246    #[test]
247    fn unknown_raw_code_round_trips() {
248        let code = 0x1234_5678;
249        assert_eq!(ErrorKind::from(code), ErrorKind::Unknown(code));
250        let back: u32 = ErrorKind::Unknown(code).into();
251        assert_eq!(back, code);
252
253        let err = Error::from_raw_error(code);
254        assert_eq!(err.kind(), ErrorKind::Unknown(code));
255        assert_eq!(err.raw_code(), code);
256    }
257}