diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 49 | ||||
-rw-r--r-- | net/core/flow_dissector.c | 4 | ||||
-rw-r--r-- | net/core/secure_seq.c | 27 |
3 files changed, 74 insertions, 6 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 5c713f2239cc..65f829cfd928 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -5247,10 +5247,12 @@ static int dev_new_index(struct net *net) | |||
5247 | 5247 | ||
5248 | /* Delayed registration/unregisteration */ | 5248 | /* Delayed registration/unregisteration */ |
5249 | static LIST_HEAD(net_todo_list); | 5249 | static LIST_HEAD(net_todo_list); |
5250 | static DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq); | ||
5250 | 5251 | ||
5251 | static void net_set_todo(struct net_device *dev) | 5252 | static void net_set_todo(struct net_device *dev) |
5252 | { | 5253 | { |
5253 | list_add_tail(&dev->todo_list, &net_todo_list); | 5254 | list_add_tail(&dev->todo_list, &net_todo_list); |
5255 | dev_net(dev)->dev_unreg_count++; | ||
5254 | } | 5256 | } |
5255 | 5257 | ||
5256 | static void rollback_registered_many(struct list_head *head) | 5258 | static void rollback_registered_many(struct list_head *head) |
@@ -5918,6 +5920,12 @@ void netdev_run_todo(void) | |||
5918 | if (dev->destructor) | 5920 | if (dev->destructor) |
5919 | dev->destructor(dev); | 5921 | dev->destructor(dev); |
5920 | 5922 | ||
5923 | /* Report a network device has been unregistered */ | ||
5924 | rtnl_lock(); | ||
5925 | dev_net(dev)->dev_unreg_count--; | ||
5926 | __rtnl_unlock(); | ||
5927 | wake_up(&netdev_unregistering_wq); | ||
5928 | |||
5921 | /* Free network device */ | 5929 | /* Free network device */ |
5922 | kobject_put(&dev->dev.kobj); | 5930 | kobject_put(&dev->dev.kobj); |
5923 | } | 5931 | } |
@@ -6603,6 +6611,34 @@ static void __net_exit default_device_exit(struct net *net) | |||
6603 | rtnl_unlock(); | 6611 | rtnl_unlock(); |
6604 | } | 6612 | } |
6605 | 6613 | ||
6614 | static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) | ||
6615 | { | ||
6616 | /* Return with the rtnl_lock held when there are no network | ||
6617 | * devices unregistering in any network namespace in net_list. | ||
6618 | */ | ||
6619 | struct net *net; | ||
6620 | bool unregistering; | ||
6621 | DEFINE_WAIT(wait); | ||
6622 | |||
6623 | for (;;) { | ||
6624 | prepare_to_wait(&netdev_unregistering_wq, &wait, | ||
6625 | TASK_UNINTERRUPTIBLE); | ||
6626 | unregistering = false; | ||
6627 | rtnl_lock(); | ||
6628 | list_for_each_entry(net, net_list, exit_list) { | ||
6629 | if (net->dev_unreg_count > 0) { | ||
6630 | unregistering = true; | ||
6631 | break; | ||
6632 | } | ||
6633 | } | ||
6634 | if (!unregistering) | ||
6635 | break; | ||
6636 | __rtnl_unlock(); | ||
6637 | schedule(); | ||
6638 | } | ||
6639 | finish_wait(&netdev_unregistering_wq, &wait); | ||
6640 | } | ||
6641 | |||
6606 | static void __net_exit default_device_exit_batch(struct list_head *net_list) | 6642 | static void __net_exit default_device_exit_batch(struct list_head *net_list) |
6607 | { | 6643 | { |
6608 | /* At exit all network devices most be removed from a network | 6644 | /* At exit all network devices most be removed from a network |
@@ -6614,7 +6650,18 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list) | |||
6614 | struct net *net; | 6650 | struct net *net; |
6615 | LIST_HEAD(dev_kill_list); | 6651 | LIST_HEAD(dev_kill_list); |
6616 | 6652 | ||
6617 | rtnl_lock(); | 6653 | /* To prevent network device cleanup code from dereferencing |
6654 | * loopback devices or network devices that have been freed | ||
6655 | * wait here for all pending unregistrations to complete, | ||
6656 | * before unregistring the loopback device and allowing the | ||
6657 | * network namespace be freed. | ||
6658 | * | ||
6659 | * The netdev todo list containing all network devices | ||
6660 | * unregistrations that happen in default_device_exit_batch | ||
6661 | * will run in the rtnl_unlock() at the end of | ||
6662 | * default_device_exit_batch. | ||
6663 | */ | ||
6664 | rtnl_lock_unregistering(net_list); | ||
6618 | list_for_each_entry(net, net_list, exit_list) { | 6665 | list_for_each_entry(net, net_list, exit_list) { |
6619 | for_each_netdev_reverse(net, dev) { | 6666 | for_each_netdev_reverse(net, dev) { |
6620 | if (dev->rtnl_link_ops) | 6667 | if (dev->rtnl_link_ops) |
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..3f1ec1586ae1 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c | |||
@@ -10,11 +10,24 @@ | |||
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 | #define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4) |
14 | 14 | ||
15 | void net_secret_init(void) | 15 | static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned; |
16 | |||
17 | static void net_secret_init(void) | ||
16 | { | 18 | { |
17 | get_random_bytes(net_secret, sizeof(net_secret)); | 19 | u32 tmp; |
20 | int i; | ||
21 | |||
22 | if (likely(net_secret[0])) | ||
23 | return; | ||
24 | |||
25 | for (i = NET_SECRET_SIZE; i > 0;) { | ||
26 | do { | ||
27 | get_random_bytes(&tmp, sizeof(tmp)); | ||
28 | } while (!tmp); | ||
29 | cmpxchg(&net_secret[--i], 0, tmp); | ||
30 | } | ||
18 | } | 31 | } |
19 | 32 | ||
20 | #ifdef CONFIG_INET | 33 | #ifdef CONFIG_INET |
@@ -42,6 +55,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, | |||
42 | u32 hash[MD5_DIGEST_WORDS]; | 55 | u32 hash[MD5_DIGEST_WORDS]; |
43 | u32 i; | 56 | u32 i; |
44 | 57 | ||
58 | net_secret_init(); | ||
45 | memcpy(hash, saddr, 16); | 59 | memcpy(hash, saddr, 16); |
46 | for (i = 0; i < 4; i++) | 60 | for (i = 0; i < 4; i++) |
47 | secret[i] = net_secret[i] + (__force u32)daddr[i]; | 61 | secret[i] = net_secret[i] + (__force u32)daddr[i]; |
@@ -63,6 +77,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, | |||
63 | u32 hash[MD5_DIGEST_WORDS]; | 77 | u32 hash[MD5_DIGEST_WORDS]; |
64 | u32 i; | 78 | u32 i; |
65 | 79 | ||
80 | net_secret_init(); | ||
66 | memcpy(hash, saddr, 16); | 81 | memcpy(hash, saddr, 16); |
67 | for (i = 0; i < 4; i++) | 82 | for (i = 0; i < 4; i++) |
68 | secret[i] = net_secret[i] + (__force u32) daddr[i]; | 83 | secret[i] = net_secret[i] + (__force u32) daddr[i]; |
@@ -82,6 +97,7 @@ __u32 secure_ip_id(__be32 daddr) | |||
82 | { | 97 | { |
83 | u32 hash[MD5_DIGEST_WORDS]; | 98 | u32 hash[MD5_DIGEST_WORDS]; |
84 | 99 | ||
100 | net_secret_init(); | ||
85 | hash[0] = (__force __u32) daddr; | 101 | hash[0] = (__force __u32) daddr; |
86 | hash[1] = net_secret[13]; | 102 | hash[1] = net_secret[13]; |
87 | hash[2] = net_secret[14]; | 103 | hash[2] = net_secret[14]; |
@@ -96,6 +112,7 @@ __u32 secure_ipv6_id(const __be32 daddr[4]) | |||
96 | { | 112 | { |
97 | __u32 hash[4]; | 113 | __u32 hash[4]; |
98 | 114 | ||
115 | net_secret_init(); | ||
99 | memcpy(hash, daddr, 16); | 116 | memcpy(hash, daddr, 16); |
100 | md5_transform(hash, net_secret); | 117 | md5_transform(hash, net_secret); |
101 | 118 | ||
@@ -107,6 +124,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, | |||
107 | { | 124 | { |
108 | u32 hash[MD5_DIGEST_WORDS]; | 125 | u32 hash[MD5_DIGEST_WORDS]; |
109 | 126 | ||
127 | net_secret_init(); | ||
110 | hash[0] = (__force u32)saddr; | 128 | hash[0] = (__force u32)saddr; |
111 | hash[1] = (__force u32)daddr; | 129 | hash[1] = (__force u32)daddr; |
112 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; | 130 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; |
@@ -121,6 +139,7 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) | |||
121 | { | 139 | { |
122 | u32 hash[MD5_DIGEST_WORDS]; | 140 | u32 hash[MD5_DIGEST_WORDS]; |
123 | 141 | ||
142 | net_secret_init(); | ||
124 | hash[0] = (__force u32)saddr; | 143 | hash[0] = (__force u32)saddr; |
125 | hash[1] = (__force u32)daddr; | 144 | hash[1] = (__force u32)daddr; |
126 | hash[2] = (__force u32)dport ^ net_secret[14]; | 145 | hash[2] = (__force u32)dport ^ net_secret[14]; |
@@ -140,6 +159,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, | |||
140 | u32 hash[MD5_DIGEST_WORDS]; | 159 | u32 hash[MD5_DIGEST_WORDS]; |
141 | u64 seq; | 160 | u64 seq; |
142 | 161 | ||
162 | net_secret_init(); | ||
143 | hash[0] = (__force u32)saddr; | 163 | hash[0] = (__force u32)saddr; |
144 | hash[1] = (__force u32)daddr; | 164 | hash[1] = (__force u32)daddr; |
145 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; | 165 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; |
@@ -164,6 +184,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, | |||
164 | u64 seq; | 184 | u64 seq; |
165 | u32 i; | 185 | u32 i; |
166 | 186 | ||
187 | net_secret_init(); | ||
167 | memcpy(hash, saddr, 16); | 188 | memcpy(hash, saddr, 16); |
168 | for (i = 0; i < 4; i++) | 189 | for (i = 0; i < 4; i++) |
169 | secret[i] = net_secret[i] + daddr[i]; | 190 | secret[i] = net_secret[i] + daddr[i]; |