Skip to content

Commit 19689e3

Browse files
edumazetdavem330
authored andcommitted
tcp: md5: use kmalloc() backed scratch areas
Some arches have virtually mapped kernel stacks, or will soon have. tcp_md5_hash_header() uses an automatic variable to copy tcp header before mangling th->check and calling crypto function, which might be problematic on such arches. David says that using percpu storage is also problematic on non SMP builds. Just use kmalloc() to allocate scratch areas. Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 435c556 commit 19689e3

File tree

4 files changed

+41
-32
lines changed

4 files changed

+41
-32
lines changed

include/net/tcp.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,7 +1384,7 @@ union tcp_md5sum_block {
13841384
/* - pool: digest algorithm, hash description and scratch buffer */
13851385
struct tcp_md5sig_pool {
13861386
struct ahash_request *md5_req;
1387-
union tcp_md5sum_block md5_blk;
1387+
void *scratch;
13881388
};
13891389

13901390
/* - functions */
@@ -1420,7 +1420,6 @@ static inline void tcp_put_md5sig_pool(void)
14201420
local_bh_enable();
14211421
}
14221422

1423-
int tcp_md5_hash_header(struct tcp_md5sig_pool *, const struct tcphdr *);
14241423
int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff *,
14251424
unsigned int header_len);
14261425
int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,

net/ipv4/tcp.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3026,8 +3026,18 @@ static void __tcp_alloc_md5sig_pool(void)
30263026
return;
30273027

30283028
for_each_possible_cpu(cpu) {
3029+
void *scratch = per_cpu(tcp_md5sig_pool, cpu).scratch;
30293030
struct ahash_request *req;
30303031

3032+
if (!scratch) {
3033+
scratch = kmalloc_node(sizeof(union tcp_md5sum_block) +
3034+
sizeof(struct tcphdr),
3035+
GFP_KERNEL,
3036+
cpu_to_node(cpu));
3037+
if (!scratch)
3038+
return;
3039+
per_cpu(tcp_md5sig_pool, cpu).scratch = scratch;
3040+
}
30313041
if (per_cpu(tcp_md5sig_pool, cpu).md5_req)
30323042
continue;
30333043

net/ipv4/tcp_ipv4.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,27 +1018,28 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
10181018
GFP_KERNEL);
10191019
}
10201020

1021-
static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
1022-
__be32 daddr, __be32 saddr, int nbytes)
1021+
static int tcp_v4_md5_hash_headers(struct tcp_md5sig_pool *hp,
1022+
__be32 daddr, __be32 saddr,
1023+
const struct tcphdr *th, int nbytes)
10231024
{
10241025
struct tcp4_pseudohdr *bp;
10251026
struct scatterlist sg;
1027+
struct tcphdr *_th;
10261028

1027-
bp = &hp->md5_blk.ip4;
1028-
1029-
/*
1030-
* 1. the TCP pseudo-header (in the order: source IP address,
1031-
* destination IP address, zero-padded protocol number, and
1032-
* segment length)
1033-
*/
1029+
bp = hp->scratch;
10341030
bp->saddr = saddr;
10351031
bp->daddr = daddr;
10361032
bp->pad = 0;
10371033
bp->protocol = IPPROTO_TCP;
10381034
bp->len = cpu_to_be16(nbytes);
10391035

1040-
sg_init_one(&sg, bp, sizeof(*bp));
1041-
ahash_request_set_crypt(hp->md5_req, &sg, NULL, sizeof(*bp));
1036+
_th = (struct tcphdr *)(bp + 1);
1037+
memcpy(_th, th, sizeof(*th));
1038+
_th->check = 0;
1039+
1040+
sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
1041+
ahash_request_set_crypt(hp->md5_req, &sg, NULL,
1042+
sizeof(*bp) + sizeof(*th));
10421043
return crypto_ahash_update(hp->md5_req);
10431044
}
10441045

@@ -1055,9 +1056,7 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
10551056

10561057
if (crypto_ahash_init(req))
10571058
goto clear_hash;
1058-
if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
1059-
goto clear_hash;
1060-
if (tcp_md5_hash_header(hp, th))
1059+
if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
10611060
goto clear_hash;
10621061
if (tcp_md5_hash_key(hp, key))
10631062
goto clear_hash;
@@ -1101,9 +1100,7 @@ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
11011100
if (crypto_ahash_init(req))
11021101
goto clear_hash;
11031102

1104-
if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
1105-
goto clear_hash;
1106-
if (tcp_md5_hash_header(hp, th))
1103+
if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, skb->len))
11071104
goto clear_hash;
11081105
if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
11091106
goto clear_hash;

net/ipv6/tcp_ipv6.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -526,26 +526,33 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval,
526526
AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
527527
}
528528

529-
static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
530-
const struct in6_addr *daddr,
531-
const struct in6_addr *saddr, int nbytes)
529+
static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
530+
const struct in6_addr *daddr,
531+
const struct in6_addr *saddr,
532+
const struct tcphdr *th, int nbytes)
532533
{
533534
struct tcp6_pseudohdr *bp;
534535
struct scatterlist sg;
536+
struct tcphdr *_th;
535537

536-
bp = &hp->md5_blk.ip6;
538+
bp = hp->scratch;
537539
/* 1. TCP pseudo-header (RFC2460) */
538540
bp->saddr = *saddr;
539541
bp->daddr = *daddr;
540542
bp->protocol = cpu_to_be32(IPPROTO_TCP);
541543
bp->len = cpu_to_be32(nbytes);
542544

543-
sg_init_one(&sg, bp, sizeof(*bp));
544-
ahash_request_set_crypt(hp->md5_req, &sg, NULL, sizeof(*bp));
545+
_th = (struct tcphdr *)(bp + 1);
546+
memcpy(_th, th, sizeof(*th));
547+
_th->check = 0;
548+
549+
sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
550+
ahash_request_set_crypt(hp->md5_req, &sg, NULL,
551+
sizeof(*bp) + sizeof(*th));
545552
return crypto_ahash_update(hp->md5_req);
546553
}
547554

548-
static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
555+
static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
549556
const struct in6_addr *daddr, struct in6_addr *saddr,
550557
const struct tcphdr *th)
551558
{
@@ -559,9 +566,7 @@ static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
559566

560567
if (crypto_ahash_init(req))
561568
goto clear_hash;
562-
if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
563-
goto clear_hash;
564-
if (tcp_md5_hash_header(hp, th))
569+
if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
565570
goto clear_hash;
566571
if (tcp_md5_hash_key(hp, key))
567572
goto clear_hash;
@@ -606,9 +611,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,
606611
if (crypto_ahash_init(req))
607612
goto clear_hash;
608613

609-
if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
610-
goto clear_hash;
611-
if (tcp_md5_hash_header(hp, th))
614+
if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len))
612615
goto clear_hash;
613616
if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
614617
goto clear_hash;

0 commit comments

Comments
 (0)