diff options
author | Jakub Kicinski <jakub.kicinski@netronome.com> | 2019-11-05 17:24:35 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-11-06 20:33:32 -0500 |
commit | 79ffe6087e9145d2377385cac48d0d6a6b4225a5 (patch) | |
tree | 7ad119676734db269b7ae127d3bf0908339306eb /net | |
parent | 02b1fa07bb58f5d1f349b5b09eb936739a7b20fc (diff) |
net/tls: add a TX lock
TLS TX needs to release and re-acquire the socket lock if send buffer
fills up.
TLS SW TX path currently depends on only allowing one thread to enter
the function by the abuse of sk_write_pending. If another writer is
already waiting for memory no new ones are allowed in.
This has two problems:
- writers don't wake other threads up when they leave the kernel;
meaning that this scheme works for single extra thread (second
application thread or delayed work) because memory becoming
available will send a wake up request, but as Mallesham and
Pooja report with larger number of threads it leads to threads
being put to sleep indefinitely;
- the delayed work does not get _scheduled_ but it may _run_ when
other writers are present leading to crashes as writers don't
expect state to change under their feet (same records get pushed
and freed multiple times); it's hard to reliably bail from the
work, however, because the mere presence of a writer does not
guarantee that the writer will push pending records before exiting.
Ensuring wakeups always happen will make the code basically open
code a mutex. Just use a mutex.
The TLS HW TX path does not have any locking (not even the
sk_write_pending hack), yet it uses a per-socket sg_tx_data
array to push records.
Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption of records for performance")
Reported-by: Mallesham Jatharakonda <mallesh537@gmail.com>
Reported-by: Pooja Trivedi <poojatrivedi@gmail.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/tls/tls_device.c | 6 | ||||
-rw-r--r-- | net/tls/tls_main.c | 2 | ||||
-rw-r--r-- | net/tls/tls_sw.c | 21 |
3 files changed, 15 insertions, 14 deletions
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 5a3715ddc592..683d00837693 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c | |||
@@ -523,8 +523,10 @@ last_record: | |||
523 | int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | 523 | int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) |
524 | { | 524 | { |
525 | unsigned char record_type = TLS_RECORD_TYPE_DATA; | 525 | unsigned char record_type = TLS_RECORD_TYPE_DATA; |
526 | struct tls_context *tls_ctx = tls_get_ctx(sk); | ||
526 | int rc; | 527 | int rc; |
527 | 528 | ||
529 | mutex_lock(&tls_ctx->tx_lock); | ||
528 | lock_sock(sk); | 530 | lock_sock(sk); |
529 | 531 | ||
530 | if (unlikely(msg->msg_controllen)) { | 532 | if (unlikely(msg->msg_controllen)) { |
@@ -538,12 +540,14 @@ int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | |||
538 | 540 | ||
539 | out: | 541 | out: |
540 | release_sock(sk); | 542 | release_sock(sk); |
543 | mutex_unlock(&tls_ctx->tx_lock); | ||
541 | return rc; | 544 | return rc; |
542 | } | 545 | } |
543 | 546 | ||
544 | int tls_device_sendpage(struct sock *sk, struct page *page, | 547 | int tls_device_sendpage(struct sock *sk, struct page *page, |
545 | int offset, size_t size, int flags) | 548 | int offset, size_t size, int flags) |
546 | { | 549 | { |
550 | struct tls_context *tls_ctx = tls_get_ctx(sk); | ||
547 | struct iov_iter msg_iter; | 551 | struct iov_iter msg_iter; |
548 | char *kaddr = kmap(page); | 552 | char *kaddr = kmap(page); |
549 | struct kvec iov; | 553 | struct kvec iov; |
@@ -552,6 +556,7 @@ int tls_device_sendpage(struct sock *sk, struct page *page, | |||
552 | if (flags & MSG_SENDPAGE_NOTLAST) | 556 | if (flags & MSG_SENDPAGE_NOTLAST) |
553 | flags |= MSG_MORE; | 557 | flags |= MSG_MORE; |
554 | 558 | ||
559 | mutex_lock(&tls_ctx->tx_lock); | ||
555 | lock_sock(sk); | 560 | lock_sock(sk); |
556 | 561 | ||
557 | if (flags & MSG_OOB) { | 562 | if (flags & MSG_OOB) { |
@@ -568,6 +573,7 @@ int tls_device_sendpage(struct sock *sk, struct page *page, | |||
568 | 573 | ||
569 | out: | 574 | out: |
570 | release_sock(sk); | 575 | release_sock(sk); |
576 | mutex_unlock(&tls_ctx->tx_lock); | ||
571 | return rc; | 577 | return rc; |
572 | } | 578 | } |
573 | 579 | ||
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index ac88877dcade..0775ae40fcfb 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c | |||
@@ -267,6 +267,7 @@ void tls_ctx_free(struct sock *sk, struct tls_context *ctx) | |||
267 | 267 | ||
268 | memzero_explicit(&ctx->crypto_send, sizeof(ctx->crypto_send)); | 268 | memzero_explicit(&ctx->crypto_send, sizeof(ctx->crypto_send)); |
269 | memzero_explicit(&ctx->crypto_recv, sizeof(ctx->crypto_recv)); | 269 | memzero_explicit(&ctx->crypto_recv, sizeof(ctx->crypto_recv)); |
270 | mutex_destroy(&ctx->tx_lock); | ||
270 | 271 | ||
271 | if (sk) | 272 | if (sk) |
272 | kfree_rcu(ctx, rcu); | 273 | kfree_rcu(ctx, rcu); |
@@ -612,6 +613,7 @@ static struct tls_context *create_ctx(struct sock *sk) | |||
612 | if (!ctx) | 613 | if (!ctx) |
613 | return NULL; | 614 | return NULL; |
614 | 615 | ||
616 | mutex_init(&ctx->tx_lock); | ||
615 | rcu_assign_pointer(icsk->icsk_ulp_data, ctx); | 617 | rcu_assign_pointer(icsk->icsk_ulp_data, ctx); |
616 | ctx->sk_proto = sk->sk_prot; | 618 | ctx->sk_proto = sk->sk_prot; |
617 | return ctx; | 619 | return ctx; |
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index e155b792df0b..446f23c1f3ce 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c | |||
@@ -897,15 +897,9 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | |||
897 | if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL)) | 897 | if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL)) |
898 | return -ENOTSUPP; | 898 | return -ENOTSUPP; |
899 | 899 | ||
900 | mutex_lock(&tls_ctx->tx_lock); | ||
900 | lock_sock(sk); | 901 | lock_sock(sk); |
901 | 902 | ||
902 | /* Wait till there is any pending write on socket */ | ||
903 | if (unlikely(sk->sk_write_pending)) { | ||
904 | ret = wait_on_pending_writer(sk, &timeo); | ||
905 | if (unlikely(ret)) | ||
906 | goto send_end; | ||
907 | } | ||
908 | |||
909 | if (unlikely(msg->msg_controllen)) { | 903 | if (unlikely(msg->msg_controllen)) { |
910 | ret = tls_proccess_cmsg(sk, msg, &record_type); | 904 | ret = tls_proccess_cmsg(sk, msg, &record_type); |
911 | if (ret) { | 905 | if (ret) { |
@@ -1091,6 +1085,7 @@ send_end: | |||
1091 | ret = sk_stream_error(sk, msg->msg_flags, ret); | 1085 | ret = sk_stream_error(sk, msg->msg_flags, ret); |
1092 | 1086 | ||
1093 | release_sock(sk); | 1087 | release_sock(sk); |
1088 | mutex_unlock(&tls_ctx->tx_lock); | ||
1094 | return copied ? copied : ret; | 1089 | return copied ? copied : ret; |
1095 | } | 1090 | } |
1096 | 1091 | ||
@@ -1114,13 +1109,6 @@ static int tls_sw_do_sendpage(struct sock *sk, struct page *page, | |||
1114 | eor = !(flags & (MSG_MORE | MSG_SENDPAGE_NOTLAST)); | 1109 | eor = !(flags & (MSG_MORE | MSG_SENDPAGE_NOTLAST)); |
1115 | sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); | 1110 | sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); |
1116 | 1111 | ||
1117 | /* Wait till there is any pending write on socket */ | ||
1118 | if (unlikely(sk->sk_write_pending)) { | ||
1119 | ret = wait_on_pending_writer(sk, &timeo); | ||
1120 | if (unlikely(ret)) | ||
1121 | goto sendpage_end; | ||
1122 | } | ||
1123 | |||
1124 | /* Call the sk_stream functions to manage the sndbuf mem. */ | 1112 | /* Call the sk_stream functions to manage the sndbuf mem. */ |
1125 | while (size > 0) { | 1113 | while (size > 0) { |
1126 | size_t copy, required_size; | 1114 | size_t copy, required_size; |
@@ -1219,15 +1207,18 @@ sendpage_end: | |||
1219 | int tls_sw_sendpage(struct sock *sk, struct page *page, | 1207 | int tls_sw_sendpage(struct sock *sk, struct page *page, |
1220 | int offset, size_t size, int flags) | 1208 | int offset, size_t size, int flags) |
1221 | { | 1209 | { |
1210 | struct tls_context *tls_ctx = tls_get_ctx(sk); | ||
1222 | int ret; | 1211 | int ret; |
1223 | 1212 | ||
1224 | if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | | 1213 | if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | |
1225 | MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) | 1214 | MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) |
1226 | return -ENOTSUPP; | 1215 | return -ENOTSUPP; |
1227 | 1216 | ||
1217 | mutex_lock(&tls_ctx->tx_lock); | ||
1228 | lock_sock(sk); | 1218 | lock_sock(sk); |
1229 | ret = tls_sw_do_sendpage(sk, page, offset, size, flags); | 1219 | ret = tls_sw_do_sendpage(sk, page, offset, size, flags); |
1230 | release_sock(sk); | 1220 | release_sock(sk); |
1221 | mutex_unlock(&tls_ctx->tx_lock); | ||
1231 | return ret; | 1222 | return ret; |
1232 | } | 1223 | } |
1233 | 1224 | ||
@@ -2170,9 +2161,11 @@ static void tx_work_handler(struct work_struct *work) | |||
2170 | 2161 | ||
2171 | if (!test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) | 2162 | if (!test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) |
2172 | return; | 2163 | return; |
2164 | mutex_lock(&tls_ctx->tx_lock); | ||
2173 | lock_sock(sk); | 2165 | lock_sock(sk); |
2174 | tls_tx_records(sk, -1); | 2166 | tls_tx_records(sk, -1); |
2175 | release_sock(sk); | 2167 | release_sock(sk); |
2168 | mutex_unlock(&tls_ctx->tx_lock); | ||
2176 | } | 2169 | } |
2177 | 2170 | ||
2178 | void tls_sw_write_space(struct sock *sk, struct tls_context *ctx) | 2171 | void tls_sw_write_space(struct sock *sk, struct tls_context *ctx) |