Array::CopyFrom and InPlaceVector::TryCopyFrom: do not allow in to alias this. Also, fix one "theoretical" use-after-free in tls13_enc that happens in the tls13_rotate_traffic_key -> tls13_set_traffic_key call chain by resetting the secret to the same secret we already have. This reads the secret after having called std::destroy_n() on it. This is not detected by asan and msan, as the std::destroy_n() call compiles to nothing when the declared type is a built-in integer type like here (uint8_t). At the same time this means that it also is harmless - at least for now, as long as all types this happens with are POD and as long as std::destroy_n() will keep doing nothing on them. Issue found by asking #Gemini to analyze the code. Change-Id: I65ef3b45a6fd3b394f85c79a658dfc2e6a6a6964 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/90987 Commit-Queue: Xiangfei Ding <xfding@google.com> Reviewed-by: Xiangfei Ding <xfding@google.com>
diff --git a/crypto/internal.h b/crypto/internal.h index b8b45f3..f7cc137 100644 --- a/crypto/internal.h +++ b/crypto/internal.h
@@ -186,6 +186,13 @@ return a_u + a_bytes > b_u && b_u + b_bytes > a_u; } +// spans_alias returns one if |a| and |b| alias, and zero otherwise. +template <typename T> +inline int spans_alias(Span<const T> a, Span<const T> b) { + return buffers_alias(a.data(), a.size() * sizeof(T), b.data(), + b.size() * sizeof(T)); +} + // align_pointer returns |ptr|, advanced to |alignment|. |alignment| must be a // power of two, and |ptr| must have at least |alignment - 1| bytes of scratch // space.
diff --git a/crypto/mem_internal.h b/crypto/mem_internal.h index bb815d7..536dddf 100644 --- a/crypto/mem_internal.h +++ b/crypto/mem_internal.h
@@ -265,7 +265,10 @@ // CopyFrom replaces the array with a newly-allocated copy of |in|. It returns // true on success and false on error. + // + // |in| may not alias |this|. [[nodiscard]] bool CopyFrom(Span<const T> in) { + BSSL_CHECK(!spans_alias(MakeConstSpan(*this), in)); if (!InitUninitialized(in.size())) { return false; } @@ -585,7 +588,10 @@ // TryCopyFrom sets the vector to a copy of |in| and returns true, or returns // false if |in| is too large. + // + // |in| may not alias |this|. [[nodiscard]] bool TryCopyFrom(Span<const T> in) { + BSSL_CHECK(!spans_alias(MakeConstSpan(*this), in)); if (in.size() > capacity()) { return false; }
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc index 9d28be5..e096503 100644 --- a/ssl/tls13_enc.cc +++ b/ssl/tls13_enc.cc
@@ -399,17 +399,17 @@ static const char kTLS13LabelApplicationTraffic[] = "traffic upd"; bool tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) { - Span<uint8_t> secret = direction == evp_aead_open - ? Span(ssl->s3->read_traffic_secret) - : Span(ssl->s3->write_traffic_secret); + InplaceVector<uint8_t, SSL_MAX_MD_SIZE> secret( + direction == evp_aead_open ? ssl->s3->read_traffic_secret + : ssl->s3->write_traffic_secret); const SSL_SESSION *session = SSL_get_session(ssl); const EVP_MD *digest = ssl_session_get_digest(session); - return hkdf_expand_label(secret, digest, secret, + return hkdf_expand_label(Span(secret), digest, secret, kTLS13LabelApplicationTraffic, {}, SSL_is_dtls(ssl)) && tls13_set_traffic_key(ssl, ssl_encryption_application, direction, - session, secret); + session, Span(secret)); } static const char kTLS13LabelResumption[] = "res master";