Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tcp: Convert tcp-md5 to use MD5 library instead of crypto_ahash

Make tcp-md5 use the MD5 library API (added in 6.18) instead of the
crypto_ahash API. This is much simpler and also more efficient:

- The library API just operates on struct md5_ctx. Just allocate this
struct on the stack instead of using a pool of pre-allocated
crypto_ahash and ahash_request objects.

- The library API accepts standard pointers and doesn't require
scatterlists. So, for hashing the headers just use an on-stack buffer
instead of a pool of pre-allocated kmalloc'ed scratch buffers.

- The library API never fails. Therefore, checking for MD5 hashing
errors is no longer necessary. Update tcp_v4_md5_hash_skb(),
tcp_v6_md5_hash_skb(), tcp_v4_md5_hash_hdr(), tcp_v6_md5_hash_hdr(),
tcp_md5_hash_key(), tcp_sock_af_ops::calc_md5_hash, and
tcp_request_sock_ops::calc_md5_hash to return void instead of int.

- The library API provides direct access to the MD5 code, eliminating
unnecessary overhead such as indirect function calls and scatterlist
management. Microbenchmarks of tcp_v4_md5_hash_skb() on x86_64 show a
speedup from 7518 to 7041 cycles (6% fewer) with skb->len == 1440, or
from 1020 to 678 cycles (33% fewer) with skb->len == 140.

Since tcp_sigpool_hash_skb_data() can no longer be used, add a function
tcp_md5_hash_skb_data() which is specialized to MD5. Of course, to the
extent that this duplicates any code, it's well worth it.

To preserve the existing behavior of TCP-MD5 support being disabled when
the kernel is booted with "fips=1", make tcp_md5_do_add() check
fips_enabled itself. Previously it relied on the error from
crypto_alloc_ahash("md5") being bubbled up. I don't know for sure that
this is actually needed, but this preserves the existing behavior.

Tested with bidirectional TCP-MD5, both IPv4 and IPv6, between a kernel
that includes this commit and a kernel that doesn't include this commit.

(Side note: please don't use TCP-MD5! It's cryptographically weak. But
as long as Linux supports it, it might as well be implemented properly.)

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Link: https://patch.msgid.link/20251014215836.115616-1-ebiggers@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Biggers and committed by
Jakub Kicinski
37a183d3 f578ff4c

+121 -240
+8 -18
include/net/tcp.h
··· 1898 1898 __be32 protocol; /* including padding */ 1899 1899 }; 1900 1900 1901 - union tcp_md5sum_block { 1902 - struct tcp4_pseudohdr ip4; 1903 - #if IS_ENABLED(CONFIG_IPV6) 1904 - struct tcp6_pseudohdr ip6; 1905 - #endif 1906 - }; 1907 - 1908 1901 /* 1909 1902 * struct tcp_sigpool - per-CPU pool of ahash_requests 1910 1903 * @scratch: per-CPU temporary area, that can be used between ··· 1932 1939 void tcp_sigpool_end(struct tcp_sigpool *c); 1933 1940 size_t tcp_sigpool_algo(unsigned int id, char *buf, size_t buf_len); 1934 1941 /* - functions */ 1935 - int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key, 1936 - const struct sock *sk, const struct sk_buff *skb); 1942 + void tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key, 1943 + const struct sock *sk, const struct sk_buff *skb); 1937 1944 int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, 1938 1945 int family, u8 prefixlen, int l3index, u8 flags, 1939 1946 const u8 *newkey, u8 newkeylen); ··· 1992 1999 } 1993 2000 #endif 1994 2001 1995 - int tcp_md5_alloc_sigpool(void); 1996 - void tcp_md5_release_sigpool(void); 1997 - void tcp_md5_add_sigpool(void); 1998 - extern int tcp_md5_sigpool_id; 1999 - 2000 - int tcp_md5_hash_key(struct tcp_sigpool *hp, 2001 - const struct tcp_md5sig_key *key); 2002 + struct md5_ctx; 2003 + void tcp_md5_hash_skb_data(struct md5_ctx *ctx, const struct sk_buff *skb, 2004 + unsigned int header_len); 2005 + void tcp_md5_hash_key(struct md5_ctx *ctx, const struct tcp_md5sig_key *key); 2002 2006 2003 2007 /* From tcp_fastopen.c */ 2004 2008 void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, ··· 2345 2355 #ifdef CONFIG_TCP_MD5SIG 2346 2356 struct tcp_md5sig_key *(*md5_lookup) (const struct sock *sk, 2347 2357 const struct sock *addr_sk); 2348 - int (*calc_md5_hash)(char *location, 2358 + void (*calc_md5_hash)(char *location, 2349 2359 const struct tcp_md5sig_key *md5, 2350 2360 const struct sock *sk, 2351 2361 const struct sk_buff *skb); ··· 2373 2383 #ifdef CONFIG_TCP_MD5SIG 2374 2384 struct tcp_md5sig_key *(*req_md5_lookup)(const struct sock *sk, 2375 2385 const struct sock *addr_sk); 2376 - int (*calc_md5_hash) (char *location, 2386 + void (*calc_md5_hash) (char *location, 2377 2387 const struct tcp_md5sig_key *md5, 2378 2388 const struct sock *sk, 2379 2389 const struct sk_buff *skb);
+1 -3
net/ipv4/Kconfig
··· 760 760 761 761 config TCP_MD5SIG 762 762 bool "TCP: MD5 Signature Option support (RFC2385)" 763 - select CRYPTO 764 - select CRYPTO_MD5 765 - select TCP_SIGPOOL 763 + select CRYPTO_LIB_MD5 766 764 help 767 765 RFC2385 specifies a method of giving MD5 protection to TCP sessions. 768 766 Its main (only?) use is to protect BGP sessions between core routers
+31 -42
net/ipv4/tcp.c
··· 243 243 244 244 #define pr_fmt(fmt) "TCP: " fmt 245 245 246 - #include <crypto/hash.h> 246 + #include <crypto/md5.h> 247 247 #include <linux/kernel.h> 248 248 #include <linux/module.h> 249 249 #include <linux/types.h> ··· 253 253 #include <linux/init.h> 254 254 #include <linux/fs.h> 255 255 #include <linux/skbuff.h> 256 - #include <linux/scatterlist.h> 257 256 #include <linux/splice.h> 258 257 #include <linux/net.h> 259 258 #include <linux/socket.h> ··· 424 425 tcp_clear_md5_list(sk); 425 426 kfree(rcu_replace_pointer(tp->md5sig_info, NULL, 1)); 426 427 static_branch_slow_dec_deferred(&tcp_md5_needed); 427 - tcp_md5_release_sigpool(); 428 428 } 429 429 } 430 430 EXPORT_IPV6_MOD_GPL(tcp_md5_destruct_sock); ··· 4836 4838 EXPORT_IPV6_MOD(tcp_getsockopt); 4837 4839 4838 4840 #ifdef CONFIG_TCP_MD5SIG 4839 - int tcp_md5_sigpool_id = -1; 4840 - EXPORT_IPV6_MOD_GPL(tcp_md5_sigpool_id); 4841 - 4842 - int tcp_md5_alloc_sigpool(void) 4841 + void tcp_md5_hash_skb_data(struct md5_ctx *ctx, const struct sk_buff *skb, 4842 + unsigned int header_len) 4843 4843 { 4844 - size_t scratch_size; 4845 - int ret; 4844 + const unsigned int head_data_len = skb_headlen(skb) > header_len ? 4845 + skb_headlen(skb) - header_len : 0; 4846 + const struct skb_shared_info *shi = skb_shinfo(skb); 4847 + struct sk_buff *frag_iter; 4848 + unsigned int i; 4846 4849 4847 - scratch_size = sizeof(union tcp_md5sum_block) + sizeof(struct tcphdr); 4848 - ret = tcp_sigpool_alloc_ahash("md5", scratch_size); 4849 - if (ret >= 0) { 4850 - /* As long as any md5 sigpool was allocated, the return 4851 - * id would stay the same. Re-write the id only for the case 4852 - * when previously all MD5 keys were deleted and this call 4853 - * allocates the first MD5 key, which may return a different 4854 - * sigpool id than was used previously. 4855 - */ 4856 - WRITE_ONCE(tcp_md5_sigpool_id, ret); /* Avoids the compiler potentially being smart here */ 4857 - return 0; 4850 + md5_update(ctx, (const u8 *)tcp_hdr(skb) + header_len, head_data_len); 4851 + 4852 + for (i = 0; i < shi->nr_frags; ++i) { 4853 + const skb_frag_t *f = &shi->frags[i]; 4854 + u32 p_off, p_len, copied; 4855 + const void *vaddr; 4856 + struct page *p; 4857 + 4858 + skb_frag_foreach_page(f, skb_frag_off(f), skb_frag_size(f), 4859 + p, p_off, p_len, copied) { 4860 + vaddr = kmap_local_page(p); 4861 + md5_update(ctx, vaddr + p_off, p_len); 4862 + kunmap_local(vaddr); 4863 + } 4858 4864 } 4859 - return ret; 4860 - } 4861 4865 4862 - void tcp_md5_release_sigpool(void) 4863 - { 4864 - tcp_sigpool_release(READ_ONCE(tcp_md5_sigpool_id)); 4866 + skb_walk_frags(skb, frag_iter) 4867 + tcp_md5_hash_skb_data(ctx, frag_iter, 0); 4865 4868 } 4869 + EXPORT_IPV6_MOD(tcp_md5_hash_skb_data); 4866 4870 4867 - void tcp_md5_add_sigpool(void) 4868 - { 4869 - tcp_sigpool_get(READ_ONCE(tcp_md5_sigpool_id)); 4870 - } 4871 - 4872 - int tcp_md5_hash_key(struct tcp_sigpool *hp, 4873 - const struct tcp_md5sig_key *key) 4871 + void tcp_md5_hash_key(struct md5_ctx *ctx, 4872 + const struct tcp_md5sig_key *key) 4874 4873 { 4875 4874 u8 keylen = READ_ONCE(key->keylen); /* paired with WRITE_ONCE() in tcp_md5_do_add */ 4876 - struct scatterlist sg; 4877 - 4878 - sg_init_one(&sg, key->key, keylen); 4879 - ahash_request_set_crypt(hp->req, &sg, NULL, keylen); 4880 4875 4881 4876 /* We use data_race() because tcp_md5_do_add() might change 4882 4877 * key->key under us 4883 4878 */ 4884 - return data_race(crypto_ahash_update(hp->req)); 4879 + data_race(({ md5_update(ctx, key->key, keylen), 0; })); 4885 4880 } 4886 4881 EXPORT_IPV6_MOD(tcp_md5_hash_key); 4887 4882 ··· 4893 4902 const struct tcp_sock *tp = tcp_sk(sk); 4894 4903 struct tcp_md5sig_key *key; 4895 4904 u8 newhash[16]; 4896 - int genhash; 4897 4905 4898 4906 key = tcp_md5_do_lookup(sk, l3index, saddr, family); 4899 4907 ··· 4907 4917 * IPv4-mapped case. 4908 4918 */ 4909 4919 if (family == AF_INET) 4910 - genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, skb); 4920 + tcp_v4_md5_hash_skb(newhash, key, NULL, skb); 4911 4921 else 4912 - genhash = tp->af_specific->calc_md5_hash(newhash, key, 4913 - NULL, skb); 4914 - if (genhash || memcmp(hash_location, newhash, 16) != 0) { 4922 + tp->af_specific->calc_md5_hash(newhash, key, NULL, skb); 4923 + if (memcmp(hash_location, newhash, 16) != 0) { 4915 4924 NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE); 4916 4925 trace_tcp_hash_md5_mismatch(sk, skb); 4917 4926 return SKB_DROP_REASON_TCP_MD5FAILURE;
+45 -94
net/ipv4/tcp_ipv4.c
··· 53 53 #include <linux/module.h> 54 54 #include <linux/random.h> 55 55 #include <linux/cache.h> 56 + #include <linux/fips.h> 56 57 #include <linux/jhash.h> 57 58 #include <linux/init.h> 58 59 #include <linux/times.h> ··· 87 86 #include <linux/btf_ids.h> 88 87 #include <linux/skbuff_ref.h> 89 88 90 - #include <crypto/hash.h> 91 - #include <linux/scatterlist.h> 89 + #include <crypto/md5.h> 92 90 93 91 #include <trace/events/tcp.h> 94 92 95 93 #ifdef CONFIG_TCP_MD5SIG 96 - static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, 97 - __be32 daddr, __be32 saddr, const struct tcphdr *th); 94 + static void tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, 95 + __be32 daddr, __be32 saddr, const struct tcphdr *th); 98 96 #endif 99 97 100 98 struct inet_hashinfo tcp_hashinfo; ··· 754 754 struct tcp_md5sig_key *key = NULL; 755 755 unsigned char newhash[16]; 756 756 struct sock *sk1 = NULL; 757 - int genhash; 758 757 #endif 759 758 u64 transmit_time = 0; 760 759 struct sock *ctl_sk; ··· 839 840 if (!key) 840 841 goto out; 841 842 842 - 843 - genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, skb); 844 - if (genhash || memcmp(md5_hash_location, newhash, 16) != 0) 843 + tcp_v4_md5_hash_skb(newhash, key, NULL, skb); 844 + if (memcmp(md5_hash_location, newhash, 16) != 0) 845 845 goto out; 846 - 847 846 } 848 847 849 848 if (key) { ··· 1422 1425 struct tcp_sock *tp = tcp_sk(sk); 1423 1426 1424 1427 if (!rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk))) { 1425 - if (tcp_md5_alloc_sigpool()) 1426 - return -ENOMEM; 1427 - 1428 - if (tcp_md5sig_info_add(sk, GFP_KERNEL)) { 1429 - tcp_md5_release_sigpool(); 1430 - return -ENOMEM; 1428 + if (fips_enabled) { 1429 + pr_warn_once("TCP-MD5 support is disabled due to FIPS\n"); 1430 + return -EOPNOTSUPP; 1431 1431 } 1432 + 1433 + if (tcp_md5sig_info_add(sk, GFP_KERNEL)) 1434 + return -ENOMEM; 1432 1435 1433 1436 if (!static_branch_inc(&tcp_md5_needed.key)) { 1434 1437 struct tcp_md5sig_info *md5sig; ··· 1436 1439 md5sig = rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk)); 1437 1440 rcu_assign_pointer(tp->md5sig_info, NULL); 1438 1441 kfree_rcu(md5sig, rcu); 1439 - tcp_md5_release_sigpool(); 1440 1442 return -EUSERS; 1441 1443 } 1442 1444 } ··· 1452 1456 struct tcp_sock *tp = tcp_sk(sk); 1453 1457 1454 1458 if (!rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk))) { 1455 - tcp_md5_add_sigpool(); 1456 1459 1457 - if (tcp_md5sig_info_add(sk, sk_gfp_mask(sk, GFP_ATOMIC))) { 1458 - tcp_md5_release_sigpool(); 1460 + if (tcp_md5sig_info_add(sk, sk_gfp_mask(sk, GFP_ATOMIC))) 1459 1461 return -ENOMEM; 1460 - } 1461 1462 1462 1463 if (!static_key_fast_inc_not_disabled(&tcp_md5_needed.key.key)) { 1463 1464 struct tcp_md5sig_info *md5sig; ··· 1463 1470 net_warn_ratelimited("Too many TCP-MD5 keys in the system\n"); 1464 1471 rcu_assign_pointer(tp->md5sig_info, NULL); 1465 1472 kfree_rcu(md5sig, rcu); 1466 - tcp_md5_release_sigpool(); 1467 1473 return -EUSERS; 1468 1474 } 1469 1475 } ··· 1570 1578 cmd.tcpm_key, cmd.tcpm_keylen); 1571 1579 } 1572 1580 1573 - static int tcp_v4_md5_hash_headers(struct tcp_sigpool *hp, 1574 - __be32 daddr, __be32 saddr, 1575 - const struct tcphdr *th, int nbytes) 1581 + static void tcp_v4_md5_hash_headers(struct md5_ctx *ctx, 1582 + __be32 daddr, __be32 saddr, 1583 + const struct tcphdr *th, int nbytes) 1576 1584 { 1577 - struct tcp4_pseudohdr *bp; 1578 - struct scatterlist sg; 1579 - struct tcphdr *_th; 1585 + struct { 1586 + struct tcp4_pseudohdr ip; 1587 + struct tcphdr tcp; 1588 + } h; 1580 1589 1581 - bp = hp->scratch; 1582 - bp->saddr = saddr; 1583 - bp->daddr = daddr; 1584 - bp->pad = 0; 1585 - bp->protocol = IPPROTO_TCP; 1586 - bp->len = cpu_to_be16(nbytes); 1587 - 1588 - _th = (struct tcphdr *)(bp + 1); 1589 - memcpy(_th, th, sizeof(*th)); 1590 - _th->check = 0; 1591 - 1592 - sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th)); 1593 - ahash_request_set_crypt(hp->req, &sg, NULL, 1594 - sizeof(*bp) + sizeof(*th)); 1595 - return crypto_ahash_update(hp->req); 1590 + h.ip.saddr = saddr; 1591 + h.ip.daddr = daddr; 1592 + h.ip.pad = 0; 1593 + h.ip.protocol = IPPROTO_TCP; 1594 + h.ip.len = cpu_to_be16(nbytes); 1595 + h.tcp = *th; 1596 + h.tcp.check = 0; 1597 + md5_update(ctx, (const u8 *)&h, sizeof(h.ip) + sizeof(h.tcp)); 1596 1598 } 1597 1599 1598 - static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, 1599 - __be32 daddr, __be32 saddr, const struct tcphdr *th) 1600 + static noinline_for_stack void 1601 + tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, 1602 + __be32 daddr, __be32 saddr, const struct tcphdr *th) 1600 1603 { 1601 - struct tcp_sigpool hp; 1604 + struct md5_ctx ctx; 1602 1605 1603 - if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp)) 1604 - goto clear_hash_nostart; 1605 - 1606 - if (crypto_ahash_init(hp.req)) 1607 - goto clear_hash; 1608 - if (tcp_v4_md5_hash_headers(&hp, daddr, saddr, th, th->doff << 2)) 1609 - goto clear_hash; 1610 - if (tcp_md5_hash_key(&hp, key)) 1611 - goto clear_hash; 1612 - ahash_request_set_crypt(hp.req, NULL, md5_hash, 0); 1613 - if (crypto_ahash_final(hp.req)) 1614 - goto clear_hash; 1615 - 1616 - tcp_sigpool_end(&hp); 1617 - return 0; 1618 - 1619 - clear_hash: 1620 - tcp_sigpool_end(&hp); 1621 - clear_hash_nostart: 1622 - memset(md5_hash, 0, 16); 1623 - return 1; 1606 + md5_init(&ctx); 1607 + tcp_v4_md5_hash_headers(&ctx, daddr, saddr, th, th->doff << 2); 1608 + tcp_md5_hash_key(&ctx, key); 1609 + md5_final(&ctx, md5_hash); 1624 1610 } 1625 1611 1626 - int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key, 1627 - const struct sock *sk, 1628 - const struct sk_buff *skb) 1612 + noinline_for_stack void 1613 + tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key, 1614 + const struct sock *sk, const struct sk_buff *skb) 1629 1615 { 1630 1616 const struct tcphdr *th = tcp_hdr(skb); 1631 - struct tcp_sigpool hp; 1632 1617 __be32 saddr, daddr; 1618 + struct md5_ctx ctx; 1633 1619 1634 1620 if (sk) { /* valid for establish/request sockets */ 1635 1621 saddr = sk->sk_rcv_saddr; ··· 1618 1648 daddr = iph->daddr; 1619 1649 } 1620 1650 1621 - if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp)) 1622 - goto clear_hash_nostart; 1623 - 1624 - if (crypto_ahash_init(hp.req)) 1625 - goto clear_hash; 1626 - 1627 - if (tcp_v4_md5_hash_headers(&hp, daddr, saddr, th, skb->len)) 1628 - goto clear_hash; 1629 - if (tcp_sigpool_hash_skb_data(&hp, skb, th->doff << 2)) 1630 - goto clear_hash; 1631 - if (tcp_md5_hash_key(&hp, key)) 1632 - goto clear_hash; 1633 - ahash_request_set_crypt(hp.req, NULL, md5_hash, 0); 1634 - if (crypto_ahash_final(hp.req)) 1635 - goto clear_hash; 1636 - 1637 - tcp_sigpool_end(&hp); 1638 - return 0; 1639 - 1640 - clear_hash: 1641 - tcp_sigpool_end(&hp); 1642 - clear_hash_nostart: 1643 - memset(md5_hash, 0, 16); 1644 - return 1; 1651 + md5_init(&ctx); 1652 + tcp_v4_md5_hash_headers(&ctx, daddr, saddr, th, skb->len); 1653 + tcp_md5_hash_skb_data(&ctx, skb, th->doff << 2); 1654 + tcp_md5_hash_key(&ctx, key); 1655 + md5_final(&ctx, md5_hash); 1645 1656 } 1646 1657 EXPORT_IPV6_MOD(tcp_v4_md5_hash_skb); 1647 1658
-2
net/ipv4/tcp_minisocks.c
··· 312 312 return; 313 313 if (!static_key_fast_inc_not_disabled(&tcp_md5_needed.key.key)) 314 314 goto out_free; 315 - tcp_md5_add_sigpool(); 316 315 } 317 316 return; 318 317 out_free: ··· 405 406 if (twsk->tw_md5_key) { 406 407 kfree(twsk->tw_md5_key); 407 408 static_branch_slow_dec_deferred(&tcp_md5_needed); 408 - tcp_md5_release_sigpool(); 409 409 } 410 410 } 411 411 #endif
+36 -81
net/ipv6/tcp_ipv6.c
··· 67 67 #include <linux/proc_fs.h> 68 68 #include <linux/seq_file.h> 69 69 70 - #include <crypto/hash.h> 71 - #include <linux/scatterlist.h> 70 + #include <crypto/md5.h> 72 71 73 72 #include <trace/events/tcp.h> 74 73 ··· 690 691 cmd.tcpm_key, cmd.tcpm_keylen); 691 692 } 692 693 693 - static int tcp_v6_md5_hash_headers(struct tcp_sigpool *hp, 694 - const struct in6_addr *daddr, 695 - const struct in6_addr *saddr, 696 - const struct tcphdr *th, int nbytes) 694 + static void tcp_v6_md5_hash_headers(struct md5_ctx *ctx, 695 + const struct in6_addr *daddr, 696 + const struct in6_addr *saddr, 697 + const struct tcphdr *th, int nbytes) 697 698 { 698 - struct tcp6_pseudohdr *bp; 699 - struct scatterlist sg; 700 - struct tcphdr *_th; 699 + struct { 700 + struct tcp6_pseudohdr ip; /* TCP pseudo-header (RFC2460) */ 701 + struct tcphdr tcp; 702 + } h; 701 703 702 - bp = hp->scratch; 703 - /* 1. TCP pseudo-header (RFC2460) */ 704 - bp->saddr = *saddr; 705 - bp->daddr = *daddr; 706 - bp->protocol = cpu_to_be32(IPPROTO_TCP); 707 - bp->len = cpu_to_be32(nbytes); 708 - 709 - _th = (struct tcphdr *)(bp + 1); 710 - memcpy(_th, th, sizeof(*th)); 711 - _th->check = 0; 712 - 713 - sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th)); 714 - ahash_request_set_crypt(hp->req, &sg, NULL, 715 - sizeof(*bp) + sizeof(*th)); 716 - return crypto_ahash_update(hp->req); 704 + h.ip.saddr = *saddr; 705 + h.ip.daddr = *daddr; 706 + h.ip.protocol = cpu_to_be32(IPPROTO_TCP); 707 + h.ip.len = cpu_to_be32(nbytes); 708 + h.tcp = *th; 709 + h.tcp.check = 0; 710 + md5_update(ctx, (const u8 *)&h, sizeof(h.ip) + sizeof(h.tcp)); 717 711 } 718 712 719 - static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, 720 - const struct in6_addr *daddr, struct in6_addr *saddr, 721 - const struct tcphdr *th) 713 + static noinline_for_stack void 714 + tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, 715 + const struct in6_addr *daddr, struct in6_addr *saddr, 716 + const struct tcphdr *th) 722 717 { 723 - struct tcp_sigpool hp; 718 + struct md5_ctx ctx; 724 719 725 - if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp)) 726 - goto clear_hash_nostart; 727 - 728 - if (crypto_ahash_init(hp.req)) 729 - goto clear_hash; 730 - if (tcp_v6_md5_hash_headers(&hp, daddr, saddr, th, th->doff << 2)) 731 - goto clear_hash; 732 - if (tcp_md5_hash_key(&hp, key)) 733 - goto clear_hash; 734 - ahash_request_set_crypt(hp.req, NULL, md5_hash, 0); 735 - if (crypto_ahash_final(hp.req)) 736 - goto clear_hash; 737 - 738 - tcp_sigpool_end(&hp); 739 - return 0; 740 - 741 - clear_hash: 742 - tcp_sigpool_end(&hp); 743 - clear_hash_nostart: 744 - memset(md5_hash, 0, 16); 745 - return 1; 720 + md5_init(&ctx); 721 + tcp_v6_md5_hash_headers(&ctx, daddr, saddr, th, th->doff << 2); 722 + tcp_md5_hash_key(&ctx, key); 723 + md5_final(&ctx, md5_hash); 746 724 } 747 725 748 - static int tcp_v6_md5_hash_skb(char *md5_hash, 749 - const struct tcp_md5sig_key *key, 750 - const struct sock *sk, 751 - const struct sk_buff *skb) 726 + static noinline_for_stack void 727 + tcp_v6_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key, 728 + const struct sock *sk, const struct sk_buff *skb) 752 729 { 753 730 const struct tcphdr *th = tcp_hdr(skb); 754 731 const struct in6_addr *saddr, *daddr; 755 - struct tcp_sigpool hp; 732 + struct md5_ctx ctx; 756 733 757 734 if (sk) { /* valid for establish/request sockets */ 758 735 saddr = &sk->sk_v6_rcv_saddr; ··· 739 764 daddr = &ip6h->daddr; 740 765 } 741 766 742 - if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp)) 743 - goto clear_hash_nostart; 744 - 745 - if (crypto_ahash_init(hp.req)) 746 - goto clear_hash; 747 - 748 - if (tcp_v6_md5_hash_headers(&hp, daddr, saddr, th, skb->len)) 749 - goto clear_hash; 750 - if (tcp_sigpool_hash_skb_data(&hp, skb, th->doff << 2)) 751 - goto clear_hash; 752 - if (tcp_md5_hash_key(&hp, key)) 753 - goto clear_hash; 754 - ahash_request_set_crypt(hp.req, NULL, md5_hash, 0); 755 - if (crypto_ahash_final(hp.req)) 756 - goto clear_hash; 757 - 758 - tcp_sigpool_end(&hp); 759 - return 0; 760 - 761 - clear_hash: 762 - tcp_sigpool_end(&hp); 763 - clear_hash_nostart: 764 - memset(md5_hash, 0, 16); 765 - return 1; 767 + md5_init(&ctx); 768 + tcp_v6_md5_hash_headers(&ctx, daddr, saddr, th, skb->len); 769 + tcp_md5_hash_skb_data(&ctx, skb, th->doff << 2); 770 + tcp_md5_hash_key(&ctx, key); 771 + md5_final(&ctx, md5_hash); 766 772 } 767 773 #endif 768 774 ··· 988 1032 int oif = 0; 989 1033 #ifdef CONFIG_TCP_MD5SIG 990 1034 unsigned char newhash[16]; 991 - int genhash; 992 1035 struct sock *sk1 = NULL; 993 1036 #endif 994 1037 ··· 1046 1091 goto out; 1047 1092 key.type = TCP_KEY_MD5; 1048 1093 1049 - genhash = tcp_v6_md5_hash_skb(newhash, key.md5_key, NULL, skb); 1050 - if (genhash || memcmp(md5_hash_location, newhash, 16) != 0) 1094 + tcp_v6_md5_hash_skb(newhash, key.md5_key, NULL, skb); 1095 + if (memcmp(md5_hash_location, newhash, 16) != 0) 1051 1096 goto out; 1052 1097 } 1053 1098 #endif