mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
so_splice: Disallow splicing with KTLS-enabled sockets
Suppose the sink socket in a splice has KTLS enabled. When data is transmitted from the source socket, sosend_generic_locked() receives an mbuf rather than a UIO as it would if userspace were transferring data. In this case, ktls_frame() expects the mbuf to be unmapped, but in general this won't be the case. Simply disallow the combination for now. Modify so_unsplice() to handle dismantling a partially initialized splice, in order to simplify error handling in so_splice(). Make sure that one can't enable KTLS on a spliced socket, or more specifically, that one can't enable RXTLS on the source side of a splice, or TXTLS on the sink side of a splice. Reported by: [email protected] Reviewed by: gallatin MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D49920
This commit is contained in:
1 parent
a1a067b713
commit
1000cc4a0d
2 files changed
+37
-19
No files matched your search
+11
-3
@@ -1332,7 +1332,11 @@ ktls_enable_rx(struct socket *so, struct tls_enable *en)
|
||||
|
||||
/* Mark the socket as using TLS offload. */
|
||||
SOCK_RECVBUF_LOCK(so);
|
||||
if (__predict_false(so->so_rcv.sb_tls_info != NULL)) {
|
||||
if (__predict_false(so->so_rcv.sb_tls_info != NULL))
|
||||
error = EALREADY;
|
||||
else if ((so->so_rcv.sb_flags & SB_SPLICED) != 0)
|
||||
error = EINVAL;
|
||||
if (error != 0) {
|
||||
SOCK_RECVBUF_UNLOCK(so);
|
||||
SOCK_IO_RECV_UNLOCK(so);
|
||||
ktls_free(tls);
|
||||
@@ -1432,12 +1436,16 @@ ktls_enable_tx(struct socket *so, struct tls_enable *en)
|
||||
inp = so->so_pcb;
|
||||
INP_WLOCK(inp);
|
||||
SOCK_SENDBUF_LOCK(so);
|
||||
if (__predict_false(so->so_snd.sb_tls_info != NULL)) {
|
||||
if (__predict_false(so->so_snd.sb_tls_info != NULL))
|
||||
error = EALREADY;
|
||||
else if ((so->so_snd.sb_flags & SB_SPLICED) != 0)
|
||||
error = EINVAL;
|
||||
if (error != 0) {
|
||||
SOCK_SENDBUF_UNLOCK(so);
|
||||
INP_WUNLOCK(inp);
|
||||
SOCK_IO_SEND_UNLOCK(so);
|
||||
ktls_free(tls);
|
||||
return (EALREADY);
|
||||
return (error);
|
||||
}
|
||||
so->so_snd.sb_tls_seqno = be64dec(en->rec_seq);
|
||||
so->so_snd.sb_tls_info = tls;
|
||||
|
||||
+26
-16
@@ -1699,10 +1699,16 @@ so_splice(struct socket *so, struct socket *so2, struct splice *splice)
|
||||
uma_zfree(splice_zone, sp);
|
||||
return (error);
|
||||
}
|
||||
soref(so);
|
||||
so->so_splice = sp;
|
||||
SOCK_RECVBUF_LOCK(so);
|
||||
if (so->so_rcv.sb_tls_info != NULL) {
|
||||
SOCK_RECVBUF_UNLOCK(so);
|
||||
SOCK_UNLOCK(so);
|
||||
uma_zfree(splice_zone, sp);
|
||||
return (EINVAL);
|
||||
}
|
||||
so->so_rcv.sb_flags |= SB_SPLICED;
|
||||
so->so_splice = sp;
|
||||
soref(so);
|
||||
SOCK_RECVBUF_UNLOCK(so);
|
||||
SOCK_UNLOCK(so);
|
||||
|
||||
@@ -1716,20 +1722,19 @@ so_splice(struct socket *so, struct socket *so2, struct splice *splice)
|
||||
error = EBUSY;
|
||||
if (error != 0) {
|
||||
SOCK_UNLOCK(so2);
|
||||
SOCK_LOCK(so);
|
||||
so->so_splice = NULL;
|
||||
SOCK_RECVBUF_LOCK(so);
|
||||
so->so_rcv.sb_flags &= ~SB_SPLICED;
|
||||
SOCK_RECVBUF_UNLOCK(so);
|
||||
SOCK_UNLOCK(so);
|
||||
sorele(so);
|
||||
uma_zfree(splice_zone, sp);
|
||||
so_unsplice(so, false);
|
||||
return (error);
|
||||
}
|
||||
soref(so2);
|
||||
so2->so_splice_back = sp;
|
||||
SOCK_SENDBUF_LOCK(so2);
|
||||
if (so->so_snd.sb_tls_info != NULL) {
|
||||
SOCK_SENDBUF_UNLOCK(so2);
|
||||
SOCK_UNLOCK(so2);
|
||||
so_unsplice(so, false);
|
||||
return (EINVAL);
|
||||
}
|
||||
so2->so_snd.sb_flags |= SB_SPLICED;
|
||||
so2->so_splice_back = sp;
|
||||
soref(so2);
|
||||
mtx_lock(&sp->mtx);
|
||||
SOCK_SENDBUF_UNLOCK(so2);
|
||||
SOCK_UNLOCK(so2);
|
||||
@@ -1754,7 +1759,7 @@ so_unsplice(struct socket *so, bool timeout)
|
||||
{
|
||||
struct socket *so2;
|
||||
struct so_splice *sp;
|
||||
bool drain;
|
||||
bool drain, so2rele;
|
||||
|
||||
/*
|
||||
* First unset SB_SPLICED and hide the splice structure so that
|
||||
@@ -1793,11 +1798,14 @@ so_unsplice(struct socket *so, bool timeout)
|
||||
SOCK_LOCK(so2);
|
||||
KASSERT(!SOLISTENING(so2), ("%s: so2 is listening", __func__));
|
||||
SOCK_SENDBUF_LOCK(so2);
|
||||
KASSERT((so2->so_snd.sb_flags & SB_SPLICED) != 0,
|
||||
KASSERT(sp->state == SPLICE_INIT ||
|
||||
(so2->so_snd.sb_flags & SB_SPLICED) != 0,
|
||||
("%s: so2 is not spliced", __func__));
|
||||
KASSERT(so2->so_splice_back == sp,
|
||||
KASSERT(sp->state == SPLICE_INIT ||
|
||||
so2->so_splice_back == sp,
|
||||
("%s: so_splice_back != sp", __func__));
|
||||
so2->so_snd.sb_flags &= ~SB_SPLICED;
|
||||
so2rele = so2->so_splice_back != NULL;
|
||||
so2->so_splice_back = NULL;
|
||||
SOCK_SENDBUF_UNLOCK(so2);
|
||||
SOCK_UNLOCK(so2);
|
||||
@@ -1815,6 +1823,7 @@ so_unsplice(struct socket *so, bool timeout)
|
||||
while (sp->state == SPLICE_CLOSING)
|
||||
msleep(sp, &sp->mtx, PSOCK, "unsplice", 0);
|
||||
break;
|
||||
case SPLICE_INIT:
|
||||
case SPLICE_IDLE:
|
||||
case SPLICE_EXCEPTION:
|
||||
sp->state = SPLICE_CLOSED;
|
||||
@@ -1840,7 +1849,8 @@ so_unsplice(struct socket *so, bool timeout)
|
||||
CURVNET_SET(so->so_vnet);
|
||||
sorele(so);
|
||||
sowwakeup(so2);
|
||||
sorele(so2);
|
||||
if (so2rele)
|
||||
sorele(so2);
|
||||
CURVNET_RESTORE();
|
||||
so_splice_free(sp);
|
||||
return (0);
|
||||
|
||||
Reference in new issue
Block a user