Skip to content

Commit 95fa145

Browse files
jrfastabborkmann
authored andcommitted
bpf: sockmap/tls, close can race with map free
When a map free is called and in parallel a socket is closed we have two paths that can potentially reset the socket prot ops, the bpf close() path and the map free path. This creates a problem with which prot ops should be used from the socket closed side. If the map_free side completes first then we want to call the original lowest level ops. However, if the tls path runs first we want to call the sockmap ops. Additionally there was no locking around prot updates in TLS code paths so the prot ops could be changed multiple times once from TLS path and again from sockmap side potentially leaving ops pointed at either TLS or sockmap when psock and/or tls context have already been destroyed. To fix this race first only update ops inside callback lock so that TLS, sockmap and lowest level all agree on prot state. Second and a ULP callback update() so that lower layers can inform the upper layer when they are being removed allowing the upper layer to reset prot ops. This gets us close to allowing sockmap and tls to be stacked in arbitrary order but will save that patch for *next trees. v4: - make sure we don't free things for device; - remove the checks which swap the callbacks back only if TLS is at the top. Reported-by: [email protected] Fixes: 02c558b ("bpf: sockmap, support for msg_peek in sk_msg with redirect ingress") Signed-off-by: John Fastabend <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]> Reviewed-by: Dirk van der Merwe <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 0e85873 commit 95fa145

File tree

5 files changed

+53
-8
lines changed

5 files changed

+53
-8
lines changed

include/linux/skmsg.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,13 @@ static inline void sk_psock_restore_proto(struct sock *sk,
354354
sk->sk_write_space = psock->saved_write_space;
355355

356356
if (psock->sk_proto) {
357-
sk->sk_prot = psock->sk_proto;
357+
struct inet_connection_sock *icsk = inet_csk(sk);
358+
bool has_ulp = !!icsk->icsk_ulp_data;
359+
360+
if (has_ulp)
361+
tcp_update_ulp(sk, psock->sk_proto);
362+
else
363+
sk->sk_prot = psock->sk_proto;
358364
psock->sk_proto = NULL;
359365
}
360366
}

include/net/tcp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,6 +2103,8 @@ struct tcp_ulp_ops {
21032103

21042104
/* initialize ulp */
21052105
int (*init)(struct sock *sk);
2106+
/* update ulp */
2107+
void (*update)(struct sock *sk, struct proto *p);
21062108
/* cleanup ulp */
21072109
void (*release)(struct sock *sk);
21082110

@@ -2114,6 +2116,7 @@ void tcp_unregister_ulp(struct tcp_ulp_ops *type);
21142116
int tcp_set_ulp(struct sock *sk, const char *name);
21152117
void tcp_get_available_ulp(char *buf, size_t len);
21162118
void tcp_cleanup_ulp(struct sock *sk);
2119+
void tcp_update_ulp(struct sock *sk, struct proto *p);
21172120

21182121
#define MODULE_ALIAS_TCP_ULP(name) \
21192122
__MODULE_INFO(alias, alias_userspace, name); \

net/core/skmsg.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,12 @@ EXPORT_SYMBOL_GPL(sk_psock_destroy);
585585

586586
void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
587587
{
588-
rcu_assign_sk_user_data(sk, NULL);
589588
sk_psock_cork_free(psock);
590589
sk_psock_zap_ingress(psock);
591-
sk_psock_restore_proto(sk, psock);
592590

593591
write_lock_bh(&sk->sk_callback_lock);
592+
sk_psock_restore_proto(sk, psock);
593+
rcu_assign_sk_user_data(sk, NULL);
594594
if (psock->progs.skb_parser)
595595
sk_psock_stop_strp(sk, psock);
596596
write_unlock_bh(&sk->sk_callback_lock);

net/ipv4/tcp_ulp.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@ void tcp_get_available_ulp(char *buf, size_t maxlen)
9696
rcu_read_unlock();
9797
}
9898

99+
void tcp_update_ulp(struct sock *sk, struct proto *proto)
100+
{
101+
struct inet_connection_sock *icsk = inet_csk(sk);
102+
103+
if (!icsk->icsk_ulp_ops) {
104+
sk->sk_prot = proto;
105+
return;
106+
}
107+
108+
if (icsk->icsk_ulp_ops->update)
109+
icsk->icsk_ulp_ops->update(sk, proto);
110+
}
111+
99112
void tcp_cleanup_ulp(struct sock *sk)
100113
{
101114
struct inet_connection_sock *icsk = inet_csk(sk);

net/tls/tls_main.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,10 @@ static void tls_sk_proto_unhash(struct sock *sk)
328328

329329
ctx = tls_get_ctx(sk);
330330
tls_sk_proto_cleanup(sk, ctx, timeo);
331+
write_lock_bh(&sk->sk_callback_lock);
331332
icsk->icsk_ulp_data = NULL;
333+
sk->sk_prot = ctx->sk_proto;
334+
write_unlock_bh(&sk->sk_callback_lock);
332335

333336
if (ctx->sk_proto->unhash)
334337
ctx->sk_proto->unhash(sk);
@@ -337,7 +340,7 @@ static void tls_sk_proto_unhash(struct sock *sk)
337340

338341
static void tls_sk_proto_close(struct sock *sk, long timeout)
339342
{
340-
void (*sk_proto_close)(struct sock *sk, long timeout);
343+
struct inet_connection_sock *icsk = inet_csk(sk);
341344
struct tls_context *ctx = tls_get_ctx(sk);
342345
long timeo = sock_sndtimeo(sk, 0);
343346
bool free_ctx;
@@ -347,20 +350,23 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
347350

348351
lock_sock(sk);
349352
free_ctx = ctx->tx_conf != TLS_HW && ctx->rx_conf != TLS_HW;
350-
sk_proto_close = ctx->sk_proto_close;
351353

352354
if (ctx->tx_conf != TLS_BASE || ctx->rx_conf != TLS_BASE)
353355
tls_sk_proto_cleanup(sk, ctx, timeo);
354356

357+
write_lock_bh(&sk->sk_callback_lock);
358+
if (free_ctx)
359+
icsk->icsk_ulp_data = NULL;
355360
sk->sk_prot = ctx->sk_proto;
361+
write_unlock_bh(&sk->sk_callback_lock);
356362
release_sock(sk);
357363
if (ctx->tx_conf == TLS_SW)
358364
tls_sw_free_ctx_tx(ctx);
359365
if (ctx->rx_conf == TLS_SW || ctx->rx_conf == TLS_HW)
360366
tls_sw_strparser_done(ctx);
361367
if (ctx->rx_conf == TLS_SW)
362368
tls_sw_free_ctx_rx(ctx);
363-
sk_proto_close(sk, timeout);
369+
ctx->sk_proto_close(sk, timeout);
364370

365371
if (free_ctx)
366372
tls_ctx_free(ctx);
@@ -827,7 +833,7 @@ static int tls_init(struct sock *sk)
827833
int rc = 0;
828834

829835
if (tls_hw_prot(sk))
830-
goto out;
836+
return 0;
831837

832838
/* The TLS ulp is currently supported only for TCP sockets
833839
* in ESTABLISHED state.
@@ -838,22 +844,38 @@ static int tls_init(struct sock *sk)
838844
if (sk->sk_state != TCP_ESTABLISHED)
839845
return -ENOTSUPP;
840846

847+
tls_build_proto(sk);
848+
841849
/* allocate tls context */
850+
write_lock_bh(&sk->sk_callback_lock);
842851
ctx = create_ctx(sk);
843852
if (!ctx) {
844853
rc = -ENOMEM;
845854
goto out;
846855
}
847856

848-
tls_build_proto(sk);
849857
ctx->tx_conf = TLS_BASE;
850858
ctx->rx_conf = TLS_BASE;
851859
ctx->sk_proto = sk->sk_prot;
852860
update_sk_prot(sk, ctx);
853861
out:
862+
write_unlock_bh(&sk->sk_callback_lock);
854863
return rc;
855864
}
856865

866+
static void tls_update(struct sock *sk, struct proto *p)
867+
{
868+
struct tls_context *ctx;
869+
870+
ctx = tls_get_ctx(sk);
871+
if (likely(ctx)) {
872+
ctx->sk_proto_close = p->close;
873+
ctx->sk_proto = p;
874+
} else {
875+
sk->sk_prot = p;
876+
}
877+
}
878+
857879
void tls_register_device(struct tls_device *device)
858880
{
859881
spin_lock_bh(&device_spinlock);
@@ -874,6 +896,7 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
874896
.name = "tls",
875897
.owner = THIS_MODULE,
876898
.init = tls_init,
899+
.update = tls_update,
877900
};
878901

879902
static int __init tls_register(void)

0 commit comments

Comments
 (0)