Merge "[bssl] Improve error processing when BoringSSL API fails" into main
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())
}