diff --git a/include/net/tls.h b/include/net/tls.h index ebd2550280ae..3811943288b3 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -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; diff --git a/net/tls/tls.h b/net/tls/tls.h index 12f44cb649c9..60a37bdaaa25 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -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); diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index fd39acf41a61..c10a3fd7fc17 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -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; diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index c72e88317627..61b10c697ecc 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c @@ -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) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 964ebc268ee4..5a4300c943a1 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -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); }