rust: bssl-tls: Cap the input length reported by the abstract socket To prevent the application from sabotaging TLS buffer state, we should cap the returned size of I/O transaction. Signed-off-by: Xiangfei Ding <xfding@google.com> Change-Id: I126cc9f5605febeeffa64c28ca9d56ef6a6a6964 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/93487 Reviewed-by: Adam Langley <agl@google.com> Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/rust/bssl-tls/src/io.rs b/rust/bssl-tls/src/io.rs index 8c29fdb..590b6df 100644 --- a/rust/bssl-tls/src/io.rs +++ b/rust/bssl-tls/src/io.rs
@@ -342,7 +342,7 @@ unsafe extern "C" fn rust_bio_read( bio: *mut bssl_sys::BIO, buffer: *mut c_char, - len: c_int, + buf_len: c_int, ) -> c_int { let rust_bio = unsafe { // Safety: `bio` is still valid and so is the `RustBio` which we have exclusive access to. @@ -351,7 +351,7 @@ if rust_bio.read_eos { return 0; } - let Ok(len) = usize::try_from(len) else { + let Ok(len) = usize::try_from(buf_len) else { return -1; }; let waker = rust_bio.waker.clone(); @@ -378,7 +378,11 @@ match rust_bio.transform_result(res, TlsRetryReason::WantRead) { IoStatus::Ok(bytes) => { if let Ok(bytes) = c_int::try_from(bytes) { - return bytes; + // Here the `bytes` read out from the transport as reported by the application does + // not necessary stay in-bound, it could be application error or active exploit. + // Therefore, we can fully trust that the application behaves well. + // In order to not break `libssl` we can cap the number of writes written. + return bytes.min(buf_len); } -1 } @@ -400,7 +404,7 @@ unsafe extern "C" fn rust_bio_write( bio: *mut bssl_sys::BIO, buffer: *const c_char, - len: c_int, + buf_len: c_int, ) -> c_int { let rust_bio = unsafe { // Safety: `bio` is still valid and so is the `RustBio` which we have exclusive access to. @@ -409,7 +413,7 @@ if rust_bio.write_eos { return 0; } - let Ok(len) = usize::try_from(len) else { + let Ok(len) = usize::try_from(buf_len) else { return -1; }; let waker = rust_bio.waker.clone(); @@ -434,7 +438,10 @@ match rust_bio.transform_result(res, TlsRetryReason::WantWrite) { IoStatus::Ok(bytes) => { if let Ok(bytes) = c_int::try_from(bytes) { - return bytes; + // Here the `bytes` sent out to the transport as reported by the application does + // not necessary stay in-bound, it could be application error or active exploit. + // Therefore, we can fully trust that the application behaves well. + return bytes.min(buf_len); } -1 }