Commit 313ab004 authored by John Fastabend's avatar John Fastabend Committed by Daniel Borkmann

net/tls: remove sock unlock/lock around strp_done()

The tls close() callback currently drops the sock lock to call
strp_done(). Split up the RX cleanup into stopping the strparser
and releasing most resources, syncing strparser and finally
freeing the context.

To avoid the need for a strp_done() call on the cleanup path
of device offload make sure we don't arm the strparser until
we are sure init will be successful.
Signed-off-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarDirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent f87e62d4
...@@ -107,9 +107,7 @@ struct tls_device { ...@@ -107,9 +107,7 @@ struct tls_device {
enum { enum {
TLS_BASE, TLS_BASE,
TLS_SW, TLS_SW,
#ifdef CONFIG_TLS_DEVICE
TLS_HW, TLS_HW,
#endif
TLS_HW_RECORD, TLS_HW_RECORD,
TLS_NUM_CONFIG, TLS_NUM_CONFIG,
}; };
...@@ -357,14 +355,17 @@ int tls_sk_attach(struct sock *sk, int optname, char __user *optval, ...@@ -357,14 +355,17 @@ int tls_sk_attach(struct sock *sk, int optname, char __user *optval,
int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx); int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx);
void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx); void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx);
void tls_sw_strparser_done(struct tls_context *tls_ctx);
int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
int tls_sw_sendpage(struct sock *sk, struct page *page, int tls_sw_sendpage(struct sock *sk, struct page *page,
int offset, size_t size, int flags); int offset, size_t size, int flags);
void tls_sw_close(struct sock *sk, long timeout); void tls_sw_close(struct sock *sk, long timeout);
void tls_sw_cancel_work_tx(struct tls_context *tls_ctx); void tls_sw_cancel_work_tx(struct tls_context *tls_ctx);
void tls_sw_free_resources_tx(struct sock *sk); void tls_sw_release_resources_tx(struct sock *sk);
void tls_sw_free_ctx_tx(struct tls_context *tls_ctx);
void tls_sw_free_resources_rx(struct sock *sk); void tls_sw_free_resources_rx(struct sock *sk);
void tls_sw_release_resources_rx(struct sock *sk); void tls_sw_release_resources_rx(struct sock *sk);
void tls_sw_free_ctx_rx(struct tls_context *tls_ctx);
int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int nonblock, int flags, int *addr_len); int nonblock, int flags, int *addr_len);
bool tls_sw_stream_read(const struct sock *sk); bool tls_sw_stream_read(const struct sock *sk);
......
...@@ -1045,7 +1045,6 @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) ...@@ -1045,7 +1045,6 @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx)
rc = tls_set_sw_offload(sk, ctx, 0); rc = tls_set_sw_offload(sk, ctx, 0);
if (rc) if (rc)
goto release_ctx; goto release_ctx;
tls_sw_strparser_arm(sk, ctx);
rc = netdev->tlsdev_ops->tls_dev_add(netdev, sk, TLS_OFFLOAD_CTX_DIR_RX, rc = netdev->tlsdev_ops->tls_dev_add(netdev, sk, TLS_OFFLOAD_CTX_DIR_RX,
&ctx->crypto_recv.info, &ctx->crypto_recv.info,
......
...@@ -261,24 +261,9 @@ void tls_ctx_free(struct tls_context *ctx) ...@@ -261,24 +261,9 @@ void tls_ctx_free(struct tls_context *ctx)
kfree(ctx); kfree(ctx);
} }
static void tls_sk_proto_close(struct sock *sk, long timeout) static void tls_sk_proto_cleanup(struct sock *sk,
struct tls_context *ctx, long timeo)
{ {
struct tls_context *ctx = tls_get_ctx(sk);
long timeo = sock_sndtimeo(sk, 0);
void (*sk_proto_close)(struct sock *sk, long timeout);
bool free_ctx = false;
if (ctx->tx_conf == TLS_SW)
tls_sw_cancel_work_tx(ctx);
lock_sock(sk);
sk_proto_close = ctx->sk_proto_close;
if (ctx->tx_conf == TLS_BASE && ctx->rx_conf == TLS_BASE) {
free_ctx = true;
goto skip_tx_cleanup;
}
if (unlikely(sk->sk_write_pending) && if (unlikely(sk->sk_write_pending) &&
!wait_on_pending_writer(sk, &timeo)) !wait_on_pending_writer(sk, &timeo))
tls_handle_open_record(sk, 0); tls_handle_open_record(sk, 0);
...@@ -287,7 +272,7 @@ static void tls_sk_proto_close(struct sock *sk, long timeout) ...@@ -287,7 +272,7 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
if (ctx->tx_conf == TLS_SW) { if (ctx->tx_conf == TLS_SW) {
kfree(ctx->tx.rec_seq); kfree(ctx->tx.rec_seq);
kfree(ctx->tx.iv); kfree(ctx->tx.iv);
tls_sw_free_resources_tx(sk); tls_sw_release_resources_tx(sk);
#ifdef CONFIG_TLS_DEVICE #ifdef CONFIG_TLS_DEVICE
} else if (ctx->tx_conf == TLS_HW) { } else if (ctx->tx_conf == TLS_HW) {
tls_device_free_resources_tx(sk); tls_device_free_resources_tx(sk);
...@@ -295,26 +280,40 @@ static void tls_sk_proto_close(struct sock *sk, long timeout) ...@@ -295,26 +280,40 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
} }
if (ctx->rx_conf == TLS_SW) if (ctx->rx_conf == TLS_SW)
tls_sw_free_resources_rx(sk); tls_sw_release_resources_rx(sk);
#ifdef CONFIG_TLS_DEVICE #ifdef CONFIG_TLS_DEVICE
if (ctx->rx_conf == TLS_HW) if (ctx->rx_conf == TLS_HW)
tls_device_offload_cleanup_rx(sk); tls_device_offload_cleanup_rx(sk);
if (ctx->tx_conf != TLS_HW && ctx->rx_conf != TLS_HW) {
#else
{
#endif #endif
tls_ctx_free(ctx); }
ctx = NULL;
} static void tls_sk_proto_close(struct sock *sk, long timeout)
{
void (*sk_proto_close)(struct sock *sk, long timeout);
struct tls_context *ctx = tls_get_ctx(sk);
long timeo = sock_sndtimeo(sk, 0);
bool free_ctx;
if (ctx->tx_conf == TLS_SW)
tls_sw_cancel_work_tx(ctx);
lock_sock(sk);
free_ctx = ctx->tx_conf != TLS_HW && ctx->rx_conf != TLS_HW;
sk_proto_close = ctx->sk_proto_close;
if (ctx->tx_conf != TLS_BASE || ctx->rx_conf != TLS_BASE)
tls_sk_proto_cleanup(sk, ctx, timeo);
skip_tx_cleanup:
release_sock(sk); release_sock(sk);
if (ctx->tx_conf == TLS_SW)
tls_sw_free_ctx_tx(ctx);
if (ctx->rx_conf == TLS_SW || ctx->rx_conf == TLS_HW)
tls_sw_strparser_done(ctx);
if (ctx->rx_conf == TLS_SW)
tls_sw_free_ctx_rx(ctx);
sk_proto_close(sk, timeout); sk_proto_close(sk, timeout);
/* free ctx for TLS_HW_RECORD, used by tcp_set_state
* for sk->sk_prot->unhash [tls_hw_unhash]
*/
if (free_ctx) if (free_ctx)
tls_ctx_free(ctx); tls_ctx_free(ctx);
} }
...@@ -541,9 +540,9 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval, ...@@ -541,9 +540,9 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
rc = tls_set_sw_offload(sk, ctx, 0); rc = tls_set_sw_offload(sk, ctx, 0);
if (rc) if (rc)
goto err_crypto_info; goto err_crypto_info;
tls_sw_strparser_arm(sk, ctx);
conf = TLS_SW; conf = TLS_SW;
} }
tls_sw_strparser_arm(sk, ctx);
} }
if (tx) if (tx)
......
...@@ -2063,7 +2063,7 @@ void tls_sw_cancel_work_tx(struct tls_context *tls_ctx) ...@@ -2063,7 +2063,7 @@ void tls_sw_cancel_work_tx(struct tls_context *tls_ctx)
cancel_delayed_work_sync(&ctx->tx_work.work); cancel_delayed_work_sync(&ctx->tx_work.work);
} }
void tls_sw_free_resources_tx(struct sock *sk) void tls_sw_release_resources_tx(struct sock *sk)
{ {
struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_context *tls_ctx = tls_get_ctx(sk);
struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
...@@ -2096,6 +2096,11 @@ void tls_sw_free_resources_tx(struct sock *sk) ...@@ -2096,6 +2096,11 @@ void tls_sw_free_resources_tx(struct sock *sk)
crypto_free_aead(ctx->aead_send); crypto_free_aead(ctx->aead_send);
tls_free_open_rec(sk); tls_free_open_rec(sk);
}
void tls_sw_free_ctx_tx(struct tls_context *tls_ctx)
{
struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
kfree(ctx); kfree(ctx);
} }
...@@ -2114,25 +2119,40 @@ void tls_sw_release_resources_rx(struct sock *sk) ...@@ -2114,25 +2119,40 @@ void tls_sw_release_resources_rx(struct sock *sk)
skb_queue_purge(&ctx->rx_list); skb_queue_purge(&ctx->rx_list);
crypto_free_aead(ctx->aead_recv); crypto_free_aead(ctx->aead_recv);
strp_stop(&ctx->strp); strp_stop(&ctx->strp);
write_lock_bh(&sk->sk_callback_lock); /* If tls_sw_strparser_arm() was not called (cleanup paths)
sk->sk_data_ready = ctx->saved_data_ready; * we still want to strp_stop(), but sk->sk_data_ready was
write_unlock_bh(&sk->sk_callback_lock); * never swapped.
release_sock(sk); */
strp_done(&ctx->strp); if (ctx->saved_data_ready) {
lock_sock(sk); write_lock_bh(&sk->sk_callback_lock);
sk->sk_data_ready = ctx->saved_data_ready;
write_unlock_bh(&sk->sk_callback_lock);
}
} }
} }
void tls_sw_free_resources_rx(struct sock *sk) void tls_sw_strparser_done(struct tls_context *tls_ctx)
{ {
struct tls_context *tls_ctx = tls_get_ctx(sk);
struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx);
tls_sw_release_resources_rx(sk); strp_done(&ctx->strp);
}
void tls_sw_free_ctx_rx(struct tls_context *tls_ctx)
{
struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx);
kfree(ctx); kfree(ctx);
} }
void tls_sw_free_resources_rx(struct sock *sk)
{
struct tls_context *tls_ctx = tls_get_ctx(sk);
tls_sw_release_resources_rx(sk);
tls_sw_free_ctx_rx(tls_ctx);
}
/* The work handler to transmitt the encrypted records in tx_list */ /* The work handler to transmitt the encrypted records in tx_list */
static void tx_work_handler(struct work_struct *work) static void tx_work_handler(struct work_struct *work)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment