From nobody Tue Jun 30 17:21:06 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gqVKv1Bz6z6jY7r for ; Tue, 30 Jun 2026 17:21:07 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gqVKt3BYtz3rWf for ; Tue, 30 Jun 2026 17:21:06 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1782840066; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sfPbh/R8HDZQN+sFXqpQTqrahCGY++7wI3k+P0YSSos=; b=W5o+Sd7IkZhjTmqn+ycEPU9eWCXSZwS1WDSXPtMCHMrqw7Ajm8ynSysZ7MvfxbZW3sklqm 98JtbfZiPXwcrZPDNC+QOZUq9eOu2a5wrR/+WaSFZhjfJ4PVuW0J84thH7SclbPc8x/VkV lwr9f+BRht4ufP1fCTSLbttng/YY7pWOu8i1mEX7zWgUbSoYO1ol75BFuk7vnSAZVw3nUd Iqweu5zeLu3SpnQ34VSJIIoXJeLeh3TG3aFSSGN05Coo0TTvsFoXOH2oz6YR+V5/QWqa0n Y3BTn0d4j6Dore+PpXA+g8MvcgMtX1XBwvGQNaSyzJ0Fo6/6f3n8cCW79sYZcA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1782840066; a=rsa-sha256; cv=none; b=UtZPdjmhXwnHlYbetIQlci9uNfrRsphFUbsmalNqEQuF0wChxHCTDNXrq6xbvpuKH6VA+B RkneKgPwEQCOOOZKJ4BjTt+LLjmZ6reKFW81Q5T43AzsaJ9nN3SQRhOJxFhh1BZzYo4Otl xBGKZfwxo6pk2tQBk4lXXgFS6d6OPldMhESTK5NUQxie46BH82qClxPcYceXN7n6n1x6RV /rCcJ/Umd5ESNlbVKQoTst/IxQdywj0rGdSL6MVmWRbrRU6hBtcqgGiLY123fRiDa9zjTy /STC8lLpICbOT1BF5KVZNECj4Yc3WZy4Xs0j5jR6LILWbf5wrY2VreioX91shA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1782840066; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sfPbh/R8HDZQN+sFXqpQTqrahCGY++7wI3k+P0YSSos=; b=qY2hPaZdjk/ryTrmo/ISF/IHUIoJDIVYGVxqeYJ+t/zMBLqx106QhDKr/rICPfwuYSArkj i/pcMfjxv4Bk1YZOH8ziVnV6dX2fVPCm0HWjlLoQxi0f7mn+u/ntwNVp4yoj3YjJAVss3C 4z8tgvm4hfER2v23napQM6lq5lX1btVBdj4kYSW+sgh4Qdgf2gj+Y7yzhdtOgWbCEV0V9g 0yTMmCCm6QYzxSUUbb2QcKqPzdwDpATfxAoGf5E2Af6dXc+UC6wDrANrAwE/OrtzsD/jQV 70tHrY4S1sIH2eS9A33g+usjYteK0VhDGEfofZXVre+k06Qt1V1VN7rZYqH1zg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gqVKt27MdztBb for ; Tue, 30 Jun 2026 17:21:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 45873 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 30 Jun 2026 17:21:06 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Cc: John Baldwin From: Mark Johnston Subject: git: 5f83a1c159a3 - releng/14.4 - ktls CBC decrypt: Only increment iovec index when an entry is used List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/releng/14.4 X-Git-Reftype: branch X-Git-Commit: 5f83a1c159a3149d65bbc0f004c7dd6c1ffb698c Auto-Submitted: auto-generated Date: Tue, 30 Jun 2026 17:21:06 +0000 Message-Id: <6a43fb02.45873.3dd5a364@gitrepo.freebsd.org> The branch releng/14.4 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=5f83a1c159a3149d65bbc0f004c7dd6c1ffb698c commit 5f83a1c159a3149d65bbc0f004c7dd6c1ffb698c Author: John Baldwin AuthorDate: 2026-06-24 01:14:11 +0000 Commit: Mark Johnston CommitDate: 2026-06-29 19:17:30 +0000 ktls CBC decrypt: Only increment iovec index when an entry is used If an mbuf in the chain was skipped because it only contained bytes from the header, the iovec index ('i') was incremented even though the entry was not populated. Only increment 'i' when an iovec entry is consumed. Add a new type of KTLS receive test which writes a single TLS record via two separate write(2) calls over a TCP_NODELAY socket to trigger a split in the mbuf chain in the kernel. Test various split locations including after the "plain" TLS header (5 bytes), after the full TLS header, in the middle of the data payload, just before the start of the trailer, and in the middle of the trailer. These tests are also run against all supported ciphers, not just CBC. The 'header' test for CBC ciphersuites was able to trigger the bug. Approved by: so Security: FreeBSD-SA-26:46.ktls Security: CVE-2026-49423 Sponsored by: Chelsio Communications --- sys/opencrypto/ktls_ocf.c | 3 +- tests/sys/kern/ktls_test.c | 110 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 3 deletions(-) diff --git a/sys/opencrypto/ktls_ocf.c b/sys/opencrypto/ktls_ocf.c index f61fb7f73b5d..3c8b2e4f4589 100644 --- a/sys/opencrypto/ktls_ocf.c +++ b/sys/opencrypto/ktls_ocf.c @@ -503,13 +503,14 @@ ktls_ocf_tls_cbc_decrypt(struct ktls_session *tls, iov[0].iov_base = &ad; iov[0].iov_len = sizeof(ad); skip = sizeof(*hdr) + AES_BLOCK_LEN; - for (i = 1, n = m; n != NULL; i++, n = n->m_next) { + for (i = 1, n = m; n != NULL; n = n->m_next) { if (n->m_len < skip) { skip -= n->m_len; continue; } iov[i].iov_base = mtod(n, char *) + skip; iov[i].iov_len = n->m_len - skip; + i++; skip = 0; } uio.uio_iov = iov; diff --git a/tests/sys/kern/ktls_test.c b/tests/sys/kern/ktls_test.c index 3970083e7f72..7003b86fb4e2 100644 --- a/tests/sys/kern/ktls_test.c +++ b/tests/sys/kern/ktls_test.c @@ -303,6 +303,15 @@ fd_set_blocking(int fd) ATF_REQUIRE(fcntl(fd, F_SETFL, flags) != -1); } +static void +tcp_nodelay(int fd) +{ + int nodelay = 1; + + ATF_REQUIRE(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, + sizeof(nodelay)) == 0); +} + static bool cbc_crypt(const EVP_CIPHER *cipher, const char *key, const char *iv, const char *input, char *output, size_t size, int enc) @@ -1920,6 +1929,55 @@ test_ktls_receive_bad_size(const atf_tc_t *tc, struct tls_enable *en, close_sockets_ignore_errors(sockets); } +static void +test_ktls_receive_split_record(const atf_tc_t *tc, struct tls_enable *en, + uint64_t seqno, size_t len, size_t first_len) +{ + char *plaintext, *received, *outbuf; + size_t outbuf_cap, outbuf_len; + ssize_t rv; + int sockets[2]; + + ATF_REQUIRE(len <= TLS_MAX_MSG_SIZE_V10_2); + + plaintext = alloc_buffer(len); + received = malloc(len); + outbuf_cap = tls_header_len(en) + len + tls_trailer_len(en); + outbuf = malloc(outbuf_cap); + + ATF_REQUIRE_MSG(open_sockets(tc, sockets), "failed to create sockets"); + + ATF_REQUIRE(setsockopt(sockets[0], IPPROTO_TCP, TCP_RXTLS_ENABLE, en, + sizeof(*en)) == 0); + check_tls_mode(tc, sockets[0], TCP_RXTLS_MODE); + + fd_set_blocking(sockets[0]); + fd_set_blocking(sockets[1]); + + outbuf_len = encrypt_tls_record(tc, en, TLS_RLTYPE_APP, seqno, + plaintext, len, outbuf, outbuf_cap, 0); + ATF_REQUIRE(first_len < outbuf_len); + + tcp_nodelay(sockets[1]); + rv = write(sockets[1], outbuf, first_len); + ATF_REQUIRE_INTEQ((ssize_t)(first_len), rv); + + rv = write(sockets[1], outbuf + first_len, outbuf_len - first_len); + ATF_REQUIRE_INTEQ((ssize_t)(outbuf_len - first_len), rv); + + rv = ktls_receive_tls_record(en, sockets[0], TLS_RLTYPE_APP, received, + len); + ATF_REQUIRE_INTEQ((ssize_t)len, rv); + + ATF_REQUIRE(memcmp(plaintext, received, len) == 0); + + free(outbuf); + free(received); + free(plaintext); + + close_sockets(sockets); +} + #define TLS_10_TESTS(M) \ M(aes128_cbc_1_0_sha1, CRYPTO_AES_CBC, 128 / 8, \ CRYPTO_SHA1_HMAC, TLS_MINOR_VER_ZERO) \ @@ -2360,6 +2418,26 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_##name, tc) \ auth_alg, minor, name) \ ATF_TP_ADD_TC(tp, ktls_receive_##cipher_name##_##name); +#define GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, name, len, first_len) \ +ATF_TC_WITHOUT_HEAD(ktls_receive_##cipher_name##_split_##name); \ +ATF_TC_BODY(ktls_receive_##cipher_name##_split_##name, tc) \ +{ \ + struct tls_enable en; \ + uint64_t seqno; \ + \ + ATF_REQUIRE_KTLS(); \ + seqno = random(); \ + build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor, \ + seqno, &en); \ + test_ktls_receive_split_record(tc, &en, seqno, len, first_len); \ + free_tls_enable(&en); \ +} + +#define ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, name) \ + ATF_TP_ADD_TC(tp, ktls_receive_##cipher_name##_split_##name); + #define GEN_RECEIVE_TESTS(cipher_name, cipher_alg, key_size, auth_alg, \ minor) \ GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size, \ @@ -2381,7 +2459,22 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_##name, tc) \ tls_minimum_record_payload(&en) - 1) \ GEN_RECEIVE_BAD_SIZE_TEST(cipher_name, cipher_alg, key_size, \ auth_alg, minor, oversized_record, \ - TLS_MAX_MSG_SIZE_V10_2 * 2) + TLS_MAX_MSG_SIZE_V10_2 * 2) \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, header, 64, \ + sizeof(struct tls_record_layer)); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, full_header, 64, \ + tls_header_len(&en)); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, half, 64, \ + tls_header_len(&en) + 32); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_start, 64, \ + tls_header_len(&en) + 64); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_middle, 64, \ + tls_header_len(&en) + 64 + tls_trailer_len(&en) / 2); #define ADD_RECEIVE_TESTS(cipher_name, cipher_alg, key_size, auth_alg, \ minor) \ @@ -2402,7 +2495,17 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_##name, tc) \ ADD_RECEIVE_BAD_SIZE_TEST(cipher_name, cipher_alg, key_size, \ auth_alg, minor, small_record) \ ADD_RECEIVE_BAD_SIZE_TEST(cipher_name, cipher_alg, key_size, \ - auth_alg, minor, oversized_record) + auth_alg, minor, oversized_record) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, header) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, full_header) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, half) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_start) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_middle) \ /* * For each supported cipher suite, run several receive tests: @@ -2425,6 +2528,9 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_##name, tc) \ * size * * - a test with an oversized TLS record + * + * - tests of a single record whose data is split across two writes, + * with each test using a different split point */ AES_CBC_NONZERO_TESTS(GEN_RECEIVE_TESTS); AES_GCM_TESTS(GEN_RECEIVE_TESTS);