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>
This commit is contained in:
parent
435c556cde
commit
19689e38ec
|
@ -1384,7 +1384,7 @@ union tcp_md5sum_block {
|
||||||
/* - pool: digest algorithm, hash description and scratch buffer */
|
/* - pool: digest algorithm, hash description and scratch buffer */
|
||||||
struct tcp_md5sig_pool {
|
struct tcp_md5sig_pool {
|
||||||
struct ahash_request *md5_req;
|
struct ahash_request *md5_req;
|
||||||
union tcp_md5sum_block md5_blk;
|
void *scratch;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* - functions */
|
/* - functions */
|
||||||
|
@ -1420,7 +1420,6 @@ static inline void tcp_put_md5sig_pool(void)
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcp_md5_hash_header(struct tcp_md5sig_pool *, const struct tcphdr *);
|
|
||||||
int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff *,
|
int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff *,
|
||||||
unsigned int header_len);
|
unsigned int header_len);
|
||||||
int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
|
int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
|
||||||
|
|
|
@ -3026,8 +3026,18 @@ static void __tcp_alloc_md5sig_pool(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
|
void *scratch = per_cpu(tcp_md5sig_pool, cpu).scratch;
|
||||||
struct ahash_request *req;
|
struct ahash_request *req;
|
||||||
|
|
||||||
|
if (!scratch) {
|
||||||
|
scratch = kmalloc_node(sizeof(union tcp_md5sum_block) +
|
||||||
|
sizeof(struct tcphdr),
|
||||||
|
GFP_KERNEL,
|
||||||
|
cpu_to_node(cpu));
|
||||||
|
if (!scratch)
|
||||||
|
return;
|
||||||
|
per_cpu(tcp_md5sig_pool, cpu).scratch = scratch;
|
||||||
|
}
|
||||||
if (per_cpu(tcp_md5sig_pool, cpu).md5_req)
|
if (per_cpu(tcp_md5sig_pool, cpu).md5_req)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -1018,27 +1018,28 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
|
static int tcp_v4_md5_hash_headers(struct tcp_md5sig_pool *hp,
|
||||||
__be32 daddr, __be32 saddr, int nbytes)
|
__be32 daddr, __be32 saddr,
|
||||||
|
const struct tcphdr *th, int nbytes)
|
||||||
{
|
{
|
||||||
struct tcp4_pseudohdr *bp;
|
struct tcp4_pseudohdr *bp;
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
|
struct tcphdr *_th;
|
||||||
|
|
||||||
bp = &hp->md5_blk.ip4;
|
bp = hp->scratch;
|
||||||
|
|
||||||
/*
|
|
||||||
* 1. the TCP pseudo-header (in the order: source IP address,
|
|
||||||
* destination IP address, zero-padded protocol number, and
|
|
||||||
* segment length)
|
|
||||||
*/
|
|
||||||
bp->saddr = saddr;
|
bp->saddr = saddr;
|
||||||
bp->daddr = daddr;
|
bp->daddr = daddr;
|
||||||
bp->pad = 0;
|
bp->pad = 0;
|
||||||
bp->protocol = IPPROTO_TCP;
|
bp->protocol = IPPROTO_TCP;
|
||||||
bp->len = cpu_to_be16(nbytes);
|
bp->len = cpu_to_be16(nbytes);
|
||||||
|
|
||||||
sg_init_one(&sg, bp, sizeof(*bp));
|
_th = (struct tcphdr *)(bp + 1);
|
||||||
ahash_request_set_crypt(hp->md5_req, &sg, NULL, sizeof(*bp));
|
memcpy(_th, th, sizeof(*th));
|
||||||
|
_th->check = 0;
|
||||||
|
|
||||||
|
sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
|
||||||
|
ahash_request_set_crypt(hp->md5_req, &sg, NULL,
|
||||||
|
sizeof(*bp) + sizeof(*th));
|
||||||
return crypto_ahash_update(hp->md5_req);
|
return crypto_ahash_update(hp->md5_req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1055,9 +1056,7 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
|
||||||
|
|
||||||
if (crypto_ahash_init(req))
|
if (crypto_ahash_init(req))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
|
if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
|
||||||
goto clear_hash;
|
|
||||||
if (tcp_md5_hash_header(hp, th))
|
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
if (tcp_md5_hash_key(hp, key))
|
if (tcp_md5_hash_key(hp, key))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
|
@ -1101,9 +1100,7 @@ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
|
||||||
if (crypto_ahash_init(req))
|
if (crypto_ahash_init(req))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
|
|
||||||
if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
|
if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, skb->len))
|
||||||
goto clear_hash;
|
|
||||||
if (tcp_md5_hash_header(hp, th))
|
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
|
if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
|
|
|
@ -526,26 +526,33 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval,
|
||||||
AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
|
AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
|
static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
|
||||||
const struct in6_addr *daddr,
|
const struct in6_addr *daddr,
|
||||||
const struct in6_addr *saddr, int nbytes)
|
const struct in6_addr *saddr,
|
||||||
|
const struct tcphdr *th, int nbytes)
|
||||||
{
|
{
|
||||||
struct tcp6_pseudohdr *bp;
|
struct tcp6_pseudohdr *bp;
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
|
struct tcphdr *_th;
|
||||||
|
|
||||||
bp = &hp->md5_blk.ip6;
|
bp = hp->scratch;
|
||||||
/* 1. TCP pseudo-header (RFC2460) */
|
/* 1. TCP pseudo-header (RFC2460) */
|
||||||
bp->saddr = *saddr;
|
bp->saddr = *saddr;
|
||||||
bp->daddr = *daddr;
|
bp->daddr = *daddr;
|
||||||
bp->protocol = cpu_to_be32(IPPROTO_TCP);
|
bp->protocol = cpu_to_be32(IPPROTO_TCP);
|
||||||
bp->len = cpu_to_be32(nbytes);
|
bp->len = cpu_to_be32(nbytes);
|
||||||
|
|
||||||
sg_init_one(&sg, bp, sizeof(*bp));
|
_th = (struct tcphdr *)(bp + 1);
|
||||||
ahash_request_set_crypt(hp->md5_req, &sg, NULL, sizeof(*bp));
|
memcpy(_th, th, sizeof(*th));
|
||||||
|
_th->check = 0;
|
||||||
|
|
||||||
|
sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
|
||||||
|
ahash_request_set_crypt(hp->md5_req, &sg, NULL,
|
||||||
|
sizeof(*bp) + sizeof(*th));
|
||||||
return crypto_ahash_update(hp->md5_req);
|
return crypto_ahash_update(hp->md5_req);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
|
static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
|
||||||
const struct in6_addr *daddr, struct in6_addr *saddr,
|
const struct in6_addr *daddr, struct in6_addr *saddr,
|
||||||
const struct tcphdr *th)
|
const struct tcphdr *th)
|
||||||
{
|
{
|
||||||
|
@ -559,9 +566,7 @@ static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
|
||||||
|
|
||||||
if (crypto_ahash_init(req))
|
if (crypto_ahash_init(req))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
|
if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
|
||||||
goto clear_hash;
|
|
||||||
if (tcp_md5_hash_header(hp, th))
|
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
if (tcp_md5_hash_key(hp, key))
|
if (tcp_md5_hash_key(hp, key))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
|
@ -606,9 +611,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,
|
||||||
if (crypto_ahash_init(req))
|
if (crypto_ahash_init(req))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
|
|
||||||
if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
|
if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len))
|
||||||
goto clear_hash;
|
|
||||||
if (tcp_md5_hash_header(hp, th))
|
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
|
if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
|
||||||
goto clear_hash;
|
goto clear_hash;
|
||||||
|
|
Loading…
Reference in New Issue