diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 52 | ||||
| -rw-r--r-- | net/core/filter.c | 8 | ||||
| -rw-r--r-- | net/core/flow_dissector.c | 4 | ||||
| -rw-r--r-- | net/core/secure_seq.c | 29 | ||||
| -rw-r--r-- | net/core/sock.c | 1 |
5 files changed, 83 insertions, 11 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 5c713f2239cc..3430b1ed12e5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -1917,7 +1917,8 @@ static struct xps_map *expand_xps_map(struct xps_map *map, | |||
| 1917 | return new_map; | 1917 | return new_map; |
| 1918 | } | 1918 | } |
| 1919 | 1919 | ||
| 1920 | int netif_set_xps_queue(struct net_device *dev, struct cpumask *mask, u16 index) | 1920 | int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask, |
| 1921 | u16 index) | ||
| 1921 | { | 1922 | { |
| 1922 | struct xps_dev_maps *dev_maps, *new_dev_maps = NULL; | 1923 | struct xps_dev_maps *dev_maps, *new_dev_maps = NULL; |
| 1923 | struct xps_map *map, *new_map; | 1924 | struct xps_map *map, *new_map; |
| @@ -5247,10 +5248,12 @@ static int dev_new_index(struct net *net) | |||
| 5247 | 5248 | ||
| 5248 | /* Delayed registration/unregisteration */ | 5249 | /* Delayed registration/unregisteration */ |
| 5249 | static LIST_HEAD(net_todo_list); | 5250 | static LIST_HEAD(net_todo_list); |
| 5251 | static DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq); | ||
| 5250 | 5252 | ||
| 5251 | static void net_set_todo(struct net_device *dev) | 5253 | static void net_set_todo(struct net_device *dev) |
| 5252 | { | 5254 | { |
| 5253 | list_add_tail(&dev->todo_list, &net_todo_list); | 5255 | list_add_tail(&dev->todo_list, &net_todo_list); |
| 5256 | dev_net(dev)->dev_unreg_count++; | ||
| 5254 | } | 5257 | } |
| 5255 | 5258 | ||
| 5256 | static void rollback_registered_many(struct list_head *head) | 5259 | static void rollback_registered_many(struct list_head *head) |
| @@ -5918,6 +5921,12 @@ void netdev_run_todo(void) | |||
| 5918 | if (dev->destructor) | 5921 | if (dev->destructor) |
| 5919 | dev->destructor(dev); | 5922 | dev->destructor(dev); |
| 5920 | 5923 | ||
| 5924 | /* Report a network device has been unregistered */ | ||
| 5925 | rtnl_lock(); | ||
| 5926 | dev_net(dev)->dev_unreg_count--; | ||
| 5927 | __rtnl_unlock(); | ||
| 5928 | wake_up(&netdev_unregistering_wq); | ||
| 5929 | |||
| 5921 | /* Free network device */ | 5930 | /* Free network device */ |
| 5922 | kobject_put(&dev->dev.kobj); | 5931 | kobject_put(&dev->dev.kobj); |
| 5923 | } | 5932 | } |
| @@ -6603,6 +6612,34 @@ static void __net_exit default_device_exit(struct net *net) | |||
| 6603 | rtnl_unlock(); | 6612 | rtnl_unlock(); |
| 6604 | } | 6613 | } |
| 6605 | 6614 | ||
| 6615 | static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) | ||
| 6616 | { | ||
| 6617 | /* Return with the rtnl_lock held when there are no network | ||
| 6618 | * devices unregistering in any network namespace in net_list. | ||
| 6619 | */ | ||
| 6620 | struct net *net; | ||
| 6621 | bool unregistering; | ||
| 6622 | DEFINE_WAIT(wait); | ||
| 6623 | |||
| 6624 | for (;;) { | ||
| 6625 | prepare_to_wait(&netdev_unregistering_wq, &wait, | ||
| 6626 | TASK_UNINTERRUPTIBLE); | ||
| 6627 | unregistering = false; | ||
| 6628 | rtnl_lock(); | ||
| 6629 | list_for_each_entry(net, net_list, exit_list) { | ||
| 6630 | if (net->dev_unreg_count > 0) { | ||
| 6631 | unregistering = true; | ||
| 6632 | break; | ||
| 6633 | } | ||
| 6634 | } | ||
| 6635 | if (!unregistering) | ||
| 6636 | break; | ||
| 6637 | __rtnl_unlock(); | ||
| 6638 | schedule(); | ||
| 6639 | } | ||
| 6640 | finish_wait(&netdev_unregistering_wq, &wait); | ||
| 6641 | } | ||
| 6642 | |||
| 6606 | static void __net_exit default_device_exit_batch(struct list_head *net_list) | 6643 | static void __net_exit default_device_exit_batch(struct list_head *net_list) |
| 6607 | { | 6644 | { |
| 6608 | /* At exit all network devices most be removed from a network | 6645 | /* At exit all network devices most be removed from a network |
| @@ -6614,7 +6651,18 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list) | |||
| 6614 | struct net *net; | 6651 | struct net *net; |
| 6615 | LIST_HEAD(dev_kill_list); | 6652 | LIST_HEAD(dev_kill_list); |
| 6616 | 6653 | ||
| 6617 | rtnl_lock(); | 6654 | /* To prevent network device cleanup code from dereferencing |
| 6655 | * loopback devices or network devices that have been freed | ||
| 6656 | * wait here for all pending unregistrations to complete, | ||
| 6657 | * before unregistring the loopback device and allowing the | ||
| 6658 | * network namespace be freed. | ||
| 6659 | * | ||
| 6660 | * The netdev todo list containing all network devices | ||
| 6661 | * unregistrations that happen in default_device_exit_batch | ||
| 6662 | * will run in the rtnl_unlock() at the end of | ||
| 6663 | * default_device_exit_batch. | ||
| 6664 | */ | ||
| 6665 | rtnl_lock_unregistering(net_list); | ||
| 6618 | list_for_each_entry(net, net_list, exit_list) { | 6666 | list_for_each_entry(net, net_list, exit_list) { |
| 6619 | for_each_netdev_reverse(net, dev) { | 6667 | for_each_netdev_reverse(net, dev) { |
| 6620 | if (dev->rtnl_link_ops) | 6668 | if (dev->rtnl_link_ops) |
diff --git a/net/core/filter.c b/net/core/filter.c index 6438f29ff266..01b780856db2 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
| @@ -644,7 +644,6 @@ void sk_filter_release_rcu(struct rcu_head *rcu) | |||
| 644 | struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); | 644 | struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); |
| 645 | 645 | ||
| 646 | bpf_jit_free(fp); | 646 | bpf_jit_free(fp); |
| 647 | kfree(fp); | ||
| 648 | } | 647 | } |
| 649 | EXPORT_SYMBOL(sk_filter_release_rcu); | 648 | EXPORT_SYMBOL(sk_filter_release_rcu); |
| 650 | 649 | ||
| @@ -683,7 +682,7 @@ int sk_unattached_filter_create(struct sk_filter **pfp, | |||
| 683 | if (fprog->filter == NULL) | 682 | if (fprog->filter == NULL) |
| 684 | return -EINVAL; | 683 | return -EINVAL; |
| 685 | 684 | ||
| 686 | fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL); | 685 | fp = kmalloc(sk_filter_size(fprog->len), GFP_KERNEL); |
| 687 | if (!fp) | 686 | if (!fp) |
| 688 | return -ENOMEM; | 687 | return -ENOMEM; |
| 689 | memcpy(fp->insns, fprog->filter, fsize); | 688 | memcpy(fp->insns, fprog->filter, fsize); |
| @@ -723,6 +722,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
| 723 | { | 722 | { |
| 724 | struct sk_filter *fp, *old_fp; | 723 | struct sk_filter *fp, *old_fp; |
| 725 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; | 724 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; |
| 725 | unsigned int sk_fsize = sk_filter_size(fprog->len); | ||
| 726 | int err; | 726 | int err; |
| 727 | 727 | ||
| 728 | if (sock_flag(sk, SOCK_FILTER_LOCKED)) | 728 | if (sock_flag(sk, SOCK_FILTER_LOCKED)) |
| @@ -732,11 +732,11 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
| 732 | if (fprog->filter == NULL) | 732 | if (fprog->filter == NULL) |
| 733 | return -EINVAL; | 733 | return -EINVAL; |
| 734 | 734 | ||
| 735 | fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); | 735 | fp = sock_kmalloc(sk, sk_fsize, GFP_KERNEL); |
| 736 | if (!fp) | 736 | if (!fp) |
| 737 | return -ENOMEM; | 737 | return -ENOMEM; |
| 738 | if (copy_from_user(fp->insns, fprog->filter, fsize)) { | 738 | if (copy_from_user(fp->insns, fprog->filter, fsize)) { |
| 739 | sock_kfree_s(sk, fp, fsize+sizeof(*fp)); | 739 | sock_kfree_s(sk, fp, sk_fsize); |
| 740 | return -EFAULT; | 740 | return -EFAULT; |
| 741 | } | 741 | } |
| 742 | 742 | ||
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 1929af87b260..8d7d0dd72db2 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
| @@ -154,8 +154,8 @@ ipv6: | |||
| 154 | if (poff >= 0) { | 154 | if (poff >= 0) { |
| 155 | __be32 *ports, _ports; | 155 | __be32 *ports, _ports; |
| 156 | 156 | ||
| 157 | nhoff += poff; | 157 | ports = skb_header_pointer(skb, nhoff + poff, |
| 158 | ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports); | 158 | sizeof(_ports), &_ports); |
| 159 | if (ports) | 159 | if (ports) |
| 160 | flow->ports = *ports; | 160 | flow->ports = *ports; |
| 161 | } | 161 | } |
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 6a2f13cee86a..8d9d05edd2eb 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c | |||
| @@ -10,12 +10,27 @@ | |||
| 10 | 10 | ||
| 11 | #include <net/secure_seq.h> | 11 | #include <net/secure_seq.h> |
| 12 | 12 | ||
| 13 | static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; | 13 | #if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET) |
| 14 | #define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4) | ||
| 14 | 15 | ||
| 15 | void net_secret_init(void) | 16 | static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned; |
| 17 | |||
| 18 | static void net_secret_init(void) | ||
| 16 | { | 19 | { |
| 17 | get_random_bytes(net_secret, sizeof(net_secret)); | 20 | u32 tmp; |
| 21 | int i; | ||
| 22 | |||
| 23 | if (likely(net_secret[0])) | ||
| 24 | return; | ||
| 25 | |||
| 26 | for (i = NET_SECRET_SIZE; i > 0;) { | ||
| 27 | do { | ||
| 28 | get_random_bytes(&tmp, sizeof(tmp)); | ||
| 29 | } while (!tmp); | ||
| 30 | cmpxchg(&net_secret[--i], 0, tmp); | ||
| 31 | } | ||
| 18 | } | 32 | } |
| 33 | #endif | ||
| 19 | 34 | ||
| 20 | #ifdef CONFIG_INET | 35 | #ifdef CONFIG_INET |
| 21 | static u32 seq_scale(u32 seq) | 36 | static u32 seq_scale(u32 seq) |
| @@ -42,6 +57,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, | |||
| 42 | u32 hash[MD5_DIGEST_WORDS]; | 57 | u32 hash[MD5_DIGEST_WORDS]; |
| 43 | u32 i; | 58 | u32 i; |
| 44 | 59 | ||
| 60 | net_secret_init(); | ||
| 45 | memcpy(hash, saddr, 16); | 61 | memcpy(hash, saddr, 16); |
| 46 | for (i = 0; i < 4; i++) | 62 | for (i = 0; i < 4; i++) |
| 47 | secret[i] = net_secret[i] + (__force u32)daddr[i]; | 63 | secret[i] = net_secret[i] + (__force u32)daddr[i]; |
| @@ -63,6 +79,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, | |||
| 63 | u32 hash[MD5_DIGEST_WORDS]; | 79 | u32 hash[MD5_DIGEST_WORDS]; |
| 64 | u32 i; | 80 | u32 i; |
| 65 | 81 | ||
| 82 | net_secret_init(); | ||
| 66 | memcpy(hash, saddr, 16); | 83 | memcpy(hash, saddr, 16); |
| 67 | for (i = 0; i < 4; i++) | 84 | for (i = 0; i < 4; i++) |
| 68 | secret[i] = net_secret[i] + (__force u32) daddr[i]; | 85 | secret[i] = net_secret[i] + (__force u32) daddr[i]; |
| @@ -82,6 +99,7 @@ __u32 secure_ip_id(__be32 daddr) | |||
| 82 | { | 99 | { |
| 83 | u32 hash[MD5_DIGEST_WORDS]; | 100 | u32 hash[MD5_DIGEST_WORDS]; |
| 84 | 101 | ||
| 102 | net_secret_init(); | ||
| 85 | hash[0] = (__force __u32) daddr; | 103 | hash[0] = (__force __u32) daddr; |
| 86 | hash[1] = net_secret[13]; | 104 | hash[1] = net_secret[13]; |
| 87 | hash[2] = net_secret[14]; | 105 | hash[2] = net_secret[14]; |
| @@ -96,6 +114,7 @@ __u32 secure_ipv6_id(const __be32 daddr[4]) | |||
| 96 | { | 114 | { |
| 97 | __u32 hash[4]; | 115 | __u32 hash[4]; |
| 98 | 116 | ||
| 117 | net_secret_init(); | ||
| 99 | memcpy(hash, daddr, 16); | 118 | memcpy(hash, daddr, 16); |
| 100 | md5_transform(hash, net_secret); | 119 | md5_transform(hash, net_secret); |
| 101 | 120 | ||
| @@ -107,6 +126,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, | |||
| 107 | { | 126 | { |
| 108 | u32 hash[MD5_DIGEST_WORDS]; | 127 | u32 hash[MD5_DIGEST_WORDS]; |
| 109 | 128 | ||
| 129 | net_secret_init(); | ||
| 110 | hash[0] = (__force u32)saddr; | 130 | hash[0] = (__force u32)saddr; |
| 111 | hash[1] = (__force u32)daddr; | 131 | hash[1] = (__force u32)daddr; |
| 112 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; | 132 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; |
| @@ -121,6 +141,7 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) | |||
| 121 | { | 141 | { |
| 122 | u32 hash[MD5_DIGEST_WORDS]; | 142 | u32 hash[MD5_DIGEST_WORDS]; |
| 123 | 143 | ||
| 144 | net_secret_init(); | ||
| 124 | hash[0] = (__force u32)saddr; | 145 | hash[0] = (__force u32)saddr; |
| 125 | hash[1] = (__force u32)daddr; | 146 | hash[1] = (__force u32)daddr; |
| 126 | hash[2] = (__force u32)dport ^ net_secret[14]; | 147 | hash[2] = (__force u32)dport ^ net_secret[14]; |
| @@ -140,6 +161,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, | |||
| 140 | u32 hash[MD5_DIGEST_WORDS]; | 161 | u32 hash[MD5_DIGEST_WORDS]; |
| 141 | u64 seq; | 162 | u64 seq; |
| 142 | 163 | ||
| 164 | net_secret_init(); | ||
| 143 | hash[0] = (__force u32)saddr; | 165 | hash[0] = (__force u32)saddr; |
| 144 | hash[1] = (__force u32)daddr; | 166 | hash[1] = (__force u32)daddr; |
| 145 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; | 167 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; |
| @@ -164,6 +186,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, | |||
| 164 | u64 seq; | 186 | u64 seq; |
| 165 | u32 i; | 187 | u32 i; |
| 166 | 188 | ||
| 189 | net_secret_init(); | ||
| 167 | memcpy(hash, saddr, 16); | 190 | memcpy(hash, saddr, 16); |
| 168 | for (i = 0; i < 4; i++) | 191 | for (i = 0; i < 4; i++) |
| 169 | secret[i] = net_secret[i] + daddr[i]; | 192 | secret[i] = net_secret[i] + daddr[i]; |
diff --git a/net/core/sock.c b/net/core/sock.c index 5b6beba494a3..0b39e7ae4383 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -2319,6 +2319,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) | |||
| 2319 | sk->sk_ll_usec = sysctl_net_busy_read; | 2319 | sk->sk_ll_usec = sysctl_net_busy_read; |
| 2320 | #endif | 2320 | #endif |
| 2321 | 2321 | ||
| 2322 | sk->sk_pacing_rate = ~0U; | ||
| 2322 | /* | 2323 | /* |
| 2323 | * Before updating sk_refcnt, we must commit prior changes to memory | 2324 | * Before updating sk_refcnt, we must commit prior changes to memory |
| 2324 | * (Documentation/RCU/rculist_nulls.txt for details) | 2325 | * (Documentation/RCU/rculist_nulls.txt for details) |
