CVE-2021-44421: Observable Discrepancy (CWE-203)
value: The pointer-validation logic in util/mem_util.rs in Occlum before 0.26.0 for Intel SGX acts as a confused deputy that allows a local attacker to access unauthorized information via side-channel analysis.
CWE description: The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not.
CVSS v3 base score: 5.5
Published: 2022-03-10T17:44Z
Repository: https://github.com/occlum/occlum
Language: Rust
Files changed: src/libos/src/util/mem_util.rs
Commit date: 2021-11-29 14:14:54 +0800
Commit message: Check the buffer address before copy the data from the buffer

This commit fixed an Occlum security issue. The researchers from KU
Leuven (Belgium) and the University of Birmingham (UK) found it and
reported it to Occlum team. Thank you, Jo Van Bulck, Frank Piessens,
Fritz Alder, David Oswald, Jesse Spielman and Sam Thomas.

Diff: diff --git a/src/libos/src/util/mem_util.rs b/src/libos/src/util/mem_util.rs
index 519cb4e..7e10a90 100644
--- a/src/libos/src/util/mem_util.rs
+++ b/src/libos/src/util/mem_util.rs
@@ -46,13 +46,16 @@ pub mod from_user {
     pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result<CString> {
         if out_ptr.is_null() {
             return_errno!(EINVAL, "NULL address is invalid");
         }
 
+        // confirm that at least the fisrt byte of the string is from user
+        check_ptr(out_ptr)?;
+
         let cstr = unsafe { CStr::from_ptr(out_ptr) };
         let cstring = CString::from(cstr);
-        if !is_inside_user_space(out_ptr as *const u8, cstring.as_bytes().len()) {
+        if !is_inside_user_space(out_ptr as *const u8, cstring.as_bytes_with_nul().len()) {
             return_errno!(EFAULT, "the whole buffer is not in the user space");
         }
         Ok(cstring)
     }
 
@@ -125,15 +128,18 @@ pub mod from_untrusted {
     pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result<CString> {
         if out_ptr.is_null() {
             return_errno!(EINVAL, "NULL address is invalid");
         }
 
+        // confirm that at least the fisrt byte of the string is out side of enclave
+        check_ptr(out_ptr)?;
+
         let cstr = unsafe { CStr::from_ptr(out_ptr) };
         let cstring = CString::from(cstr);
         if !sgx_trts::trts::rsgx_raw_is_outside_enclave(
             out_ptr as *const u8,
-            cstring.as_bytes().len(),
+            cstring.as_bytes_with_nul().len(),
         ) {
             return_errno!(EFAULT, "the string is not outside enclave");
         }
         Ok(cstring)
     }

Vulnerable code:         if !is_inside_user_space(out_ptr as *const u8, cstring.as_bytes().len()) {
            cstring.as_bytes().len(),
Fixed code:         // confirm that at least the fisrt byte of the string is from user
        check_ptr(out_ptr)?;

        if !is_inside_user_space(out_ptr as *const u8, cstring.as_bytes_with_nul().len()) {
        // confirm that at least the fisrt byte of the string is out side of enclave
        check_ptr(out_ptr)?;

            cstring.as_bytes_with_nul().len(),