Skip to content

Commit e91de6a

Browse files
jrfastabAlexei Starovoitov
authored andcommitted
bpf: Fix running sk_skb program types with ktls
KTLS uses a stream parser to collect TLS messages and send them to the upper layer tls receive handler. This ensures the tls receiver has a full TLS header to parse when it is run. However, when a socket has BPF_SK_SKB_STREAM_VERDICT program attached before KTLS is enabled we end up with two stream parsers running on the same socket. The result is both try to run on the same socket. First the KTLS stream parser runs and calls read_sock() which will tcp_read_sock which in turn calls tcp_rcv_skb(). This dequeues the skb from the sk_receive_queue. When this is done KTLS code then data_ready() callback which because we stacked KTLS on top of the bpf stream verdict program has been replaced with sk_psock_start_strp(). This will in turn kick the stream parser again and eventually do the same thing KTLS did above calling into tcp_rcv_skb() and dequeuing a skb from the sk_receive_queue. At this point the data stream is broke. Part of the stream was handled by the KTLS side some other bytes may have been handled by the BPF side. Generally this results in either missing data or more likely a "Bad Message" complaint from the kTLS receive handler as the BPF program steals some bytes meant to be in a TLS header and/or the TLS header length is no longer correct. We've already broke the idealized model where we can stack ULPs in any order with generic callbacks on the TX side to handle this. So in this patch we do the same thing but for RX side. We add a sk_psock_strp_enabled() helper so TLS can learn a BPF verdict program is running and add a tls_sw_has_ctx_rx() helper so BPF side can learn there is a TLS ULP on the socket. Then on BPF side we omit calling our stream parser to avoid breaking the data stream for the KTLS receiver. Then on the KTLS side we call BPF_SK_SKB_STREAM_VERDICT once the KTLS receiver is done with the packet but before it posts the msg to userspace. This gives us symmetry between the TX and RX halfs and IMO makes it usable again. On the TX side we process packets in this order BPF -> TLS -> TCP and on the receive side in the reverse order TCP -> TLS -> BPF. Discovered while testing OpenSSL 3.0 Alpha2.0 release. Fixes: d829e9c ("tls: convert to generic sk_msg interface") Signed-off-by: John Fastabend <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/159079361946.5745.605854335665044485.stgit@john-Precision-5820-Tower Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent ca2f5f2 commit e91de6a

File tree

4 files changed

+75
-5
lines changed

4 files changed

+75
-5
lines changed

include/linux/skmsg.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,4 +437,12 @@ static inline void psock_progs_drop(struct sk_psock_progs *progs)
437437
psock_set_prog(&progs->skb_verdict, NULL);
438438
}
439439

440+
int sk_psock_tls_strp_read(struct sk_psock *psock, struct sk_buff *skb);
441+
442+
static inline bool sk_psock_strp_enabled(struct sk_psock *psock)
443+
{
444+
if (!psock)
445+
return false;
446+
return psock->parser.enabled;
447+
}
440448
#endif /* _LINUX_SKMSG_H */

include/net/tls.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,15 @@ static inline bool tls_sw_has_ctx_tx(const struct sock *sk)
571571
return !!tls_sw_ctx_tx(ctx);
572572
}
573573

574+
static inline bool tls_sw_has_ctx_rx(const struct sock *sk)
575+
{
576+
struct tls_context *ctx = tls_get_ctx(sk);
577+
578+
if (!ctx)
579+
return false;
580+
return !!tls_sw_ctx_rx(ctx);
581+
}
582+
574583
void tls_sw_write_space(struct sock *sk, struct tls_context *ctx);
575584
void tls_device_write_space(struct sock *sk, struct tls_context *ctx);
576585

net/core/skmsg.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <net/sock.h>
99
#include <net/tcp.h>
10+
#include <net/tls.h>
1011

1112
static bool sk_msg_try_coalesce_ok(struct sk_msg *msg, int elem_first_coalesce)
1213
{
@@ -714,6 +715,38 @@ static void sk_psock_skb_redirect(struct sk_psock *psock, struct sk_buff *skb)
714715
}
715716
}
716717

718+
static void sk_psock_tls_verdict_apply(struct sk_psock *psock,
719+
struct sk_buff *skb, int verdict)
720+
{
721+
switch (verdict) {
722+
case __SK_REDIRECT:
723+
sk_psock_skb_redirect(psock, skb);
724+
break;
725+
case __SK_PASS:
726+
case __SK_DROP:
727+
default:
728+
break;
729+
}
730+
}
731+
732+
int sk_psock_tls_strp_read(struct sk_psock *psock, struct sk_buff *skb)
733+
{
734+
struct bpf_prog *prog;
735+
int ret = __SK_PASS;
736+
737+
rcu_read_lock();
738+
prog = READ_ONCE(psock->progs.skb_verdict);
739+
if (likely(prog)) {
740+
tcp_skb_bpf_redirect_clear(skb);
741+
ret = sk_psock_bpf_run(psock, prog, skb);
742+
ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb));
743+
}
744+
rcu_read_unlock();
745+
sk_psock_tls_verdict_apply(psock, skb, ret);
746+
return ret;
747+
}
748+
EXPORT_SYMBOL_GPL(sk_psock_tls_strp_read);
749+
717750
static void sk_psock_verdict_apply(struct sk_psock *psock,
718751
struct sk_buff *skb, int verdict)
719752
{
@@ -792,9 +825,13 @@ static void sk_psock_strp_data_ready(struct sock *sk)
792825
rcu_read_lock();
793826
psock = sk_psock(sk);
794827
if (likely(psock)) {
795-
write_lock_bh(&sk->sk_callback_lock);
796-
strp_data_ready(&psock->parser.strp);
797-
write_unlock_bh(&sk->sk_callback_lock);
828+
if (tls_sw_has_ctx_rx(sk)) {
829+
psock->parser.saved_data_ready(sk);
830+
} else {
831+
write_lock_bh(&sk->sk_callback_lock);
832+
strp_data_ready(&psock->parser.strp);
833+
write_unlock_bh(&sk->sk_callback_lock);
834+
}
798835
}
799836
rcu_read_unlock();
800837
}

net/tls/tls_sw.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,7 @@ int tls_sw_recvmsg(struct sock *sk,
17421742
long timeo;
17431743
bool is_kvec = iov_iter_is_kvec(&msg->msg_iter);
17441744
bool is_peek = flags & MSG_PEEK;
1745+
bool bpf_strp_enabled;
17451746
int num_async = 0;
17461747
int pending;
17471748

@@ -1752,6 +1753,7 @@ int tls_sw_recvmsg(struct sock *sk,
17521753

17531754
psock = sk_psock_get(sk);
17541755
lock_sock(sk);
1756+
bpf_strp_enabled = sk_psock_strp_enabled(psock);
17551757

17561758
/* Process pending decrypted records. It must be non-zero-copy */
17571759
err = process_rx_list(ctx, msg, &control, &cmsg, 0, len, false,
@@ -1805,11 +1807,12 @@ int tls_sw_recvmsg(struct sock *sk,
18051807

18061808
if (to_decrypt <= len && !is_kvec && !is_peek &&
18071809
ctx->control == TLS_RECORD_TYPE_DATA &&
1808-
prot->version != TLS_1_3_VERSION)
1810+
prot->version != TLS_1_3_VERSION &&
1811+
!bpf_strp_enabled)
18091812
zc = true;
18101813

18111814
/* Do not use async mode if record is non-data */
1812-
if (ctx->control == TLS_RECORD_TYPE_DATA)
1815+
if (ctx->control == TLS_RECORD_TYPE_DATA && !bpf_strp_enabled)
18131816
async_capable = ctx->async_capable;
18141817
else
18151818
async_capable = false;
@@ -1859,6 +1862,19 @@ int tls_sw_recvmsg(struct sock *sk,
18591862
goto pick_next_record;
18601863

18611864
if (!zc) {
1865+
if (bpf_strp_enabled) {
1866+
err = sk_psock_tls_strp_read(psock, skb);
1867+
if (err != __SK_PASS) {
1868+
rxm->offset = rxm->offset + rxm->full_len;
1869+
rxm->full_len = 0;
1870+
if (err == __SK_DROP)
1871+
consume_skb(skb);
1872+
ctx->recv_pkt = NULL;
1873+
__strp_unpause(&ctx->strp);
1874+
continue;
1875+
}
1876+
}
1877+
18621878
if (rxm->full_len > len) {
18631879
retain_skb = true;
18641880
chunk = len;

0 commit comments

Comments
 (0)