xref: /aosp_15_r20/bootable/libbootloader/gbl/liberror/src/lib.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1 // Copyright 2024, 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 //! Unified error type library
16 //!
17 //! This crate defines a common error type for all of GBL.
18 //! It is intended to reduce conversion boilerplate and to make
19 //! the various GBL libraries interoperate more cleanly.
20 //!
21 //! Because of its intended broad application, certain error types will
22 //! be highly specific to particular libraries.
23 //! More specific errors can be useful when writing unit tests or when defining
24 //! APIs that third party code may interact with.
25 //! It's a judgement call whether a new variant should be added,
26 //! but if possible try to use an existing variant.
27 //!
28 //! It is a further judgement call whether a new variant should wrap a payload.
29 //! The rule of thumb is that a payload requires one of the following conditions:
30 //! 1) The error will be logged and the payload will help with debugging.
31 //! 2) The error is transient or retriable, and the payload helps with the retry.
32 //!
33 //! New error variants should be inserted alphabetically.
34 
35 #![cfg_attr(not(any(test, android_dylib)), no_std)]
36 
37 use core::{
38     ffi::{FromBytesUntilNulError, FromBytesWithNulError},
39     str::Utf8Error,
40 };
41 
42 use efi_types as efi;
43 
44 /// Gpt related errors.
45 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
46 pub enum GptError {
47     /// Secondary header is valid, but different from primary.
48     DifferentFromPrimary,
49     /// Disk size is not enough to accommodate maximum allowed entries.
50     DiskTooSmall,
51     /// GPT entries buffer is too small for the expected number of entries.
52     EntriesTruncated,
53     /// GPT header CRC is not correct.
54     IncorrectHeaderCrc,
55     /// GPT header MAGIC is not correct.
56     IncorrectMagic(u64),
57     /// GPT entries CRC doesn't match.
58     IncorrectEntriesCrc,
59     /// Invalid first and last usable block in the GPT header.
60     InvalidFirstLastUsableBlock {
61         /// The value of first usable block in the GPT header.
62         first: u64,
63         /// The value of last usable block in the GPT header.
64         last: u64,
65         /// Expected range inclusive.
66         range: (u64, u64),
67     },
68     /// Partition range is invalid.
69     InvalidPartitionRange {
70         /// Partition index (1-based).
71         idx: usize,
72         /// Range of the partition, inclusive.
73         part_range: (u64, u64),
74         /// Range of usable block, inclusive.
75         usable_range: (u64, u64),
76     },
77     /// Invalid start block for primary GPT entries.
78     InvalidPrimaryEntriesStart {
79         /// The entry start block value.
80         value: u64,
81         /// Expected range.
82         expect_range: (u64, u64),
83     },
84     /// Invalid start block for secondary GPT entries.
85     InvalidSecondaryEntriesStart {
86         /// The entry start block value.
87         value: u64,
88         /// Expected range.
89         expect_range: (u64, u64),
90     },
91     /// Number of entries greater than maximum allowed.
92     NumberOfEntriesOverflow {
93         /// Actual number of entries,
94         entries: u32,
95         /// Maximum allowed.
96         max_allowed: usize,
97     },
98     /// Two partitions overlap.
99     PartitionRangeOverlap {
100         /// Previous partition in overlap. (partition index, first, last)
101         prev: (usize, u64, u64),
102         /// Next partition in overlap. (partition index, first, last)
103         next: (usize, u64, u64),
104     },
105     /// Unexpected GPT header size.
106     UnexpectedEntrySize {
107         /// The actual entry size in the GPT header.
108         actual: u32,
109         /// The expected size.
110         expect: usize,
111     },
112     /// Unexpected GPT header size.
113     UnexpectedHeaderSize {
114         /// The actual header size in the GPT header.
115         actual: u32,
116         /// The expected size.
117         expect: usize,
118     },
119     /// Zero partition type GUID.
120     ZeroPartitionTypeGUID {
121         /// Partition index (1-based).
122         idx: usize,
123     },
124     /// Zero partition unique GUID.
125     ZeroPartitionUniqueGUID {
126         /// Partition index (1-based).
127         idx: usize,
128     },
129 }
130 
131 /// Common, universal error type
132 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
133 pub enum Error {
134     /// An operation has been aborted. Useful for async or IO operations.
135     Aborted,
136     /// Access was denied.
137     AccessDenied,
138     /// The protocol has already been started.
139     AlreadyStarted,
140     /// A checked arithmetic operation has overflowed.
141     ArithmeticOverflow(safemath::Error),
142     /// The buffer was not the proper size for the request (different from BufferTooSmall).
143     BadBufferSize,
144     /// Data verification has encountered an invalid checksum.
145     BadChecksum,
146     /// An operation attempted to access data outside of the valid range.
147     /// Includes the problematic index.
148     BadIndex(usize),
149     /// Data verification has encountered an invalid magic number.
150     BadMagic,
151     /// Generic BlockIO error.
152     BlockIoError,
153     /// Generic boot failure has occurred.
154     BootFailed,
155     /// Buffers provided by third party code overlap.
156     BufferOverlap,
157     /// The provided buffer is too small.
158     /// If Some(n), provides the minimum required buffer size.
159     BufferTooSmall(Option<usize>),
160     /// The security status of the data is unknown or compromised
161     /// and the data must be updated or replaced to restore a valid security status.
162     CompromisedData,
163     /// The remote peer has reset the network connection.
164     ConnectionReset,
165     /// A relevant device encountered an error.
166     DeviceError,
167     /// The connected peripheral or network peer has disconnected.
168     Disconnected,
169     /// The end of the file was reached.
170     EndOfFile,
171     /// Beginning or end of media was reached
172     EndOfMedia,
173     /// A polled operation has finished
174     Finished,
175     /// GPT related errors.
176     GptError(GptError),
177     /// A HTTP error occurred during a network operation.
178     HttpError,
179     /// An ICMP error occurred during a network operation.
180     IcmpError,
181     /// The provided buffer or data structure is invalidly aligned.
182     InvalidAlignment,
183     /// A connected agent failed a multi-stage handshake.
184     InvalidHandshake,
185     /// At least one parameter fails preconditions.
186     InvalidInput,
187     /// The language specified was invalid.
188     InvalidLanguage,
189     /// A state machine has entered an invalid state.
190     InvalidState,
191     /// There was a conflict in IP address allocation.
192     IpAddressConflict,
193     /// Image failed to load
194     LoadError,
195     /// The medium in the device has changed since the last access.
196     MediaChanged,
197     /// Memory map error with error code.
198     MemoryMapCallbackError(i64),
199     /// An image required for system boot is missing.
200     MissingImage,
201     /// A valid Flattened Device Tree was not found.
202     NoFdt,
203     /// The block device does not have a valid GUID Partition Table.
204     NoGpt,
205     /// A mapping to a device does not exist.
206     NoMapping,
207     /// The device does not contain any medium to perform the operation.
208     NoMedia,
209     /// The server was not found or did not respond to the request.
210     NoResponse,
211     /// The requested element (e.g. device, partition, or value) was not found.
212     NotFound,
213     /// The default implementation for a trait method has not been overridden.
214     NotImplemented,
215     /// The polled device or future is not ready.
216     NotReady,
217     /// The protocol has not been started.
218     NotStarted,
219     /// The provided name does not uniquely describe a partition.
220     NotUnique,
221     /// Generic permissions failure.
222     OperationProhibited,
223     /// Catch-all error with optional debugging string.
224     Other(Option<&'static str>),
225     /// A resource has run out.
226     OutOfResources,
227     /// A protocol error occurred during the network operation.
228     ProtocolError,
229     /// The function was not performed due to a security violation.
230     SecurityViolation,
231     /// A TFTP error occurred during a network operation.
232     TftpError,
233     /// Operation has timed out.
234     Timeout,
235     /// The remote network endpoint is not addressable.
236     Unaddressable,
237     /// An unknown, unexpected EFI_STATUS error code was returned,
238     UnexpectedEfiError(efi::EfiStatus),
239     /// Operation is unsupported
240     Unsupported,
241     /// Data verification has encountered a version number that is not supported.
242     UnsupportedVersion,
243     /// An inconstancy was detected on the file system causing the operating to fail.
244     VolumeCorrupted,
245     /// There is no more space on the file system.
246     VolumeFull,
247     /// The device cannot be written to.
248     WriteProtected,
249 }
250 
251 impl From<Option<&'static str>> for Error {
from(val: Option<&'static str>) -> Self252     fn from(val: Option<&'static str>) -> Self {
253         Self::Other(val)
254     }
255 }
256 
257 impl From<&'static str> for Error {
from(val: &'static str) -> Self258     fn from(val: &'static str) -> Self {
259         Self::Other(Some(val))
260     }
261 }
262 
263 impl From<safemath::Error> for Error {
from(err: safemath::Error) -> Self264     fn from(err: safemath::Error) -> Self {
265         Self::ArithmeticOverflow(err)
266     }
267 }
268 
269 impl From<core::num::TryFromIntError> for Error {
270     #[track_caller]
from(err: core::num::TryFromIntError) -> Self271     fn from(err: core::num::TryFromIntError) -> Self {
272         Self::ArithmeticOverflow(err.into())
273     }
274 }
275 
276 impl From<FromBytesUntilNulError> for Error {
from(_: FromBytesUntilNulError) -> Self277     fn from(_: FromBytesUntilNulError) -> Self {
278         Self::InvalidInput
279     }
280 }
281 
282 impl From<FromBytesWithNulError> for Error {
from(_: FromBytesWithNulError) -> Self283     fn from(_: FromBytesWithNulError) -> Self {
284         Self::InvalidInput
285     }
286 }
287 
288 impl From<Utf8Error> for Error {
from(_: Utf8Error) -> Self289     fn from(_: Utf8Error) -> Self {
290         Self::InvalidInput
291     }
292 }
293 
294 impl core::fmt::Display for Error {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result295     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
296         write!(f, "{:#?}", self)
297     }
298 }
299 
300 impl From<core::fmt::Error> for Error {
from(_: core::fmt::Error) -> Self301     fn from(_: core::fmt::Error) -> Self {
302         Self::Unsupported
303     }
304 }
305 
306 /// Helper type alias.
307 pub type Result<T> = core::result::Result<T, Error>;
308 
309 /// Workaround for orphan rule.
efi_status_to_result(e: efi::EfiStatus) -> Result<()>310 pub fn efi_status_to_result(e: efi::EfiStatus) -> Result<()> {
311     match e {
312         efi::EFI_STATUS_SUCCESS => Ok(()),
313         efi::EFI_STATUS_CRC_ERROR => Err(Error::BadChecksum),
314         efi::EFI_STATUS_ABORTED => Err(Error::Aborted),
315         efi::EFI_STATUS_ACCESS_DENIED => Err(Error::AccessDenied),
316         efi::EFI_STATUS_ALREADY_STARTED => Err(Error::AlreadyStarted),
317         efi::EFI_STATUS_BAD_BUFFER_SIZE => Err(Error::BadBufferSize),
318         efi::EFI_STATUS_BUFFER_TOO_SMALL => Err(Error::BufferTooSmall(None)),
319         efi::EFI_STATUS_COMPROMISED_DATA => Err(Error::CompromisedData),
320         efi::EFI_STATUS_CONNECTION_FIN => Err(Error::Disconnected),
321         efi::EFI_STATUS_CONNECTION_REFUSED => Err(Error::OperationProhibited),
322         efi::EFI_STATUS_CONNECTION_RESET => Err(Error::ConnectionReset),
323         efi::EFI_STATUS_DEVICE_ERROR => Err(Error::DeviceError),
324         efi::EFI_STATUS_END_OF_FILE => Err(Error::EndOfFile),
325         efi::EFI_STATUS_END_OF_MEDIA => Err(Error::EndOfMedia),
326         efi::EFI_STATUS_HTTP_ERROR => Err(Error::HttpError),
327         efi::EFI_STATUS_ICMP_ERROR => Err(Error::IcmpError),
328         efi::EFI_STATUS_INCOMPATIBLE_VERSION => Err(Error::UnsupportedVersion),
329         efi::EFI_STATUS_INVALID_LANGUAGE => Err(Error::InvalidLanguage),
330         efi::EFI_STATUS_INVALID_PARAMETER => Err(Error::InvalidInput),
331         efi::EFI_STATUS_IP_ADDRESS_CONFLICT => Err(Error::IpAddressConflict),
332         efi::EFI_STATUS_LOAD_ERROR => Err(Error::LoadError),
333         efi::EFI_STATUS_MEDIA_CHANGED => Err(Error::MediaChanged),
334         efi::EFI_STATUS_NOT_FOUND => Err(Error::NotFound),
335         efi::EFI_STATUS_NOT_READY => Err(Error::NotReady),
336         efi::EFI_STATUS_NOT_STARTED => Err(Error::NotStarted),
337         efi::EFI_STATUS_NO_MAPPING => Err(Error::NoMapping),
338         efi::EFI_STATUS_NO_MEDIA => Err(Error::NoMedia),
339         efi::EFI_STATUS_NO_RESPONSE => Err(Error::NoResponse),
340         efi::EFI_STATUS_OUT_OF_RESOURCES => Err(Error::OutOfResources),
341         efi::EFI_STATUS_PROTOCOL_ERROR => Err(Error::ProtocolError),
342         efi::EFI_STATUS_SECURITY_VIOLATION => Err(Error::SecurityViolation),
343         efi::EFI_STATUS_TFTP_ERROR => Err(Error::TftpError),
344         efi::EFI_STATUS_TIMEOUT => Err(Error::Timeout),
345         efi::EFI_STATUS_UNSUPPORTED => Err(Error::Unsupported),
346         efi::EFI_STATUS_VOLUME_CORRUPTED => Err(Error::VolumeCorrupted),
347         efi::EFI_STATUS_VOLUME_FULL => Err(Error::VolumeFull),
348         efi::EFI_STATUS_WRITE_PROTECTED => Err(Error::WriteProtected),
349         // The UEFI spec reserves part of the error space for
350         // OEM defined errors and warnings.
351         // We can't know in advance what these are or what they mean,
352         // so just preserve them as is.
353         e => Err(Error::UnexpectedEfiError(e)),
354     }
355 }
356 
357 #[cfg(test)]
358 mod test {
359     use super::*;
360 
361     #[test]
test_from_safemath_error()362     fn test_from_safemath_error() {
363         let n = u8::try_from(safemath::SafeNum::ZERO - 1).unwrap_err();
364         let _e: Error = n.into();
365     }
366 
367     #[test]
test_from_str()368     fn test_from_str() {
369         let _e: Error = "error string".into();
370     }
371 
372     #[test]
test_from_str_option()373     fn test_from_str_option() {
374         let _e: Error = Some("error string").into();
375         let n: Option<&str> = None;
376         let _e2: Error = n.into();
377     }
378 }
379