diff options
author | David S. Miller <davem@davemloft.net> | 2011-07-21 15:39:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-07-21 15:39:35 -0400 |
commit | f5caadbb3d8fc0b71533e880c684b2230bdb76ac (patch) | |
tree | 7a23a2b44f6e043d9cb6ad4245b78da4bd2e14b0 /net/netfilter | |
parent | 0ca87f05ba8bdc6791c14878464efc901ad71e99 (diff) | |
parent | 0f598f0b4c3b2259366cfa8adc01bd8e714c82d0 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ip.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipport.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportip.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportnet.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_net.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netiface.c | 40 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netport.c | 6 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 40 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 170 | ||||
-rw-r--r-- | net/netfilter/xt_AUDIT.c | 5 |
10 files changed, 215 insertions, 76 deletions
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index fa80bb9b9c81..f2d576e6b769 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c | |||
@@ -53,7 +53,8 @@ struct hash_ip4_telem { | |||
53 | 53 | ||
54 | static inline bool | 54 | static inline bool |
55 | hash_ip4_data_equal(const struct hash_ip4_elem *ip1, | 55 | hash_ip4_data_equal(const struct hash_ip4_elem *ip1, |
56 | const struct hash_ip4_elem *ip2) | 56 | const struct hash_ip4_elem *ip2, |
57 | u32 *multi) | ||
57 | { | 58 | { |
58 | return ip1->ip == ip2->ip; | 59 | return ip1->ip == ip2->ip; |
59 | } | 60 | } |
@@ -225,7 +226,8 @@ struct hash_ip6_telem { | |||
225 | 226 | ||
226 | static inline bool | 227 | static inline bool |
227 | hash_ip6_data_equal(const struct hash_ip6_elem *ip1, | 228 | hash_ip6_data_equal(const struct hash_ip6_elem *ip1, |
228 | const struct hash_ip6_elem *ip2) | 229 | const struct hash_ip6_elem *ip2, |
230 | u32 *multi) | ||
229 | { | 231 | { |
230 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0; | 232 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0; |
231 | } | 233 | } |
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index bbf51b67b170..6ee10f5d59bd 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c | |||
@@ -60,7 +60,8 @@ struct hash_ipport4_telem { | |||
60 | 60 | ||
61 | static inline bool | 61 | static inline bool |
62 | hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1, | 62 | hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1, |
63 | const struct hash_ipport4_elem *ip2) | 63 | const struct hash_ipport4_elem *ip2, |
64 | u32 *multi) | ||
64 | { | 65 | { |
65 | return ip1->ip == ip2->ip && | 66 | return ip1->ip == ip2->ip && |
66 | ip1->port == ip2->port && | 67 | ip1->port == ip2->port && |
@@ -276,7 +277,8 @@ struct hash_ipport6_telem { | |||
276 | 277 | ||
277 | static inline bool | 278 | static inline bool |
278 | hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1, | 279 | hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1, |
279 | const struct hash_ipport6_elem *ip2) | 280 | const struct hash_ipport6_elem *ip2, |
281 | u32 *multi) | ||
280 | { | 282 | { |
281 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 283 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
282 | ip1->port == ip2->port && | 284 | ip1->port == ip2->port && |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 96525f529a54..fb90e344e907 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c | |||
@@ -62,7 +62,8 @@ struct hash_ipportip4_telem { | |||
62 | 62 | ||
63 | static inline bool | 63 | static inline bool |
64 | hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, | 64 | hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, |
65 | const struct hash_ipportip4_elem *ip2) | 65 | const struct hash_ipportip4_elem *ip2, |
66 | u32 *multi) | ||
66 | { | 67 | { |
67 | return ip1->ip == ip2->ip && | 68 | return ip1->ip == ip2->ip && |
68 | ip1->ip2 == ip2->ip2 && | 69 | ip1->ip2 == ip2->ip2 && |
@@ -286,7 +287,8 @@ struct hash_ipportip6_telem { | |||
286 | 287 | ||
287 | static inline bool | 288 | static inline bool |
288 | hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, | 289 | hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, |
289 | const struct hash_ipportip6_elem *ip2) | 290 | const struct hash_ipportip6_elem *ip2, |
291 | u32 *multi) | ||
290 | { | 292 | { |
291 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 293 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
292 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && | 294 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index d2d6ab89f087..deb3e3dfa5fc 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
@@ -62,7 +62,8 @@ struct hash_ipportnet4_telem { | |||
62 | 62 | ||
63 | static inline bool | 63 | static inline bool |
64 | hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1, | 64 | hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1, |
65 | const struct hash_ipportnet4_elem *ip2) | 65 | const struct hash_ipportnet4_elem *ip2, |
66 | u32 *multi) | ||
66 | { | 67 | { |
67 | return ip1->ip == ip2->ip && | 68 | return ip1->ip == ip2->ip && |
68 | ip1->ip2 == ip2->ip2 && | 69 | ip1->ip2 == ip2->ip2 && |
@@ -335,7 +336,8 @@ struct hash_ipportnet6_telem { | |||
335 | 336 | ||
336 | static inline bool | 337 | static inline bool |
337 | hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1, | 338 | hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1, |
338 | const struct hash_ipportnet6_elem *ip2) | 339 | const struct hash_ipportnet6_elem *ip2, |
340 | u32 *multi) | ||
339 | { | 341 | { |
340 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 342 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
341 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && | 343 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && |
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 2d4b1f48e8c9..60d016541c58 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
@@ -58,7 +58,8 @@ struct hash_net4_telem { | |||
58 | 58 | ||
59 | static inline bool | 59 | static inline bool |
60 | hash_net4_data_equal(const struct hash_net4_elem *ip1, | 60 | hash_net4_data_equal(const struct hash_net4_elem *ip1, |
61 | const struct hash_net4_elem *ip2) | 61 | const struct hash_net4_elem *ip2, |
62 | u32 *multi) | ||
62 | { | 63 | { |
63 | return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; | 64 | return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; |
64 | } | 65 | } |
@@ -249,7 +250,8 @@ struct hash_net6_telem { | |||
249 | 250 | ||
250 | static inline bool | 251 | static inline bool |
251 | hash_net6_data_equal(const struct hash_net6_elem *ip1, | 252 | hash_net6_data_equal(const struct hash_net6_elem *ip1, |
252 | const struct hash_net6_elem *ip2) | 253 | const struct hash_net6_elem *ip2, |
254 | u32 *multi) | ||
253 | { | 255 | { |
254 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 256 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
255 | ip1->cidr == ip2->cidr; | 257 | ip1->cidr == ip2->cidr; |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index 3d6c53b6211a..e13095deb50d 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
@@ -99,7 +99,7 @@ iface_test(struct rb_root *root, const char **iface) | |||
99 | 99 | ||
100 | while (n) { | 100 | while (n) { |
101 | const char *d = iface_data(n); | 101 | const char *d = iface_data(n); |
102 | int res = ifname_compare(*iface, d); | 102 | long res = ifname_compare(*iface, d); |
103 | 103 | ||
104 | if (res < 0) | 104 | if (res < 0) |
105 | n = n->rb_left; | 105 | n = n->rb_left; |
@@ -121,7 +121,7 @@ iface_add(struct rb_root *root, const char **iface) | |||
121 | 121 | ||
122 | while (*n) { | 122 | while (*n) { |
123 | char *ifname = iface_data(*n); | 123 | char *ifname = iface_data(*n); |
124 | int res = ifname_compare(*iface, ifname); | 124 | long res = ifname_compare(*iface, ifname); |
125 | 125 | ||
126 | p = *n; | 126 | p = *n; |
127 | if (res < 0) | 127 | if (res < 0) |
@@ -159,31 +159,42 @@ hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b); | |||
159 | 159 | ||
160 | /* The type variant functions: IPv4 */ | 160 | /* The type variant functions: IPv4 */ |
161 | 161 | ||
162 | struct hash_netiface4_elem_hashed { | ||
163 | __be32 ip; | ||
164 | u8 physdev; | ||
165 | u8 cidr; | ||
166 | u16 padding; | ||
167 | }; | ||
168 | |||
169 | #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) | ||
170 | |||
162 | /* Member elements without timeout */ | 171 | /* Member elements without timeout */ |
163 | struct hash_netiface4_elem { | 172 | struct hash_netiface4_elem { |
164 | __be32 ip; | 173 | __be32 ip; |
165 | const char *iface; | ||
166 | u8 physdev; | 174 | u8 physdev; |
167 | u8 cidr; | 175 | u8 cidr; |
168 | u16 padding; | 176 | u16 padding; |
177 | const char *iface; | ||
169 | }; | 178 | }; |
170 | 179 | ||
171 | /* Member elements with timeout support */ | 180 | /* Member elements with timeout support */ |
172 | struct hash_netiface4_telem { | 181 | struct hash_netiface4_telem { |
173 | __be32 ip; | 182 | __be32 ip; |
174 | const char *iface; | ||
175 | u8 physdev; | 183 | u8 physdev; |
176 | u8 cidr; | 184 | u8 cidr; |
177 | u16 padding; | 185 | u16 padding; |
186 | const char *iface; | ||
178 | unsigned long timeout; | 187 | unsigned long timeout; |
179 | }; | 188 | }; |
180 | 189 | ||
181 | static inline bool | 190 | static inline bool |
182 | hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1, | 191 | hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1, |
183 | const struct hash_netiface4_elem *ip2) | 192 | const struct hash_netiface4_elem *ip2, |
193 | u32 *multi) | ||
184 | { | 194 | { |
185 | return ip1->ip == ip2->ip && | 195 | return ip1->ip == ip2->ip && |
186 | ip1->cidr == ip2->cidr && | 196 | ip1->cidr == ip2->cidr && |
197 | (++*multi) && | ||
187 | ip1->physdev == ip2->physdev && | 198 | ip1->physdev == ip2->physdev && |
188 | ip1->iface == ip2->iface; | 199 | ip1->iface == ip2->iface; |
189 | } | 200 | } |
@@ -257,6 +268,7 @@ nla_put_failure: | |||
257 | 268 | ||
258 | #define IP_SET_HASH_WITH_NETS | 269 | #define IP_SET_HASH_WITH_NETS |
259 | #define IP_SET_HASH_WITH_RBTREE | 270 | #define IP_SET_HASH_WITH_RBTREE |
271 | #define IP_SET_HASH_WITH_MULTI | ||
260 | 272 | ||
261 | #define PF 4 | 273 | #define PF 4 |
262 | #define HOST_MASK 32 | 274 | #define HOST_MASK 32 |
@@ -424,29 +436,40 @@ hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b) | |||
424 | 436 | ||
425 | /* The type variant functions: IPv6 */ | 437 | /* The type variant functions: IPv6 */ |
426 | 438 | ||
439 | struct hash_netiface6_elem_hashed { | ||
440 | union nf_inet_addr ip; | ||
441 | u8 physdev; | ||
442 | u8 cidr; | ||
443 | u16 padding; | ||
444 | }; | ||
445 | |||
446 | #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed) | ||
447 | |||
427 | struct hash_netiface6_elem { | 448 | struct hash_netiface6_elem { |
428 | union nf_inet_addr ip; | 449 | union nf_inet_addr ip; |
429 | const char *iface; | ||
430 | u8 physdev; | 450 | u8 physdev; |
431 | u8 cidr; | 451 | u8 cidr; |
432 | u16 padding; | 452 | u16 padding; |
453 | const char *iface; | ||
433 | }; | 454 | }; |
434 | 455 | ||
435 | struct hash_netiface6_telem { | 456 | struct hash_netiface6_telem { |
436 | union nf_inet_addr ip; | 457 | union nf_inet_addr ip; |
437 | const char *iface; | ||
438 | u8 physdev; | 458 | u8 physdev; |
439 | u8 cidr; | 459 | u8 cidr; |
440 | u16 padding; | 460 | u16 padding; |
461 | const char *iface; | ||
441 | unsigned long timeout; | 462 | unsigned long timeout; |
442 | }; | 463 | }; |
443 | 464 | ||
444 | static inline bool | 465 | static inline bool |
445 | hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1, | 466 | hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1, |
446 | const struct hash_netiface6_elem *ip2) | 467 | const struct hash_netiface6_elem *ip2, |
468 | u32 *multi) | ||
447 | { | 469 | { |
448 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 470 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
449 | ip1->cidr == ip2->cidr && | 471 | ip1->cidr == ip2->cidr && |
472 | (++*multi) && | ||
450 | ip1->physdev == ip2->physdev && | 473 | ip1->physdev == ip2->physdev && |
451 | ip1->iface == ip2->iface; | 474 | ip1->iface == ip2->iface; |
452 | } | 475 | } |
@@ -681,6 +704,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
681 | h->maxelem = maxelem; | 704 | h->maxelem = maxelem; |
682 | get_random_bytes(&h->initval, sizeof(h->initval)); | 705 | get_random_bytes(&h->initval, sizeof(h->initval)); |
683 | h->timeout = IPSET_NO_TIMEOUT; | 706 | h->timeout = IPSET_NO_TIMEOUT; |
707 | h->ahash_max = AHASH_MAX_SIZE; | ||
684 | 708 | ||
685 | hbits = htable_bits(hashsize); | 709 | hbits = htable_bits(hashsize); |
686 | h->table = ip_set_alloc( | 710 | h->table = ip_set_alloc( |
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index fe203d12f56b..8f9de7207ec9 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
@@ -59,7 +59,8 @@ struct hash_netport4_telem { | |||
59 | 59 | ||
60 | static inline bool | 60 | static inline bool |
61 | hash_netport4_data_equal(const struct hash_netport4_elem *ip1, | 61 | hash_netport4_data_equal(const struct hash_netport4_elem *ip1, |
62 | const struct hash_netport4_elem *ip2) | 62 | const struct hash_netport4_elem *ip2, |
63 | u32 *multi) | ||
63 | { | 64 | { |
64 | return ip1->ip == ip2->ip && | 65 | return ip1->ip == ip2->ip && |
65 | ip1->port == ip2->port && | 66 | ip1->port == ip2->port && |
@@ -300,7 +301,8 @@ struct hash_netport6_telem { | |||
300 | 301 | ||
301 | static inline bool | 302 | static inline bool |
302 | hash_netport6_data_equal(const struct hash_netport6_elem *ip1, | 303 | hash_netport6_data_equal(const struct hash_netport6_elem *ip1, |
303 | const struct hash_netport6_elem *ip2) | 304 | const struct hash_netport6_elem *ip2, |
305 | u32 *multi) | ||
304 | { | 306 | { |
305 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 307 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
306 | ip1->port == ip2->port && | 308 | ip1->port == ip2->port && |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b4a4532823e8..1905976b5135 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -37,7 +37,7 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); | |||
37 | 37 | ||
38 | static char __initdata nfversion[] = "0.30"; | 38 | static char __initdata nfversion[] = "0.30"; |
39 | 39 | ||
40 | static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; | 40 | static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT]; |
41 | static DEFINE_MUTEX(nfnl_mutex); | 41 | static DEFINE_MUTEX(nfnl_mutex); |
42 | 42 | ||
43 | void nfnl_lock(void) | 43 | void nfnl_lock(void) |
@@ -59,7 +59,7 @@ int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n) | |||
59 | nfnl_unlock(); | 59 | nfnl_unlock(); |
60 | return -EBUSY; | 60 | return -EBUSY; |
61 | } | 61 | } |
62 | subsys_table[n->subsys_id] = n; | 62 | rcu_assign_pointer(subsys_table[n->subsys_id], n); |
63 | nfnl_unlock(); | 63 | nfnl_unlock(); |
64 | 64 | ||
65 | return 0; | 65 | return 0; |
@@ -71,7 +71,7 @@ int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n) | |||
71 | nfnl_lock(); | 71 | nfnl_lock(); |
72 | subsys_table[n->subsys_id] = NULL; | 72 | subsys_table[n->subsys_id] = NULL; |
73 | nfnl_unlock(); | 73 | nfnl_unlock(); |
74 | 74 | synchronize_rcu(); | |
75 | return 0; | 75 | return 0; |
76 | } | 76 | } |
77 | EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); | 77 | EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); |
@@ -83,7 +83,7 @@ static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t t | |||
83 | if (subsys_id >= NFNL_SUBSYS_COUNT) | 83 | if (subsys_id >= NFNL_SUBSYS_COUNT) |
84 | return NULL; | 84 | return NULL; |
85 | 85 | ||
86 | return subsys_table[subsys_id]; | 86 | return rcu_dereference(subsys_table[subsys_id]); |
87 | } | 87 | } |
88 | 88 | ||
89 | static inline const struct nfnl_callback * | 89 | static inline const struct nfnl_callback * |
@@ -139,21 +139,27 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
139 | 139 | ||
140 | type = nlh->nlmsg_type; | 140 | type = nlh->nlmsg_type; |
141 | replay: | 141 | replay: |
142 | rcu_read_lock(); | ||
142 | ss = nfnetlink_get_subsys(type); | 143 | ss = nfnetlink_get_subsys(type); |
143 | if (!ss) { | 144 | if (!ss) { |
144 | #ifdef CONFIG_MODULES | 145 | #ifdef CONFIG_MODULES |
145 | nfnl_unlock(); | 146 | rcu_read_unlock(); |
146 | request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); | 147 | request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); |
147 | nfnl_lock(); | 148 | rcu_read_lock(); |
148 | ss = nfnetlink_get_subsys(type); | 149 | ss = nfnetlink_get_subsys(type); |
149 | if (!ss) | 150 | if (!ss) |
150 | #endif | 151 | #endif |
152 | { | ||
153 | rcu_read_unlock(); | ||
151 | return -EINVAL; | 154 | return -EINVAL; |
155 | } | ||
152 | } | 156 | } |
153 | 157 | ||
154 | nc = nfnetlink_find_client(type, ss); | 158 | nc = nfnetlink_find_client(type, ss); |
155 | if (!nc) | 159 | if (!nc) { |
160 | rcu_read_unlock(); | ||
156 | return -EINVAL; | 161 | return -EINVAL; |
162 | } | ||
157 | 163 | ||
158 | { | 164 | { |
159 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); | 165 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); |
@@ -167,7 +173,23 @@ replay: | |||
167 | if (err < 0) | 173 | if (err < 0) |
168 | return err; | 174 | return err; |
169 | 175 | ||
170 | err = nc->call(net->nfnl, skb, nlh, (const struct nlattr **)cda); | 176 | if (nc->call_rcu) { |
177 | err = nc->call_rcu(net->nfnl, skb, nlh, | ||
178 | (const struct nlattr **)cda); | ||
179 | rcu_read_unlock(); | ||
180 | } else { | ||
181 | rcu_read_unlock(); | ||
182 | nfnl_lock(); | ||
183 | if (rcu_dereference_protected( | ||
184 | subsys_table[NFNL_SUBSYS_ID(type)], | ||
185 | lockdep_is_held(&nfnl_mutex)) != ss || | ||
186 | nfnetlink_find_client(type, ss) != nc) | ||
187 | err = -EAGAIN; | ||
188 | else | ||
189 | err = nc->call(net->nfnl, skb, nlh, | ||
190 | (const struct nlattr **)cda); | ||
191 | nfnl_unlock(); | ||
192 | } | ||
171 | if (err == -EAGAIN) | 193 | if (err == -EAGAIN) |
172 | goto replay; | 194 | goto replay; |
173 | return err; | 195 | return err; |
@@ -176,9 +198,7 @@ replay: | |||
176 | 198 | ||
177 | static void nfnetlink_rcv(struct sk_buff *skb) | 199 | static void nfnetlink_rcv(struct sk_buff *skb) |
178 | { | 200 | { |
179 | nfnl_lock(); | ||
180 | netlink_rcv_skb(skb, &nfnetlink_rcv_msg); | 201 | netlink_rcv_skb(skb, &nfnetlink_rcv_msg); |
181 | nfnl_unlock(); | ||
182 | } | 202 | } |
183 | 203 | ||
184 | static int __net_init nfnetlink_net_init(struct net *net) | 204 | static int __net_init nfnetlink_net_init(struct net *net) |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index fdd2fafe0a14..49132bddd73e 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -58,7 +58,7 @@ struct nfqnl_instance { | |||
58 | */ | 58 | */ |
59 | spinlock_t lock; | 59 | spinlock_t lock; |
60 | unsigned int queue_total; | 60 | unsigned int queue_total; |
61 | atomic_t id_sequence; /* 'sequence' of pkt ids */ | 61 | unsigned int id_sequence; /* 'sequence' of pkt ids */ |
62 | struct list_head queue_list; /* packets in queue */ | 62 | struct list_head queue_list; /* packets in queue */ |
63 | }; | 63 | }; |
64 | 64 | ||
@@ -171,6 +171,13 @@ __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) | |||
171 | queue->queue_total++; | 171 | queue->queue_total++; |
172 | } | 172 | } |
173 | 173 | ||
174 | static void | ||
175 | __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) | ||
176 | { | ||
177 | list_del(&entry->list); | ||
178 | queue->queue_total--; | ||
179 | } | ||
180 | |||
174 | static struct nf_queue_entry * | 181 | static struct nf_queue_entry * |
175 | find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) | 182 | find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) |
176 | { | 183 | { |
@@ -185,10 +192,8 @@ find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) | |||
185 | } | 192 | } |
186 | } | 193 | } |
187 | 194 | ||
188 | if (entry) { | 195 | if (entry) |
189 | list_del(&entry->list); | 196 | __dequeue_entry(queue, entry); |
190 | queue->queue_total--; | ||
191 | } | ||
192 | 197 | ||
193 | spin_unlock_bh(&queue->lock); | 198 | spin_unlock_bh(&queue->lock); |
194 | 199 | ||
@@ -213,13 +218,15 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) | |||
213 | 218 | ||
214 | static struct sk_buff * | 219 | static struct sk_buff * |
215 | nfqnl_build_packet_message(struct nfqnl_instance *queue, | 220 | nfqnl_build_packet_message(struct nfqnl_instance *queue, |
216 | struct nf_queue_entry *entry) | 221 | struct nf_queue_entry *entry, |
222 | __be32 **packet_id_ptr) | ||
217 | { | 223 | { |
218 | sk_buff_data_t old_tail; | 224 | sk_buff_data_t old_tail; |
219 | size_t size; | 225 | size_t size; |
220 | size_t data_len = 0; | 226 | size_t data_len = 0; |
221 | struct sk_buff *skb; | 227 | struct sk_buff *skb; |
222 | struct nfqnl_msg_packet_hdr pmsg; | 228 | struct nlattr *nla; |
229 | struct nfqnl_msg_packet_hdr *pmsg; | ||
223 | struct nlmsghdr *nlh; | 230 | struct nlmsghdr *nlh; |
224 | struct nfgenmsg *nfmsg; | 231 | struct nfgenmsg *nfmsg; |
225 | struct sk_buff *entskb = entry->skb; | 232 | struct sk_buff *entskb = entry->skb; |
@@ -272,12 +279,11 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
272 | nfmsg->version = NFNETLINK_V0; | 279 | nfmsg->version = NFNETLINK_V0; |
273 | nfmsg->res_id = htons(queue->queue_num); | 280 | nfmsg->res_id = htons(queue->queue_num); |
274 | 281 | ||
275 | entry->id = atomic_inc_return(&queue->id_sequence); | 282 | nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg)); |
276 | pmsg.packet_id = htonl(entry->id); | 283 | pmsg = nla_data(nla); |
277 | pmsg.hw_protocol = entskb->protocol; | 284 | pmsg->hw_protocol = entskb->protocol; |
278 | pmsg.hook = entry->hook; | 285 | pmsg->hook = entry->hook; |
279 | 286 | *packet_id_ptr = &pmsg->packet_id; | |
280 | NLA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg); | ||
281 | 287 | ||
282 | indev = entry->indev; | 288 | indev = entry->indev; |
283 | if (indev) { | 289 | if (indev) { |
@@ -389,6 +395,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
389 | struct sk_buff *nskb; | 395 | struct sk_buff *nskb; |
390 | struct nfqnl_instance *queue; | 396 | struct nfqnl_instance *queue; |
391 | int err = -ENOBUFS; | 397 | int err = -ENOBUFS; |
398 | __be32 *packet_id_ptr; | ||
392 | 399 | ||
393 | /* rcu_read_lock()ed by nf_hook_slow() */ | 400 | /* rcu_read_lock()ed by nf_hook_slow() */ |
394 | queue = instance_lookup(queuenum); | 401 | queue = instance_lookup(queuenum); |
@@ -402,7 +409,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
402 | goto err_out; | 409 | goto err_out; |
403 | } | 410 | } |
404 | 411 | ||
405 | nskb = nfqnl_build_packet_message(queue, entry); | 412 | nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr); |
406 | if (nskb == NULL) { | 413 | if (nskb == NULL) { |
407 | err = -ENOMEM; | 414 | err = -ENOMEM; |
408 | goto err_out; | 415 | goto err_out; |
@@ -421,6 +428,8 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
421 | queue->queue_total); | 428 | queue->queue_total); |
422 | goto err_out_free_nskb; | 429 | goto err_out_free_nskb; |
423 | } | 430 | } |
431 | entry->id = ++queue->id_sequence; | ||
432 | *packet_id_ptr = htonl(entry->id); | ||
424 | 433 | ||
425 | /* nfnetlink_unicast will either free the nskb or add it to a socket */ | 434 | /* nfnetlink_unicast will either free the nskb or add it to a socket */ |
426 | err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); | 435 | err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); |
@@ -608,6 +617,92 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = { | |||
608 | [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, | 617 | [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, |
609 | }; | 618 | }; |
610 | 619 | ||
620 | static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = { | ||
621 | [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) }, | ||
622 | [NFQA_MARK] = { .type = NLA_U32 }, | ||
623 | }; | ||
624 | |||
625 | static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid) | ||
626 | { | ||
627 | struct nfqnl_instance *queue; | ||
628 | |||
629 | queue = instance_lookup(queue_num); | ||
630 | if (!queue) | ||
631 | return ERR_PTR(-ENODEV); | ||
632 | |||
633 | if (queue->peer_pid != nlpid) | ||
634 | return ERR_PTR(-EPERM); | ||
635 | |||
636 | return queue; | ||
637 | } | ||
638 | |||
639 | static struct nfqnl_msg_verdict_hdr* | ||
640 | verdicthdr_get(const struct nlattr * const nfqa[]) | ||
641 | { | ||
642 | struct nfqnl_msg_verdict_hdr *vhdr; | ||
643 | unsigned int verdict; | ||
644 | |||
645 | if (!nfqa[NFQA_VERDICT_HDR]) | ||
646 | return NULL; | ||
647 | |||
648 | vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); | ||
649 | verdict = ntohl(vhdr->verdict); | ||
650 | if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) | ||
651 | return NULL; | ||
652 | return vhdr; | ||
653 | } | ||
654 | |||
655 | static int nfq_id_after(unsigned int id, unsigned int max) | ||
656 | { | ||
657 | return (int)(id - max) > 0; | ||
658 | } | ||
659 | |||
660 | static int | ||
661 | nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb, | ||
662 | const struct nlmsghdr *nlh, | ||
663 | const struct nlattr * const nfqa[]) | ||
664 | { | ||
665 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
666 | struct nf_queue_entry *entry, *tmp; | ||
667 | unsigned int verdict, maxid; | ||
668 | struct nfqnl_msg_verdict_hdr *vhdr; | ||
669 | struct nfqnl_instance *queue; | ||
670 | LIST_HEAD(batch_list); | ||
671 | u16 queue_num = ntohs(nfmsg->res_id); | ||
672 | |||
673 | queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); | ||
674 | if (IS_ERR(queue)) | ||
675 | return PTR_ERR(queue); | ||
676 | |||
677 | vhdr = verdicthdr_get(nfqa); | ||
678 | if (!vhdr) | ||
679 | return -EINVAL; | ||
680 | |||
681 | verdict = ntohl(vhdr->verdict); | ||
682 | maxid = ntohl(vhdr->id); | ||
683 | |||
684 | spin_lock_bh(&queue->lock); | ||
685 | |||
686 | list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) { | ||
687 | if (nfq_id_after(entry->id, maxid)) | ||
688 | break; | ||
689 | __dequeue_entry(queue, entry); | ||
690 | list_add_tail(&entry->list, &batch_list); | ||
691 | } | ||
692 | |||
693 | spin_unlock_bh(&queue->lock); | ||
694 | |||
695 | if (list_empty(&batch_list)) | ||
696 | return -ENOENT; | ||
697 | |||
698 | list_for_each_entry_safe(entry, tmp, &batch_list, list) { | ||
699 | if (nfqa[NFQA_MARK]) | ||
700 | entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK])); | ||
701 | nf_reinject(entry, verdict); | ||
702 | } | ||
703 | return 0; | ||
704 | } | ||
705 | |||
611 | static int | 706 | static int |
612 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | 707 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, |
613 | const struct nlmsghdr *nlh, | 708 | const struct nlmsghdr *nlh, |
@@ -620,39 +715,23 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | |||
620 | struct nfqnl_instance *queue; | 715 | struct nfqnl_instance *queue; |
621 | unsigned int verdict; | 716 | unsigned int verdict; |
622 | struct nf_queue_entry *entry; | 717 | struct nf_queue_entry *entry; |
623 | int err; | ||
624 | 718 | ||
625 | rcu_read_lock(); | ||
626 | queue = instance_lookup(queue_num); | 719 | queue = instance_lookup(queue_num); |
627 | if (!queue) { | 720 | if (!queue) |
628 | err = -ENODEV; | ||
629 | goto err_out_unlock; | ||
630 | } | ||
631 | 721 | ||
632 | if (queue->peer_pid != NETLINK_CB(skb).pid) { | 722 | queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); |
633 | err = -EPERM; | 723 | if (IS_ERR(queue)) |
634 | goto err_out_unlock; | 724 | return PTR_ERR(queue); |
635 | } | ||
636 | 725 | ||
637 | if (!nfqa[NFQA_VERDICT_HDR]) { | 726 | vhdr = verdicthdr_get(nfqa); |
638 | err = -EINVAL; | 727 | if (!vhdr) |
639 | goto err_out_unlock; | 728 | return -EINVAL; |
640 | } | ||
641 | 729 | ||
642 | vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); | ||
643 | verdict = ntohl(vhdr->verdict); | 730 | verdict = ntohl(vhdr->verdict); |
644 | 731 | ||
645 | if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) { | ||
646 | err = -EINVAL; | ||
647 | goto err_out_unlock; | ||
648 | } | ||
649 | |||
650 | entry = find_dequeue_entry(queue, ntohl(vhdr->id)); | 732 | entry = find_dequeue_entry(queue, ntohl(vhdr->id)); |
651 | if (entry == NULL) { | 733 | if (entry == NULL) |
652 | err = -ENOENT; | 734 | return -ENOENT; |
653 | goto err_out_unlock; | ||
654 | } | ||
655 | rcu_read_unlock(); | ||
656 | 735 | ||
657 | if (nfqa[NFQA_PAYLOAD]) { | 736 | if (nfqa[NFQA_PAYLOAD]) { |
658 | if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), | 737 | if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), |
@@ -665,10 +744,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | |||
665 | 744 | ||
666 | nf_reinject(entry, verdict); | 745 | nf_reinject(entry, verdict); |
667 | return 0; | 746 | return 0; |
668 | |||
669 | err_out_unlock: | ||
670 | rcu_read_unlock(); | ||
671 | return err; | ||
672 | } | 747 | } |
673 | 748 | ||
674 | static int | 749 | static int |
@@ -781,14 +856,17 @@ err_out_unlock: | |||
781 | } | 856 | } |
782 | 857 | ||
783 | static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { | 858 | static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { |
784 | [NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp, | 859 | [NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp, |
785 | .attr_count = NFQA_MAX, }, | 860 | .attr_count = NFQA_MAX, }, |
786 | [NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict, | 861 | [NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict, |
787 | .attr_count = NFQA_MAX, | 862 | .attr_count = NFQA_MAX, |
788 | .policy = nfqa_verdict_policy }, | 863 | .policy = nfqa_verdict_policy }, |
789 | [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, | 864 | [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, |
790 | .attr_count = NFQA_CFG_MAX, | 865 | .attr_count = NFQA_CFG_MAX, |
791 | .policy = nfqa_cfg_policy }, | 866 | .policy = nfqa_cfg_policy }, |
867 | [NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch, | ||
868 | .attr_count = NFQA_MAX, | ||
869 | .policy = nfqa_verdict_batch_policy }, | ||
792 | }; | 870 | }; |
793 | 871 | ||
794 | static const struct nfnetlink_subsystem nfqnl_subsys = { | 872 | static const struct nfnetlink_subsystem nfqnl_subsys = { |
@@ -870,7 +948,7 @@ static int seq_show(struct seq_file *s, void *v) | |||
870 | inst->peer_pid, inst->queue_total, | 948 | inst->peer_pid, inst->queue_total, |
871 | inst->copy_mode, inst->copy_range, | 949 | inst->copy_mode, inst->copy_range, |
872 | inst->queue_dropped, inst->queue_user_dropped, | 950 | inst->queue_dropped, inst->queue_user_dropped, |
873 | atomic_read(&inst->id_sequence), 1); | 951 | inst->id_sequence, 1); |
874 | } | 952 | } |
875 | 953 | ||
876 | static const struct seq_operations nfqnl_seq_ops = { | 954 | static const struct seq_operations nfqnl_seq_ops = { |
diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c index 363a99ec0637..4bca15a0c385 100644 --- a/net/netfilter/xt_AUDIT.c +++ b/net/netfilter/xt_AUDIT.c | |||
@@ -163,6 +163,11 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
163 | break; | 163 | break; |
164 | } | 164 | } |
165 | 165 | ||
166 | #ifdef CONFIG_NETWORK_SECMARK | ||
167 | if (skb->secmark) | ||
168 | audit_log_secctx(ab, skb->secmark); | ||
169 | #endif | ||
170 | |||
166 | audit_log_end(ab); | 171 | audit_log_end(ab); |
167 | 172 | ||
168 | errout: | 173 | errout: |