| From d3e008c647b732c45c8532905abbf91bbf433186 Mon Sep 17 00:00:00 2001 |
| From: Eric Dumazet <edumazet@google.com> |
| Date: Tue, 30 Jun 2020 16:41:01 -0700 |
| Subject: [PATCH] tcp: md5: add missing memory barriers in |
| tcp_md5_do_add()/tcp_md5_hash_key() |
| |
| commit 6a2febec338df7e7699a52d00b2e1207dcf65b28 upstream. |
| |
| MD5 keys are read with RCU protection, and tcp_md5_do_add() |
| might update in-place a prior key. |
| |
| Normally, typical RCU updates would allocate a new piece |
| of memory. In this case only key->key and key->keylen might |
| be updated, and we do not care if an incoming packet could |
| see the old key, the new one, or some intermediate value, |
| since changing the key on a live flow is known to be problematic |
| anyway. |
| |
| We only want to make sure that in the case key->keylen |
| is changed, cpus in tcp_md5_hash_key() wont try to use |
| uninitialized data, or crash because key->keylen was |
| read twice to feed sg_init_one() and ahash_request_set_crypt() |
| |
| Fixes: 9ea88a153001 ("tcp: md5: check md5 signature without socket lock") |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c |
| index 9bd121004d19..18282f5ff66e 100644 |
| --- a/net/ipv4/tcp.c |
| +++ b/net/ipv4/tcp.c |
| @@ -3809,10 +3809,13 @@ EXPORT_SYMBOL(tcp_md5_hash_skb_data); |
| |
| int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, const struct tcp_md5sig_key *key) |
| { |
| + u8 keylen = key->keylen; |
| struct scatterlist sg; |
| |
| - sg_init_one(&sg, key->key, key->keylen); |
| - ahash_request_set_crypt(hp->md5_req, &sg, NULL, key->keylen); |
| + smp_rmb(); /* paired with smp_wmb() in tcp_md5_do_add() */ |
| + |
| + sg_init_one(&sg, key->key, keylen); |
| + ahash_request_set_crypt(hp->md5_req, &sg, NULL, keylen); |
| return crypto_ahash_update(hp->md5_req); |
| } |
| EXPORT_SYMBOL(tcp_md5_hash_key); |
| diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c |
| index 16591cccbeff..4e1252674a1f 100644 |
| --- a/net/ipv4/tcp_ipv4.c |
| +++ b/net/ipv4/tcp_ipv4.c |
| @@ -1069,6 +1069,9 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, |
| if (key) { |
| /* Pre-existing entry - just update that one. */ |
| memcpy(key->key, newkey, newkeylen); |
| + |
| + smp_wmb(); /* pairs with smp_rmb() in tcp_md5_hash_key() */ |
| + |
| key->keylen = newkeylen; |
| return 0; |
| } |
| -- |
| 2.27.0 |
| |