mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
Merge branch 'tls-receive-path-fixes-and-clean-ups'
Chuck Lever says: ==================== tls: receive-path fixes and clean-ups I'd like to encourage in-kernel kTLS consumers (NFSD, NVMe/TCP) to coalesce on the use of read_sock. While auditing read_sock for that purpose, Hannes and Sabrina flagged a few rough edges in the receive paths. This series is a set of clean-ups, not a performance series. Async batch decryption and its submit/deliver scaffolding were dropped during previous review: async_capable is always false for TLS 1.3, the version NFSD and NVMe/TCP both require, so async-related improvements were unreachable for the in-kernel consumers this work targets. A subsequent series will introduce infrastructure to support KeyUpdate for in-kernel kTLS consumers, which need to handle TLS Alert messages that trigger a tlshd upcall. ==================== Link: https://patch.msgid.link/20260604-tls-read-sock-v12-0-b114efa6e3e2@oracle.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
67ad35a58a
|
|
@ -111,11 +111,16 @@ struct tls_sw_context_tx {
|
|||
struct tls_strparser {
|
||||
struct sock *sk;
|
||||
|
||||
/* Bitfield word and msg_ready are serialized by the lower
|
||||
* socket lock; BH and worker contexts both acquire it.
|
||||
*/
|
||||
u32 mark : 8;
|
||||
u32 stopped : 1;
|
||||
u32 copy_mode : 1;
|
||||
u32 mixed_decrypted : 1;
|
||||
|
||||
u32 msg_announced : 1;
|
||||
|
||||
bool msg_ready;
|
||||
|
||||
struct strp_msg stm;
|
||||
|
|
|
|||
|
|
@ -193,11 +193,11 @@ void tls_strp_stop(struct tls_strparser *strp);
|
|||
int tls_strp_init(struct tls_strparser *strp, struct sock *sk);
|
||||
void tls_strp_data_ready(struct tls_strparser *strp);
|
||||
|
||||
void tls_strp_check_rcv(struct tls_strparser *strp);
|
||||
void tls_strp_msg_done(struct tls_strparser *strp);
|
||||
void tls_strp_check_rcv(struct tls_strparser *strp, bool announce);
|
||||
void tls_strp_msg_consume(struct tls_strparser *strp);
|
||||
|
||||
int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb);
|
||||
void tls_rx_msg_ready(struct tls_strparser *strp);
|
||||
void tls_rx_msg_maybe_announce(struct tls_strparser *strp);
|
||||
|
||||
bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh);
|
||||
int tls_strp_msg_cow(struct tls_sw_context_rx *ctx);
|
||||
|
|
|
|||
|
|
@ -769,7 +769,7 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
|
|||
} else {
|
||||
struct tls_sw_context_rx *rx_ctx = tls_sw_ctx_rx(ctx);
|
||||
|
||||
tls_strp_check_rcv(&rx_ctx->strp);
|
||||
tls_strp_check_rcv(&rx_ctx->strp, true);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -368,7 +368,6 @@ static int tls_strp_copyin(read_descriptor_t *desc, struct sk_buff *in_skb,
|
|||
desc->count = 0;
|
||||
|
||||
WRITE_ONCE(strp->msg_ready, 1);
|
||||
tls_rx_msg_ready(strp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -492,6 +491,7 @@ bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh)
|
|||
if (!strp->copy_mode && force_refresh) {
|
||||
if (unlikely(tcp_inq(strp->sk) < strp->stm.full_len)) {
|
||||
WRITE_ONCE(strp->msg_ready, 0);
|
||||
strp->msg_announced = 0;
|
||||
memset(&strp->stm, 0, sizeof(strp->stm));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -539,18 +539,24 @@ static int tls_strp_read_sock(struct tls_strparser *strp)
|
|||
return tls_strp_read_copy(strp, false);
|
||||
|
||||
WRITE_ONCE(strp->msg_ready, 1);
|
||||
tls_rx_msg_ready(strp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tls_strp_check_rcv(struct tls_strparser *strp)
|
||||
/* Parse queued data. When @announce is true and parsing produces a
|
||||
* newly-ready record, fire the consumer notification. Callers that
|
||||
* need to notify a waiter about a record parsed by another path
|
||||
* should invoke tls_rx_msg_maybe_announce() directly.
|
||||
*/
|
||||
void tls_strp_check_rcv(struct tls_strparser *strp, bool announce)
|
||||
{
|
||||
if (unlikely(strp->stopped) || strp->msg_ready)
|
||||
return;
|
||||
|
||||
if (tls_strp_read_sock(strp) == -ENOMEM)
|
||||
queue_work(tls_strp_wq, &strp->work);
|
||||
else if (announce && strp->msg_ready)
|
||||
tls_rx_msg_maybe_announce(strp);
|
||||
}
|
||||
|
||||
/* Lower sock lock held */
|
||||
|
|
@ -568,7 +574,7 @@ void tls_strp_data_ready(struct tls_strparser *strp)
|
|||
return;
|
||||
}
|
||||
|
||||
tls_strp_check_rcv(strp);
|
||||
tls_strp_check_rcv(strp, true);
|
||||
}
|
||||
|
||||
static void tls_strp_work(struct work_struct *w)
|
||||
|
|
@ -577,11 +583,16 @@ static void tls_strp_work(struct work_struct *w)
|
|||
container_of(w, struct tls_strparser, work);
|
||||
|
||||
lock_sock(strp->sk);
|
||||
tls_strp_check_rcv(strp);
|
||||
tls_strp_check_rcv(strp, true);
|
||||
release_sock(strp->sk);
|
||||
}
|
||||
|
||||
void tls_strp_msg_done(struct tls_strparser *strp)
|
||||
/* Release the current record without triggering a check for the
|
||||
* next record. Callers must invoke tls_strp_check_rcv() before
|
||||
* releasing the socket lock, or queued data will stall until the
|
||||
* next tls_strp_data_ready() event.
|
||||
*/
|
||||
void tls_strp_msg_consume(struct tls_strparser *strp)
|
||||
{
|
||||
WARN_ON(!strp->stm.full_len);
|
||||
|
||||
|
|
@ -591,9 +602,8 @@ void tls_strp_msg_done(struct tls_strparser *strp)
|
|||
tls_strp_flush_anchor_copy(strp);
|
||||
|
||||
WRITE_ONCE(strp->msg_ready, 0);
|
||||
strp->msg_announced = 0;
|
||||
memset(&strp->stm, 0, sizeof(strp->stm));
|
||||
|
||||
tls_strp_check_rcv(strp);
|
||||
}
|
||||
|
||||
void tls_strp_stop(struct tls_strparser *strp)
|
||||
|
|
|
|||
|
|
@ -1400,12 +1400,27 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (sk_flush_backlog(sk))
|
||||
released = true;
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue)) {
|
||||
tls_strp_check_rcv(&ctx->strp);
|
||||
/* Defer notification to the exit point; this thread
|
||||
* will consume the record directly.
|
||||
*/
|
||||
tls_strp_check_rcv(&ctx->strp, false);
|
||||
if (tls_strp_msg_ready(ctx))
|
||||
break;
|
||||
}
|
||||
|
||||
/* sk_flush_backlog() can run tcp_reset(), which sets
|
||||
* sk_err and then sk_shutdown via tcp_done(). Recheck
|
||||
* sk_err here so a connection abort surfaces as the
|
||||
* actual error rather than a clean EOF.
|
||||
*/
|
||||
if (sk->sk_err) {
|
||||
if (has_copied)
|
||||
return -READ_ONCE(sk->sk_err);
|
||||
return sock_error(sk);
|
||||
}
|
||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||
return 0;
|
||||
|
||||
|
|
@ -1827,6 +1842,9 @@ static int tls_check_pending_rekey(struct sock *sk, struct tls_context *ctx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* On decrypt failure the connection is aborted (sk_err set) before
|
||||
* returning a negative errno.
|
||||
*/
|
||||
static int tls_rx_one_record(struct sock *sk, struct msghdr *msg,
|
||||
struct tls_decrypt_arg *darg)
|
||||
{
|
||||
|
|
@ -1838,8 +1856,10 @@ static int tls_rx_one_record(struct sock *sk, struct msghdr *msg,
|
|||
err = tls_decrypt_device(sk, msg, tls_ctx, darg);
|
||||
if (!err)
|
||||
err = tls_decrypt_sw(sk, tls_ctx, msg, darg);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
tls_err_abort(sk, -EBADMSG);
|
||||
return err;
|
||||
}
|
||||
|
||||
rxm = strp_msg(darg->skb);
|
||||
rxm->offset += prot->prepend_size;
|
||||
|
|
@ -1882,9 +1902,13 @@ static int tls_record_content_type(struct msghdr *msg, struct tls_msg *tlm,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* The deferred announce is fired once on reader exit by
|
||||
* tls_rx_reader_release().
|
||||
*/
|
||||
static void tls_rx_rec_done(struct tls_sw_context_rx *ctx)
|
||||
{
|
||||
tls_strp_msg_done(&ctx->strp);
|
||||
tls_strp_msg_consume(&ctx->strp);
|
||||
tls_strp_check_rcv(&ctx->strp, false);
|
||||
}
|
||||
|
||||
/* This function traverses the rx_list in tls receive context to copies the
|
||||
|
|
@ -2039,6 +2063,12 @@ static int tls_rx_reader_lock(struct sock *sk, struct tls_sw_context_rx *ctx,
|
|||
|
||||
static void tls_rx_reader_release(struct sock *sk, struct tls_sw_context_rx *ctx)
|
||||
{
|
||||
/* Fire any deferred announce once per reader so that a record
|
||||
* parsed but not yet announced becomes visible to the next
|
||||
* reader. The call is idempotent through msg_announced.
|
||||
*/
|
||||
tls_rx_msg_maybe_announce(&ctx->strp);
|
||||
|
||||
if (unlikely(ctx->reader_contended)) {
|
||||
if (wq_has_sleeper(&ctx->wq))
|
||||
wake_up(&ctx->wq);
|
||||
|
|
@ -2150,10 +2180,8 @@ int tls_sw_recvmsg(struct sock *sk,
|
|||
darg.async = false;
|
||||
|
||||
err = tls_rx_one_record(sk, msg, &darg);
|
||||
if (err < 0) {
|
||||
tls_err_abort(sk, -EBADMSG);
|
||||
if (err < 0)
|
||||
goto recv_end;
|
||||
}
|
||||
|
||||
async |= darg.async;
|
||||
|
||||
|
|
@ -2312,10 +2340,8 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
|
|||
memset(&darg.inargs, 0, sizeof(darg.inargs));
|
||||
|
||||
err = tls_rx_one_record(sk, NULL, &darg);
|
||||
if (err < 0) {
|
||||
tls_err_abort(sk, -EBADMSG);
|
||||
if (err < 0)
|
||||
goto splice_read_end;
|
||||
}
|
||||
|
||||
tls_rx_rec_done(ctx);
|
||||
skb = darg.skb;
|
||||
|
|
@ -2383,7 +2409,7 @@ int tls_sw_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|||
goto read_sock_end;
|
||||
|
||||
decrypted = 0;
|
||||
do {
|
||||
while (desc->count) {
|
||||
if (!skb_queue_empty(&ctx->rx_list)) {
|
||||
skb = __skb_dequeue(&ctx->rx_list);
|
||||
rxm = strp_msg(skb);
|
||||
|
|
@ -2398,10 +2424,8 @@ int tls_sw_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|||
memset(&darg.inargs, 0, sizeof(darg.inargs));
|
||||
|
||||
err = tls_rx_one_record(sk, NULL, &darg);
|
||||
if (err < 0) {
|
||||
tls_err_abort(sk, -EBADMSG);
|
||||
if (err < 0)
|
||||
goto read_sock_end;
|
||||
}
|
||||
|
||||
released = tls_read_flush_backlog(sk, prot, INT_MAX,
|
||||
0, decrypted,
|
||||
|
|
@ -2430,14 +2454,11 @@ int tls_sw_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|||
if (used < rxm->full_len) {
|
||||
rxm->offset += used;
|
||||
rxm->full_len -= used;
|
||||
if (!desc->count)
|
||||
goto read_sock_requeue;
|
||||
__skb_queue_head(&ctx->rx_list, skb);
|
||||
} else {
|
||||
consume_skb(skb);
|
||||
if (!desc->count)
|
||||
skb = NULL;
|
||||
}
|
||||
} while (skb);
|
||||
}
|
||||
|
||||
read_sock_end:
|
||||
tls_rx_reader_release(sk, ctx);
|
||||
|
|
@ -2524,10 +2545,18 @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void tls_rx_msg_ready(struct tls_strparser *strp)
|
||||
/* Fire saved_data_ready() at most once per parsed record. The
|
||||
* msg_announced bit is cleared by tls_strp_msg_consume() when the
|
||||
* record is consumed, arming the next announcement.
|
||||
*/
|
||||
void tls_rx_msg_maybe_announce(struct tls_strparser *strp)
|
||||
{
|
||||
struct tls_sw_context_rx *ctx;
|
||||
|
||||
if (!READ_ONCE(strp->msg_ready) || strp->msg_announced)
|
||||
return;
|
||||
strp->msg_announced = 1;
|
||||
|
||||
ctx = container_of(strp, struct tls_sw_context_rx, strp);
|
||||
ctx->saved_data_ready(strp->sk);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user