[bssl] Improve error processing when BoringSSL API fails
This cl logs Bssl the reason and library strings for all the
errors from the Bssl's error queue when an API fails and returns
the most recent error instead of the least recent one.
The logging is helpful for debugging as not all the Bssl error
codes are mapped into readable enums.
Test: atest libbssl_avf_nostd.test
Change-Id: Ifaad4acfb43461ce2794a9fd2b60ac9beb64a238
diff --git a/libs/bssl/src/err.rs b/libs/bssl/src/err.rs
index 60bab98..a53ac8c 100644
--- a/libs/bssl/src/err.rs
+++ b/libs/bssl/src/err.rs
@@ -14,27 +14,90 @@
//! Wrappers of the error handling functions in BoringSSL err.h.
+use alloc::string::{String, ToString};
use bssl_avf_error::{CipherError, EcError, EcdsaError, GlobalError, ReasonCode};
-use bssl_sys::{self, ERR_get_error, ERR_GET_LIB_RUST, ERR_GET_REASON_RUST};
+use bssl_sys::{
+ self, ERR_get_error_line, ERR_lib_error_string, ERR_reason_error_string, ERR_GET_LIB_RUST,
+ ERR_GET_REASON_RUST,
+};
+use core::ffi::{c_char, CStr};
+use core::ptr;
+use log::{error, info};
const NO_ERROR_REASON_CODE: i32 = 0;
-/// Returns the reason code for the least recent error and removes that
-/// error from the error queue.
-pub(crate) fn get_error_reason_code() -> ReasonCode {
- let packed_error = get_packed_error();
+/// Processes the error queue till it is empty, logs the information for all the errors in
+/// the queue from the least recent to the most recent, and returns the reason code for the
+/// most recent error.
+pub(crate) fn process_error_queue() -> ReasonCode {
+ let mut reason_code = ReasonCode::NoError;
+ loop {
+ let code = process_least_recent_error();
+ if code == ReasonCode::NoError {
+ break;
+ }
+ reason_code = code;
+ }
+ reason_code
+}
+
+/// Removes the least recent error in the error queue and logs the error information.
+///
+/// Returns the reason code for the least recent error.
+fn process_least_recent_error() -> ReasonCode {
+ let mut file = ptr::null();
+ let mut line = 0;
+ // SAFETY: This function only reads the error queue and writes to the given
+ // pointers. It doesn't retain any references to the pointers.
+ let packed_error = unsafe { ERR_get_error_line(&mut file, &mut line) };
let reason = get_reason(packed_error);
+ if reason == NO_ERROR_REASON_CODE {
+ info!("No error in the BoringSSL error queue");
+ return ReasonCode::NoError;
+ }
+
+ // SAFETY: Any non-null result is expected to point to a global const C string.
+ let file = unsafe { cstr_to_string(file, "<unknown file>") };
+ error!(
+ "BoringSSL error: {}:{}: lib = {}, reason = {}",
+ file,
+ line,
+ lib_error_string(packed_error),
+ reason_error_string(packed_error),
+ );
+
let lib = get_lib(packed_error);
map_to_reason_code(reason, lib)
}
-/// Returns the packed error code for the least recent error and removes that
-/// error from the error queue.
+fn lib_error_string(packed_error: u32) -> String {
+ // SAFETY: This function only reads the given error code and returns a
+ // pointer to a static string.
+ let p = unsafe { ERR_lib_error_string(packed_error) };
+ // SAFETY: Any non-null result is expected to point to a global const C string.
+ unsafe { cstr_to_string(p, "<unknown library>") }
+}
+
+fn reason_error_string(packed_error: u32) -> String {
+ // SAFETY: This function only reads the given error code and returns a
+ // pointer to a static string.
+ let p = unsafe { ERR_reason_error_string(packed_error) };
+ // SAFETY: Any non-null result is expected to point to a global const C string.
+ unsafe { cstr_to_string(p, "<unknown reason>") }
+}
+
+/// Converts a C string pointer to a Rust string.
///
-/// Returns 0 if there are no errors in the queue.
-fn get_packed_error() -> u32 {
- // SAFETY: This function only reads the error queue.
- unsafe { ERR_get_error() }
+/// # Safety
+///
+/// The caller needs to ensure that the pointer is null or points to a valid C string.
+unsafe fn cstr_to_string(p: *const c_char, default: &str) -> String {
+ if p.is_null() {
+ return default.to_string();
+ }
+ // Safety: Safe given the requirements of this function.
+ let s = unsafe { CStr::from_ptr(p) };
+ s.to_str().unwrap_or(default).to_string()
}
fn get_reason(packed_error: u32) -> i32 {
diff --git a/libs/bssl/src/util.rs b/libs/bssl/src/util.rs
index 880c85b..ddb6c6b 100644
--- a/libs/bssl/src/util.rs
+++ b/libs/bssl/src/util.rs
@@ -14,14 +14,14 @@
//! Utility functions.
-use crate::err::get_error_reason_code;
+use crate::err::process_error_queue;
use bssl_avf_error::{ApiName, Error, Result};
use log::error;
pub(crate) fn check_int_result(ret: i32, api_name: ApiName) -> Result<()> {
match ret {
1 => Ok(()),
- 0 => Err(Error::CallFailed(api_name, get_error_reason_code())),
+ 0 => Err(Error::CallFailed(api_name, process_error_queue())),
_ => {
error!(
"Received a return value ({}) other than 0 or 1 from the BoringSSL API: {:?}",
@@ -33,5 +33,5 @@
}
pub(crate) fn to_call_failed_error(api_name: ApiName) -> Error {
- Error::CallFailed(api_name, get_error_reason_code())
+ Error::CallFailed(api_name, process_error_queue())
}