diff options
author | David S. Miller <davem@davemloft.net> | 2018-05-13 20:28:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-05-13 20:28:47 -0400 |
commit | 4f6b15c3a604c0addf1607c5482c46a0a5123066 (patch) | |
tree | 4d47d8780be641a240e28cff56f702b40c384f91 | |
parent | 91dfd02b23006e7cc557bcb3a40aeb740f66fb52 (diff) | |
parent | f0dfd7a2b35b02030949100247d851b793cb275f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says:
====================
Netfilter/IPVS fixes for net
The following patchset contains Netfilter/IPVS fixes for your net tree,
they are:
1) Fix handling of simultaneous open TCP connection in conntrack,
from Jozsef Kadlecsik.
2) Insufficient sanitify check of xtables extension names, from
Florian Westphal.
3) Skip unnecessary synchronize_rcu() call when transaction log
is already empty, from Florian Westphal.
4) Incorrect destination mac validation in ebt_stp, from Stephen
Hemminger.
5) xtables module reference counter leak in nft_compat, from
Florian Westphal.
6) Incorrect connection reference counting logic in IPVS
one-packet scheduler, from Julian Anastasov.
7) Wrong stats for 32-bits CPU in IPVS, also from Julian.
8) Calm down sparse error in netfilter core, also from Florian.
9) Use nla_strlcpy to fix compilation warning in nfnetlink_acct
and nfnetlink_cthelper, again from Florian.
10) Missing module alias in icmp and icmp6 xtables extensions,
from Florian Westphal.
11) Base chain statistics in nf_tables may be unset/null, from Florian.
12) Fix handling of large matchinfo size in nft_compat, this includes
one preparation for before this fix. From Florian.
13) Fix bogus EBUSY error when deleting chains due to incorrect reference
counting from the preparation phase of the two-phase commit protocol.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/netfilter/nf_tables.h | 5 | ||||
-rw-r--r-- | include/uapi/linux/netfilter/nf_conntrack_tcp.h | 3 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_stp.c | 4 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 1 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 1 | ||||
-rw-r--r-- | net/netfilter/core.c | 3 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_conn.c | 17 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 12 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 11 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 77 | ||||
-rw-r--r-- | net/netfilter/nf_tables_core.c | 21 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_acct.c | 2 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_cthelper.c | 7 | ||||
-rw-r--r-- | net/netfilter/nft_compat.c | 201 | ||||
-rw-r--r-- | net/netfilter/nft_immediate.c | 15 | ||||
-rw-r--r-- | net/netfilter/x_tables.c | 6 |
16 files changed, 299 insertions, 87 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index cd368d1b8cb8..a1e28dd5d0bf 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -170,6 +170,7 @@ struct nft_data_desc { | |||
170 | int nft_data_init(const struct nft_ctx *ctx, | 170 | int nft_data_init(const struct nft_ctx *ctx, |
171 | struct nft_data *data, unsigned int size, | 171 | struct nft_data *data, unsigned int size, |
172 | struct nft_data_desc *desc, const struct nlattr *nla); | 172 | struct nft_data_desc *desc, const struct nlattr *nla); |
173 | void nft_data_hold(const struct nft_data *data, enum nft_data_types type); | ||
173 | void nft_data_release(const struct nft_data *data, enum nft_data_types type); | 174 | void nft_data_release(const struct nft_data *data, enum nft_data_types type); |
174 | int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data, | 175 | int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data, |
175 | enum nft_data_types type, unsigned int len); | 176 | enum nft_data_types type, unsigned int len); |
@@ -736,6 +737,10 @@ struct nft_expr_ops { | |||
736 | int (*init)(const struct nft_ctx *ctx, | 737 | int (*init)(const struct nft_ctx *ctx, |
737 | const struct nft_expr *expr, | 738 | const struct nft_expr *expr, |
738 | const struct nlattr * const tb[]); | 739 | const struct nlattr * const tb[]); |
740 | void (*activate)(const struct nft_ctx *ctx, | ||
741 | const struct nft_expr *expr); | ||
742 | void (*deactivate)(const struct nft_ctx *ctx, | ||
743 | const struct nft_expr *expr); | ||
739 | void (*destroy)(const struct nft_ctx *ctx, | 744 | void (*destroy)(const struct nft_ctx *ctx, |
740 | const struct nft_expr *expr); | 745 | const struct nft_expr *expr); |
741 | int (*dump)(struct sk_buff *skb, | 746 | int (*dump)(struct sk_buff *skb, |
diff --git a/include/uapi/linux/netfilter/nf_conntrack_tcp.h b/include/uapi/linux/netfilter/nf_conntrack_tcp.h index 74b91151d494..bcba72def817 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_tcp.h +++ b/include/uapi/linux/netfilter/nf_conntrack_tcp.h | |||
@@ -46,6 +46,9 @@ enum tcp_conntrack { | |||
46 | /* Marks possibility for expected RFC5961 challenge ACK */ | 46 | /* Marks possibility for expected RFC5961 challenge ACK */ |
47 | #define IP_CT_EXP_CHALLENGE_ACK 0x40 | 47 | #define IP_CT_EXP_CHALLENGE_ACK 0x40 |
48 | 48 | ||
49 | /* Simultaneous open initialized */ | ||
50 | #define IP_CT_TCP_SIMULTANEOUS_OPEN 0x80 | ||
51 | |||
49 | struct nf_ct_tcp_flags { | 52 | struct nf_ct_tcp_flags { |
50 | __u8 flags; | 53 | __u8 flags; |
51 | __u8 mask; | 54 | __u8 mask; |
diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c index 47ba98db145d..46c1fe7637ea 100644 --- a/net/bridge/netfilter/ebt_stp.c +++ b/net/bridge/netfilter/ebt_stp.c | |||
@@ -161,8 +161,8 @@ static int ebt_stp_mt_check(const struct xt_mtchk_param *par) | |||
161 | /* Make sure the match only receives stp frames */ | 161 | /* Make sure the match only receives stp frames */ |
162 | if (!par->nft_compat && | 162 | if (!par->nft_compat && |
163 | (!ether_addr_equal(e->destmac, eth_stp_addr) || | 163 | (!ether_addr_equal(e->destmac, eth_stp_addr) || |
164 | !is_broadcast_ether_addr(e->destmsk) || | 164 | !(e->bitmask & EBT_DESTMAC) || |
165 | !(e->bitmask & EBT_DESTMAC))) | 165 | !is_broadcast_ether_addr(e->destmsk))) |
166 | return -EINVAL; | 166 | return -EINVAL; |
167 | 167 | ||
168 | return 0; | 168 | return 0; |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 44b308d93ec2..e85f35b89c49 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -34,6 +34,7 @@ | |||
34 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
35 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 35 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
36 | MODULE_DESCRIPTION("IPv4 packet filter"); | 36 | MODULE_DESCRIPTION("IPv4 packet filter"); |
37 | MODULE_ALIAS("ipt_icmp"); | ||
37 | 38 | ||
38 | void *ipt_alloc_initial_table(const struct xt_table *info) | 39 | void *ipt_alloc_initial_table(const struct xt_table *info) |
39 | { | 40 | { |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 65c9e1a58305..97f79dc943d7 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -38,6 +38,7 @@ | |||
38 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
39 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 39 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
40 | MODULE_DESCRIPTION("IPv6 packet filter"); | 40 | MODULE_DESCRIPTION("IPv6 packet filter"); |
41 | MODULE_ALIAS("ip6t_icmp6"); | ||
41 | 42 | ||
42 | void *ip6t_alloc_initial_table(const struct xt_table *info) | 43 | void *ip6t_alloc_initial_table(const struct xt_table *info) |
43 | { | 44 | { |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 0f6b8172fb9a..206fb2c4c319 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -585,7 +585,8 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); | |||
585 | EXPORT_SYMBOL(nf_nat_decode_session_hook); | 585 | EXPORT_SYMBOL(nf_nat_decode_session_hook); |
586 | #endif | 586 | #endif |
587 | 587 | ||
588 | static void __net_init __netfilter_net_init(struct nf_hook_entries **e, int max) | 588 | static void __net_init |
589 | __netfilter_net_init(struct nf_hook_entries __rcu **e, int max) | ||
589 | { | 590 | { |
590 | int h; | 591 | int h; |
591 | 592 | ||
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 370abbf6f421..75de46576f51 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c | |||
@@ -232,7 +232,10 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp) | |||
232 | static inline bool ip_vs_conn_unlink(struct ip_vs_conn *cp) | 232 | static inline bool ip_vs_conn_unlink(struct ip_vs_conn *cp) |
233 | { | 233 | { |
234 | unsigned int hash; | 234 | unsigned int hash; |
235 | bool ret; | 235 | bool ret = false; |
236 | |||
237 | if (cp->flags & IP_VS_CONN_F_ONE_PACKET) | ||
238 | return refcount_dec_if_one(&cp->refcnt); | ||
236 | 239 | ||
237 | hash = ip_vs_conn_hashkey_conn(cp); | 240 | hash = ip_vs_conn_hashkey_conn(cp); |
238 | 241 | ||
@@ -240,15 +243,13 @@ static inline bool ip_vs_conn_unlink(struct ip_vs_conn *cp) | |||
240 | spin_lock(&cp->lock); | 243 | spin_lock(&cp->lock); |
241 | 244 | ||
242 | if (cp->flags & IP_VS_CONN_F_HASHED) { | 245 | if (cp->flags & IP_VS_CONN_F_HASHED) { |
243 | ret = false; | ||
244 | /* Decrease refcnt and unlink conn only if we are last user */ | 246 | /* Decrease refcnt and unlink conn only if we are last user */ |
245 | if (refcount_dec_if_one(&cp->refcnt)) { | 247 | if (refcount_dec_if_one(&cp->refcnt)) { |
246 | hlist_del_rcu(&cp->c_list); | 248 | hlist_del_rcu(&cp->c_list); |
247 | cp->flags &= ~IP_VS_CONN_F_HASHED; | 249 | cp->flags &= ~IP_VS_CONN_F_HASHED; |
248 | ret = true; | 250 | ret = true; |
249 | } | 251 | } |
250 | } else | 252 | } |
251 | ret = refcount_read(&cp->refcnt) ? false : true; | ||
252 | 253 | ||
253 | spin_unlock(&cp->lock); | 254 | spin_unlock(&cp->lock); |
254 | ct_write_unlock_bh(hash); | 255 | ct_write_unlock_bh(hash); |
@@ -454,12 +455,6 @@ ip_vs_conn_out_get_proto(struct netns_ipvs *ipvs, int af, | |||
454 | } | 455 | } |
455 | EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto); | 456 | EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto); |
456 | 457 | ||
457 | static void __ip_vs_conn_put_notimer(struct ip_vs_conn *cp) | ||
458 | { | ||
459 | __ip_vs_conn_put(cp); | ||
460 | ip_vs_conn_expire(&cp->timer); | ||
461 | } | ||
462 | |||
463 | /* | 458 | /* |
464 | * Put back the conn and restart its timer with its timeout | 459 | * Put back the conn and restart its timer with its timeout |
465 | */ | 460 | */ |
@@ -478,7 +473,7 @@ void ip_vs_conn_put(struct ip_vs_conn *cp) | |||
478 | (refcount_read(&cp->refcnt) == 1) && | 473 | (refcount_read(&cp->refcnt) == 1) && |
479 | !timer_pending(&cp->timer)) | 474 | !timer_pending(&cp->timer)) |
480 | /* expire connection immediately */ | 475 | /* expire connection immediately */ |
481 | __ip_vs_conn_put_notimer(cp); | 476 | ip_vs_conn_expire(&cp->timer); |
482 | else | 477 | else |
483 | __ip_vs_conn_put_timer(cp); | 478 | __ip_vs_conn_put_timer(cp); |
484 | } | 479 | } |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 5f6f73cf2174..0679dd101e72 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -119,6 +119,8 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb) | |||
119 | struct ip_vs_cpu_stats *s; | 119 | struct ip_vs_cpu_stats *s; |
120 | struct ip_vs_service *svc; | 120 | struct ip_vs_service *svc; |
121 | 121 | ||
122 | local_bh_disable(); | ||
123 | |||
122 | s = this_cpu_ptr(dest->stats.cpustats); | 124 | s = this_cpu_ptr(dest->stats.cpustats); |
123 | u64_stats_update_begin(&s->syncp); | 125 | u64_stats_update_begin(&s->syncp); |
124 | s->cnt.inpkts++; | 126 | s->cnt.inpkts++; |
@@ -137,6 +139,8 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb) | |||
137 | s->cnt.inpkts++; | 139 | s->cnt.inpkts++; |
138 | s->cnt.inbytes += skb->len; | 140 | s->cnt.inbytes += skb->len; |
139 | u64_stats_update_end(&s->syncp); | 141 | u64_stats_update_end(&s->syncp); |
142 | |||
143 | local_bh_enable(); | ||
140 | } | 144 | } |
141 | } | 145 | } |
142 | 146 | ||
@@ -151,6 +155,8 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb) | |||
151 | struct ip_vs_cpu_stats *s; | 155 | struct ip_vs_cpu_stats *s; |
152 | struct ip_vs_service *svc; | 156 | struct ip_vs_service *svc; |
153 | 157 | ||
158 | local_bh_disable(); | ||
159 | |||
154 | s = this_cpu_ptr(dest->stats.cpustats); | 160 | s = this_cpu_ptr(dest->stats.cpustats); |
155 | u64_stats_update_begin(&s->syncp); | 161 | u64_stats_update_begin(&s->syncp); |
156 | s->cnt.outpkts++; | 162 | s->cnt.outpkts++; |
@@ -169,6 +175,8 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb) | |||
169 | s->cnt.outpkts++; | 175 | s->cnt.outpkts++; |
170 | s->cnt.outbytes += skb->len; | 176 | s->cnt.outbytes += skb->len; |
171 | u64_stats_update_end(&s->syncp); | 177 | u64_stats_update_end(&s->syncp); |
178 | |||
179 | local_bh_enable(); | ||
172 | } | 180 | } |
173 | } | 181 | } |
174 | 182 | ||
@@ -179,6 +187,8 @@ ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc) | |||
179 | struct netns_ipvs *ipvs = svc->ipvs; | 187 | struct netns_ipvs *ipvs = svc->ipvs; |
180 | struct ip_vs_cpu_stats *s; | 188 | struct ip_vs_cpu_stats *s; |
181 | 189 | ||
190 | local_bh_disable(); | ||
191 | |||
182 | s = this_cpu_ptr(cp->dest->stats.cpustats); | 192 | s = this_cpu_ptr(cp->dest->stats.cpustats); |
183 | u64_stats_update_begin(&s->syncp); | 193 | u64_stats_update_begin(&s->syncp); |
184 | s->cnt.conns++; | 194 | s->cnt.conns++; |
@@ -193,6 +203,8 @@ ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc) | |||
193 | u64_stats_update_begin(&s->syncp); | 203 | u64_stats_update_begin(&s->syncp); |
194 | s->cnt.conns++; | 204 | s->cnt.conns++; |
195 | u64_stats_update_end(&s->syncp); | 205 | u64_stats_update_end(&s->syncp); |
206 | |||
207 | local_bh_enable(); | ||
196 | } | 208 | } |
197 | 209 | ||
198 | 210 | ||
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index e97cdc1cf98c..8e67910185a0 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -981,6 +981,17 @@ static int tcp_packet(struct nf_conn *ct, | |||
981 | return NF_ACCEPT; /* Don't change state */ | 981 | return NF_ACCEPT; /* Don't change state */ |
982 | } | 982 | } |
983 | break; | 983 | break; |
984 | case TCP_CONNTRACK_SYN_SENT2: | ||
985 | /* tcp_conntracks table is not smart enough to handle | ||
986 | * simultaneous open. | ||
987 | */ | ||
988 | ct->proto.tcp.last_flags |= IP_CT_TCP_SIMULTANEOUS_OPEN; | ||
989 | break; | ||
990 | case TCP_CONNTRACK_SYN_RECV: | ||
991 | if (dir == IP_CT_DIR_REPLY && index == TCP_ACK_SET && | ||
992 | ct->proto.tcp.last_flags & IP_CT_TCP_SIMULTANEOUS_OPEN) | ||
993 | new_state = TCP_CONNTRACK_ESTABLISHED; | ||
994 | break; | ||
984 | case TCP_CONNTRACK_CLOSE: | 995 | case TCP_CONNTRACK_CLOSE: |
985 | if (index == TCP_RST_SET | 996 | if (index == TCP_RST_SET |
986 | && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) | 997 | && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 04d4e3772584..91e80aa852d6 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -214,6 +214,34 @@ static int nft_delchain(struct nft_ctx *ctx) | |||
214 | return err; | 214 | return err; |
215 | } | 215 | } |
216 | 216 | ||
217 | static void nft_rule_expr_activate(const struct nft_ctx *ctx, | ||
218 | struct nft_rule *rule) | ||
219 | { | ||
220 | struct nft_expr *expr; | ||
221 | |||
222 | expr = nft_expr_first(rule); | ||
223 | while (expr != nft_expr_last(rule) && expr->ops) { | ||
224 | if (expr->ops->activate) | ||
225 | expr->ops->activate(ctx, expr); | ||
226 | |||
227 | expr = nft_expr_next(expr); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static void nft_rule_expr_deactivate(const struct nft_ctx *ctx, | ||
232 | struct nft_rule *rule) | ||
233 | { | ||
234 | struct nft_expr *expr; | ||
235 | |||
236 | expr = nft_expr_first(rule); | ||
237 | while (expr != nft_expr_last(rule) && expr->ops) { | ||
238 | if (expr->ops->deactivate) | ||
239 | expr->ops->deactivate(ctx, expr); | ||
240 | |||
241 | expr = nft_expr_next(expr); | ||
242 | } | ||
243 | } | ||
244 | |||
217 | static int | 245 | static int |
218 | nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule) | 246 | nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule) |
219 | { | 247 | { |
@@ -259,6 +287,7 @@ static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule) | |||
259 | nft_trans_destroy(trans); | 287 | nft_trans_destroy(trans); |
260 | return err; | 288 | return err; |
261 | } | 289 | } |
290 | nft_rule_expr_deactivate(ctx, rule); | ||
262 | 291 | ||
263 | return 0; | 292 | return 0; |
264 | } | 293 | } |
@@ -2238,6 +2267,13 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx, | |||
2238 | kfree(rule); | 2267 | kfree(rule); |
2239 | } | 2268 | } |
2240 | 2269 | ||
2270 | static void nf_tables_rule_release(const struct nft_ctx *ctx, | ||
2271 | struct nft_rule *rule) | ||
2272 | { | ||
2273 | nft_rule_expr_deactivate(ctx, rule); | ||
2274 | nf_tables_rule_destroy(ctx, rule); | ||
2275 | } | ||
2276 | |||
2241 | #define NFT_RULE_MAXEXPRS 128 | 2277 | #define NFT_RULE_MAXEXPRS 128 |
2242 | 2278 | ||
2243 | static struct nft_expr_info *info; | 2279 | static struct nft_expr_info *info; |
@@ -2402,7 +2438,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk, | |||
2402 | return 0; | 2438 | return 0; |
2403 | 2439 | ||
2404 | err2: | 2440 | err2: |
2405 | nf_tables_rule_destroy(&ctx, rule); | 2441 | nf_tables_rule_release(&ctx, rule); |
2406 | err1: | 2442 | err1: |
2407 | for (i = 0; i < n; i++) { | 2443 | for (i = 0; i < n; i++) { |
2408 | if (info[i].ops != NULL) | 2444 | if (info[i].ops != NULL) |
@@ -4044,8 +4080,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
4044 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^ | 4080 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^ |
4045 | nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) || | 4081 | nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) || |
4046 | nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^ | 4082 | nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^ |
4047 | nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF)) | 4083 | nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF)) { |
4048 | return -EBUSY; | 4084 | err = -EBUSY; |
4085 | goto err5; | ||
4086 | } | ||
4049 | if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) && | 4087 | if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) && |
4050 | nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) && | 4088 | nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) && |
4051 | memcmp(nft_set_ext_data(ext), | 4089 | memcmp(nft_set_ext_data(ext), |
@@ -4130,7 +4168,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk, | |||
4130 | * NFT_GOTO verdicts. This function must be called on active data objects | 4168 | * NFT_GOTO verdicts. This function must be called on active data objects |
4131 | * from the second phase of the commit protocol. | 4169 | * from the second phase of the commit protocol. |
4132 | */ | 4170 | */ |
4133 | static void nft_data_hold(const struct nft_data *data, enum nft_data_types type) | 4171 | void nft_data_hold(const struct nft_data *data, enum nft_data_types type) |
4134 | { | 4172 | { |
4135 | if (type == NFT_DATA_VERDICT) { | 4173 | if (type == NFT_DATA_VERDICT) { |
4136 | switch (data->verdict.code) { | 4174 | switch (data->verdict.code) { |
@@ -5761,7 +5799,7 @@ static void nft_chain_commit_update(struct nft_trans *trans) | |||
5761 | } | 5799 | } |
5762 | } | 5800 | } |
5763 | 5801 | ||
5764 | static void nf_tables_commit_release(struct nft_trans *trans) | 5802 | static void nft_commit_release(struct nft_trans *trans) |
5765 | { | 5803 | { |
5766 | switch (trans->msg_type) { | 5804 | switch (trans->msg_type) { |
5767 | case NFT_MSG_DELTABLE: | 5805 | case NFT_MSG_DELTABLE: |
@@ -5790,6 +5828,21 @@ static void nf_tables_commit_release(struct nft_trans *trans) | |||
5790 | kfree(trans); | 5828 | kfree(trans); |
5791 | } | 5829 | } |
5792 | 5830 | ||
5831 | static void nf_tables_commit_release(struct net *net) | ||
5832 | { | ||
5833 | struct nft_trans *trans, *next; | ||
5834 | |||
5835 | if (list_empty(&net->nft.commit_list)) | ||
5836 | return; | ||
5837 | |||
5838 | synchronize_rcu(); | ||
5839 | |||
5840 | list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { | ||
5841 | list_del(&trans->list); | ||
5842 | nft_commit_release(trans); | ||
5843 | } | ||
5844 | } | ||
5845 | |||
5793 | static int nf_tables_commit(struct net *net, struct sk_buff *skb) | 5846 | static int nf_tables_commit(struct net *net, struct sk_buff *skb) |
5794 | { | 5847 | { |
5795 | struct nft_trans *trans, *next; | 5848 | struct nft_trans *trans, *next; |
@@ -5920,13 +5973,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) | |||
5920 | } | 5973 | } |
5921 | } | 5974 | } |
5922 | 5975 | ||
5923 | synchronize_rcu(); | 5976 | nf_tables_commit_release(net); |
5924 | |||
5925 | list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { | ||
5926 | list_del(&trans->list); | ||
5927 | nf_tables_commit_release(trans); | ||
5928 | } | ||
5929 | |||
5930 | nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); | 5977 | nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); |
5931 | 5978 | ||
5932 | return 0; | 5979 | return 0; |
@@ -6006,10 +6053,12 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb) | |||
6006 | case NFT_MSG_NEWRULE: | 6053 | case NFT_MSG_NEWRULE: |
6007 | trans->ctx.chain->use--; | 6054 | trans->ctx.chain->use--; |
6008 | list_del_rcu(&nft_trans_rule(trans)->list); | 6055 | list_del_rcu(&nft_trans_rule(trans)->list); |
6056 | nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans)); | ||
6009 | break; | 6057 | break; |
6010 | case NFT_MSG_DELRULE: | 6058 | case NFT_MSG_DELRULE: |
6011 | trans->ctx.chain->use++; | 6059 | trans->ctx.chain->use++; |
6012 | nft_clear(trans->ctx.net, nft_trans_rule(trans)); | 6060 | nft_clear(trans->ctx.net, nft_trans_rule(trans)); |
6061 | nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans)); | ||
6013 | nft_trans_destroy(trans); | 6062 | nft_trans_destroy(trans); |
6014 | break; | 6063 | break; |
6015 | case NFT_MSG_NEWSET: | 6064 | case NFT_MSG_NEWSET: |
@@ -6585,7 +6634,7 @@ int __nft_release_basechain(struct nft_ctx *ctx) | |||
6585 | list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { | 6634 | list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { |
6586 | list_del(&rule->list); | 6635 | list_del(&rule->list); |
6587 | ctx->chain->use--; | 6636 | ctx->chain->use--; |
6588 | nf_tables_rule_destroy(ctx, rule); | 6637 | nf_tables_rule_release(ctx, rule); |
6589 | } | 6638 | } |
6590 | list_del(&ctx->chain->list); | 6639 | list_del(&ctx->chain->list); |
6591 | ctx->table->use--; | 6640 | ctx->table->use--; |
@@ -6623,7 +6672,7 @@ static void __nft_release_tables(struct net *net) | |||
6623 | list_for_each_entry_safe(rule, nr, &chain->rules, list) { | 6672 | list_for_each_entry_safe(rule, nr, &chain->rules, list) { |
6624 | list_del(&rule->list); | 6673 | list_del(&rule->list); |
6625 | chain->use--; | 6674 | chain->use--; |
6626 | nf_tables_rule_destroy(&ctx, rule); | 6675 | nf_tables_rule_release(&ctx, rule); |
6627 | } | 6676 | } |
6628 | } | 6677 | } |
6629 | list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) { | 6678 | list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) { |
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index dfd0bf3810d2..942702a2776f 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c | |||
@@ -119,15 +119,22 @@ DEFINE_STATIC_KEY_FALSE(nft_counters_enabled); | |||
119 | static noinline void nft_update_chain_stats(const struct nft_chain *chain, | 119 | static noinline void nft_update_chain_stats(const struct nft_chain *chain, |
120 | const struct nft_pktinfo *pkt) | 120 | const struct nft_pktinfo *pkt) |
121 | { | 121 | { |
122 | struct nft_base_chain *base_chain; | ||
122 | struct nft_stats *stats; | 123 | struct nft_stats *stats; |
123 | 124 | ||
124 | local_bh_disable(); | 125 | base_chain = nft_base_chain(chain); |
125 | stats = this_cpu_ptr(rcu_dereference(nft_base_chain(chain)->stats)); | 126 | if (!base_chain->stats) |
126 | u64_stats_update_begin(&stats->syncp); | 127 | return; |
127 | stats->pkts++; | 128 | |
128 | stats->bytes += pkt->skb->len; | 129 | stats = this_cpu_ptr(rcu_dereference(base_chain->stats)); |
129 | u64_stats_update_end(&stats->syncp); | 130 | if (stats) { |
130 | local_bh_enable(); | 131 | local_bh_disable(); |
132 | u64_stats_update_begin(&stats->syncp); | ||
133 | stats->pkts++; | ||
134 | stats->bytes += pkt->skb->len; | ||
135 | u64_stats_update_end(&stats->syncp); | ||
136 | local_bh_enable(); | ||
137 | } | ||
131 | } | 138 | } |
132 | 139 | ||
133 | struct nft_jumpstack { | 140 | struct nft_jumpstack { |
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index b9505bcd3827..6ddf89183e7b 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c | |||
@@ -115,7 +115,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl, | |||
115 | nfacct->flags = flags; | 115 | nfacct->flags = flags; |
116 | } | 116 | } |
117 | 117 | ||
118 | strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX); | 118 | nla_strlcpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX); |
119 | 119 | ||
120 | if (tb[NFACCT_BYTES]) { | 120 | if (tb[NFACCT_BYTES]) { |
121 | atomic64_set(&nfacct->bytes, | 121 | atomic64_set(&nfacct->bytes, |
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index 4a4b293fb2e5..fa026b269b36 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c | |||
@@ -149,8 +149,8 @@ nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy, | |||
149 | !tb[NFCTH_POLICY_EXPECT_TIMEOUT]) | 149 | !tb[NFCTH_POLICY_EXPECT_TIMEOUT]) |
150 | return -EINVAL; | 150 | return -EINVAL; |
151 | 151 | ||
152 | strncpy(expect_policy->name, | 152 | nla_strlcpy(expect_policy->name, |
153 | nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN); | 153 | nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN); |
154 | expect_policy->max_expected = | 154 | expect_policy->max_expected = |
155 | ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX])); | 155 | ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX])); |
156 | if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT) | 156 | if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT) |
@@ -234,7 +234,8 @@ nfnl_cthelper_create(const struct nlattr * const tb[], | |||
234 | if (ret < 0) | 234 | if (ret < 0) |
235 | goto err1; | 235 | goto err1; |
236 | 236 | ||
237 | strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN); | 237 | nla_strlcpy(helper->name, |
238 | nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN); | ||
238 | size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN])); | 239 | size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN])); |
239 | if (size > FIELD_SIZEOF(struct nf_conn_help, data)) { | 240 | if (size > FIELD_SIZEOF(struct nf_conn_help, data)) { |
240 | ret = -ENOMEM; | 241 | ret = -ENOMEM; |
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 8e23726b9081..1d99a1efdafc 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
@@ -27,14 +27,31 @@ struct nft_xt { | |||
27 | struct list_head head; | 27 | struct list_head head; |
28 | struct nft_expr_ops ops; | 28 | struct nft_expr_ops ops; |
29 | unsigned int refcnt; | 29 | unsigned int refcnt; |
30 | |||
31 | /* Unlike other expressions, ops doesn't have static storage duration. | ||
32 | * nft core assumes they do. We use kfree_rcu so that nft core can | ||
33 | * can check expr->ops->size even after nft_compat->destroy() frees | ||
34 | * the nft_xt struct that holds the ops structure. | ||
35 | */ | ||
36 | struct rcu_head rcu_head; | ||
37 | }; | ||
38 | |||
39 | /* Used for matches where *info is larger than X byte */ | ||
40 | #define NFT_MATCH_LARGE_THRESH 192 | ||
41 | |||
42 | struct nft_xt_match_priv { | ||
43 | void *info; | ||
30 | }; | 44 | }; |
31 | 45 | ||
32 | static void nft_xt_put(struct nft_xt *xt) | 46 | static bool nft_xt_put(struct nft_xt *xt) |
33 | { | 47 | { |
34 | if (--xt->refcnt == 0) { | 48 | if (--xt->refcnt == 0) { |
35 | list_del(&xt->head); | 49 | list_del(&xt->head); |
36 | kfree(xt); | 50 | kfree_rcu(xt, rcu_head); |
51 | return true; | ||
37 | } | 52 | } |
53 | |||
54 | return false; | ||
38 | } | 55 | } |
39 | 56 | ||
40 | static int nft_compat_chain_validate_dependency(const char *tablename, | 57 | static int nft_compat_chain_validate_dependency(const char *tablename, |
@@ -226,6 +243,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
226 | struct xt_target *target = expr->ops->data; | 243 | struct xt_target *target = expr->ops->data; |
227 | struct xt_tgchk_param par; | 244 | struct xt_tgchk_param par; |
228 | size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); | 245 | size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); |
246 | struct nft_xt *nft_xt; | ||
229 | u16 proto = 0; | 247 | u16 proto = 0; |
230 | bool inv = false; | 248 | bool inv = false; |
231 | union nft_entry e = {}; | 249 | union nft_entry e = {}; |
@@ -236,25 +254,22 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
236 | if (ctx->nla[NFTA_RULE_COMPAT]) { | 254 | if (ctx->nla[NFTA_RULE_COMPAT]) { |
237 | ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); | 255 | ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); |
238 | if (ret < 0) | 256 | if (ret < 0) |
239 | goto err; | 257 | return ret; |
240 | } | 258 | } |
241 | 259 | ||
242 | nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv); | 260 | nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv); |
243 | 261 | ||
244 | ret = xt_check_target(&par, size, proto, inv); | 262 | ret = xt_check_target(&par, size, proto, inv); |
245 | if (ret < 0) | 263 | if (ret < 0) |
246 | goto err; | 264 | return ret; |
247 | 265 | ||
248 | /* The standard target cannot be used */ | 266 | /* The standard target cannot be used */ |
249 | if (target->target == NULL) { | 267 | if (!target->target) |
250 | ret = -EINVAL; | 268 | return -EINVAL; |
251 | goto err; | ||
252 | } | ||
253 | 269 | ||
270 | nft_xt = container_of(expr->ops, struct nft_xt, ops); | ||
271 | nft_xt->refcnt++; | ||
254 | return 0; | 272 | return 0; |
255 | err: | ||
256 | module_put(target->me); | ||
257 | return ret; | ||
258 | } | 273 | } |
259 | 274 | ||
260 | static void | 275 | static void |
@@ -271,8 +286,8 @@ nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | |||
271 | if (par.target->destroy != NULL) | 286 | if (par.target->destroy != NULL) |
272 | par.target->destroy(&par); | 287 | par.target->destroy(&par); |
273 | 288 | ||
274 | nft_xt_put(container_of(expr->ops, struct nft_xt, ops)); | 289 | if (nft_xt_put(container_of(expr->ops, struct nft_xt, ops))) |
275 | module_put(target->me); | 290 | module_put(target->me); |
276 | } | 291 | } |
277 | 292 | ||
278 | static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) | 293 | static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) |
@@ -316,11 +331,11 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
316 | return 0; | 331 | return 0; |
317 | } | 332 | } |
318 | 333 | ||
319 | static void nft_match_eval(const struct nft_expr *expr, | 334 | static void __nft_match_eval(const struct nft_expr *expr, |
320 | struct nft_regs *regs, | 335 | struct nft_regs *regs, |
321 | const struct nft_pktinfo *pkt) | 336 | const struct nft_pktinfo *pkt, |
337 | void *info) | ||
322 | { | 338 | { |
323 | void *info = nft_expr_priv(expr); | ||
324 | struct xt_match *match = expr->ops->data; | 339 | struct xt_match *match = expr->ops->data; |
325 | struct sk_buff *skb = pkt->skb; | 340 | struct sk_buff *skb = pkt->skb; |
326 | bool ret; | 341 | bool ret; |
@@ -344,6 +359,22 @@ static void nft_match_eval(const struct nft_expr *expr, | |||
344 | } | 359 | } |
345 | } | 360 | } |
346 | 361 | ||
362 | static void nft_match_large_eval(const struct nft_expr *expr, | ||
363 | struct nft_regs *regs, | ||
364 | const struct nft_pktinfo *pkt) | ||
365 | { | ||
366 | struct nft_xt_match_priv *priv = nft_expr_priv(expr); | ||
367 | |||
368 | __nft_match_eval(expr, regs, pkt, priv->info); | ||
369 | } | ||
370 | |||
371 | static void nft_match_eval(const struct nft_expr *expr, | ||
372 | struct nft_regs *regs, | ||
373 | const struct nft_pktinfo *pkt) | ||
374 | { | ||
375 | __nft_match_eval(expr, regs, pkt, nft_expr_priv(expr)); | ||
376 | } | ||
377 | |||
347 | static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { | 378 | static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { |
348 | [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, | 379 | [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, |
349 | [NFTA_MATCH_REV] = { .type = NLA_U32 }, | 380 | [NFTA_MATCH_REV] = { .type = NLA_U32 }, |
@@ -404,13 +435,14 @@ static void match_compat_from_user(struct xt_match *m, void *in, void *out) | |||
404 | } | 435 | } |
405 | 436 | ||
406 | static int | 437 | static int |
407 | nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | 438 | __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, |
408 | const struct nlattr * const tb[]) | 439 | const struct nlattr * const tb[], |
440 | void *info) | ||
409 | { | 441 | { |
410 | void *info = nft_expr_priv(expr); | ||
411 | struct xt_match *match = expr->ops->data; | 442 | struct xt_match *match = expr->ops->data; |
412 | struct xt_mtchk_param par; | 443 | struct xt_mtchk_param par; |
413 | size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); | 444 | size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); |
445 | struct nft_xt *nft_xt; | ||
414 | u16 proto = 0; | 446 | u16 proto = 0; |
415 | bool inv = false; | 447 | bool inv = false; |
416 | union nft_entry e = {}; | 448 | union nft_entry e = {}; |
@@ -421,26 +453,50 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
421 | if (ctx->nla[NFTA_RULE_COMPAT]) { | 453 | if (ctx->nla[NFTA_RULE_COMPAT]) { |
422 | ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); | 454 | ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); |
423 | if (ret < 0) | 455 | if (ret < 0) |
424 | goto err; | 456 | return ret; |
425 | } | 457 | } |
426 | 458 | ||
427 | nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv); | 459 | nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv); |
428 | 460 | ||
429 | ret = xt_check_match(&par, size, proto, inv); | 461 | ret = xt_check_match(&par, size, proto, inv); |
430 | if (ret < 0) | 462 | if (ret < 0) |
431 | goto err; | 463 | return ret; |
432 | 464 | ||
465 | nft_xt = container_of(expr->ops, struct nft_xt, ops); | ||
466 | nft_xt->refcnt++; | ||
433 | return 0; | 467 | return 0; |
434 | err: | 468 | } |
435 | module_put(match->me); | 469 | |
470 | static int | ||
471 | nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
472 | const struct nlattr * const tb[]) | ||
473 | { | ||
474 | return __nft_match_init(ctx, expr, tb, nft_expr_priv(expr)); | ||
475 | } | ||
476 | |||
477 | static int | ||
478 | nft_match_large_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
479 | const struct nlattr * const tb[]) | ||
480 | { | ||
481 | struct nft_xt_match_priv *priv = nft_expr_priv(expr); | ||
482 | struct xt_match *m = expr->ops->data; | ||
483 | int ret; | ||
484 | |||
485 | priv->info = kmalloc(XT_ALIGN(m->matchsize), GFP_KERNEL); | ||
486 | if (!priv->info) | ||
487 | return -ENOMEM; | ||
488 | |||
489 | ret = __nft_match_init(ctx, expr, tb, priv->info); | ||
490 | if (ret) | ||
491 | kfree(priv->info); | ||
436 | return ret; | 492 | return ret; |
437 | } | 493 | } |
438 | 494 | ||
439 | static void | 495 | static void |
440 | nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | 496 | __nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr, |
497 | void *info) | ||
441 | { | 498 | { |
442 | struct xt_match *match = expr->ops->data; | 499 | struct xt_match *match = expr->ops->data; |
443 | void *info = nft_expr_priv(expr); | ||
444 | struct xt_mtdtor_param par; | 500 | struct xt_mtdtor_param par; |
445 | 501 | ||
446 | par.net = ctx->net; | 502 | par.net = ctx->net; |
@@ -450,13 +506,28 @@ nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | |||
450 | if (par.match->destroy != NULL) | 506 | if (par.match->destroy != NULL) |
451 | par.match->destroy(&par); | 507 | par.match->destroy(&par); |
452 | 508 | ||
453 | nft_xt_put(container_of(expr->ops, struct nft_xt, ops)); | 509 | if (nft_xt_put(container_of(expr->ops, struct nft_xt, ops))) |
454 | module_put(match->me); | 510 | module_put(match->me); |
455 | } | 511 | } |
456 | 512 | ||
457 | static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr) | 513 | static void |
514 | nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | ||
515 | { | ||
516 | __nft_match_destroy(ctx, expr, nft_expr_priv(expr)); | ||
517 | } | ||
518 | |||
519 | static void | ||
520 | nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) | ||
521 | { | ||
522 | struct nft_xt_match_priv *priv = nft_expr_priv(expr); | ||
523 | |||
524 | __nft_match_destroy(ctx, expr, priv->info); | ||
525 | kfree(priv->info); | ||
526 | } | ||
527 | |||
528 | static int __nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr, | ||
529 | void *info) | ||
458 | { | 530 | { |
459 | void *info = nft_expr_priv(expr); | ||
460 | struct xt_match *match = expr->ops->data; | 531 | struct xt_match *match = expr->ops->data; |
461 | 532 | ||
462 | if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) || | 533 | if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) || |
@@ -470,6 +541,18 @@ nla_put_failure: | |||
470 | return -1; | 541 | return -1; |
471 | } | 542 | } |
472 | 543 | ||
544 | static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr) | ||
545 | { | ||
546 | return __nft_match_dump(skb, expr, nft_expr_priv(expr)); | ||
547 | } | ||
548 | |||
549 | static int nft_match_large_dump(struct sk_buff *skb, const struct nft_expr *e) | ||
550 | { | ||
551 | struct nft_xt_match_priv *priv = nft_expr_priv(e); | ||
552 | |||
553 | return __nft_match_dump(skb, e, priv->info); | ||
554 | } | ||
555 | |||
473 | static int nft_match_validate(const struct nft_ctx *ctx, | 556 | static int nft_match_validate(const struct nft_ctx *ctx, |
474 | const struct nft_expr *expr, | 557 | const struct nft_expr *expr, |
475 | const struct nft_data **data) | 558 | const struct nft_data **data) |
@@ -637,6 +720,7 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
637 | { | 720 | { |
638 | struct nft_xt *nft_match; | 721 | struct nft_xt *nft_match; |
639 | struct xt_match *match; | 722 | struct xt_match *match; |
723 | unsigned int matchsize; | ||
640 | char *mt_name; | 724 | char *mt_name; |
641 | u32 rev, family; | 725 | u32 rev, family; |
642 | int err; | 726 | int err; |
@@ -654,13 +738,8 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
654 | list_for_each_entry(nft_match, &nft_match_list, head) { | 738 | list_for_each_entry(nft_match, &nft_match_list, head) { |
655 | struct xt_match *match = nft_match->ops.data; | 739 | struct xt_match *match = nft_match->ops.data; |
656 | 740 | ||
657 | if (nft_match_cmp(match, mt_name, rev, family)) { | 741 | if (nft_match_cmp(match, mt_name, rev, family)) |
658 | if (!try_module_get(match->me)) | ||
659 | return ERR_PTR(-ENOENT); | ||
660 | |||
661 | nft_match->refcnt++; | ||
662 | return &nft_match->ops; | 742 | return &nft_match->ops; |
663 | } | ||
664 | } | 743 | } |
665 | 744 | ||
666 | match = xt_request_find_match(family, mt_name, rev); | 745 | match = xt_request_find_match(family, mt_name, rev); |
@@ -679,9 +758,8 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
679 | goto err; | 758 | goto err; |
680 | } | 759 | } |
681 | 760 | ||
682 | nft_match->refcnt = 1; | 761 | nft_match->refcnt = 0; |
683 | nft_match->ops.type = &nft_match_type; | 762 | nft_match->ops.type = &nft_match_type; |
684 | nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize)); | ||
685 | nft_match->ops.eval = nft_match_eval; | 763 | nft_match->ops.eval = nft_match_eval; |
686 | nft_match->ops.init = nft_match_init; | 764 | nft_match->ops.init = nft_match_init; |
687 | nft_match->ops.destroy = nft_match_destroy; | 765 | nft_match->ops.destroy = nft_match_destroy; |
@@ -689,6 +767,18 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
689 | nft_match->ops.validate = nft_match_validate; | 767 | nft_match->ops.validate = nft_match_validate; |
690 | nft_match->ops.data = match; | 768 | nft_match->ops.data = match; |
691 | 769 | ||
770 | matchsize = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize)); | ||
771 | if (matchsize > NFT_MATCH_LARGE_THRESH) { | ||
772 | matchsize = NFT_EXPR_SIZE(sizeof(struct nft_xt_match_priv)); | ||
773 | |||
774 | nft_match->ops.eval = nft_match_large_eval; | ||
775 | nft_match->ops.init = nft_match_large_init; | ||
776 | nft_match->ops.destroy = nft_match_large_destroy; | ||
777 | nft_match->ops.dump = nft_match_large_dump; | ||
778 | } | ||
779 | |||
780 | nft_match->ops.size = matchsize; | ||
781 | |||
692 | list_add(&nft_match->head, &nft_match_list); | 782 | list_add(&nft_match->head, &nft_match_list); |
693 | 783 | ||
694 | return &nft_match->ops; | 784 | return &nft_match->ops; |
@@ -739,13 +829,8 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
739 | list_for_each_entry(nft_target, &nft_target_list, head) { | 829 | list_for_each_entry(nft_target, &nft_target_list, head) { |
740 | struct xt_target *target = nft_target->ops.data; | 830 | struct xt_target *target = nft_target->ops.data; |
741 | 831 | ||
742 | if (nft_target_cmp(target, tg_name, rev, family)) { | 832 | if (nft_target_cmp(target, tg_name, rev, family)) |
743 | if (!try_module_get(target->me)) | ||
744 | return ERR_PTR(-ENOENT); | ||
745 | |||
746 | nft_target->refcnt++; | ||
747 | return &nft_target->ops; | 833 | return &nft_target->ops; |
748 | } | ||
749 | } | 834 | } |
750 | 835 | ||
751 | target = xt_request_find_target(family, tg_name, rev); | 836 | target = xt_request_find_target(family, tg_name, rev); |
@@ -764,7 +849,7 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
764 | goto err; | 849 | goto err; |
765 | } | 850 | } |
766 | 851 | ||
767 | nft_target->refcnt = 1; | 852 | nft_target->refcnt = 0; |
768 | nft_target->ops.type = &nft_target_type; | 853 | nft_target->ops.type = &nft_target_type; |
769 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); | 854 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); |
770 | nft_target->ops.init = nft_target_init; | 855 | nft_target->ops.init = nft_target_init; |
@@ -823,6 +908,32 @@ err_match: | |||
823 | 908 | ||
824 | static void __exit nft_compat_module_exit(void) | 909 | static void __exit nft_compat_module_exit(void) |
825 | { | 910 | { |
911 | struct nft_xt *xt, *next; | ||
912 | |||
913 | /* list should be empty here, it can be non-empty only in case there | ||
914 | * was an error that caused nft_xt expr to not be initialized fully | ||
915 | * and noone else requested the same expression later. | ||
916 | * | ||
917 | * In this case, the lists contain 0-refcount entries that still | ||
918 | * hold module reference. | ||
919 | */ | ||
920 | list_for_each_entry_safe(xt, next, &nft_target_list, head) { | ||
921 | struct xt_target *target = xt->ops.data; | ||
922 | |||
923 | if (WARN_ON_ONCE(xt->refcnt)) | ||
924 | continue; | ||
925 | module_put(target->me); | ||
926 | kfree(xt); | ||
927 | } | ||
928 | |||
929 | list_for_each_entry_safe(xt, next, &nft_match_list, head) { | ||
930 | struct xt_match *match = xt->ops.data; | ||
931 | |||
932 | if (WARN_ON_ONCE(xt->refcnt)) | ||
933 | continue; | ||
934 | module_put(match->me); | ||
935 | kfree(xt); | ||
936 | } | ||
826 | nfnetlink_subsys_unregister(&nfnl_compat_subsys); | 937 | nfnetlink_subsys_unregister(&nfnl_compat_subsys); |
827 | nft_unregister_expr(&nft_target_type); | 938 | nft_unregister_expr(&nft_target_type); |
828 | nft_unregister_expr(&nft_match_type); | 939 | nft_unregister_expr(&nft_match_type); |
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c index 4717d7796927..aa87ff8beae8 100644 --- a/net/netfilter/nft_immediate.c +++ b/net/netfilter/nft_immediate.c | |||
@@ -69,8 +69,16 @@ err1: | |||
69 | return err; | 69 | return err; |
70 | } | 70 | } |
71 | 71 | ||
72 | static void nft_immediate_destroy(const struct nft_ctx *ctx, | 72 | static void nft_immediate_activate(const struct nft_ctx *ctx, |
73 | const struct nft_expr *expr) | 73 | const struct nft_expr *expr) |
74 | { | ||
75 | const struct nft_immediate_expr *priv = nft_expr_priv(expr); | ||
76 | |||
77 | return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg)); | ||
78 | } | ||
79 | |||
80 | static void nft_immediate_deactivate(const struct nft_ctx *ctx, | ||
81 | const struct nft_expr *expr) | ||
74 | { | 82 | { |
75 | const struct nft_immediate_expr *priv = nft_expr_priv(expr); | 83 | const struct nft_immediate_expr *priv = nft_expr_priv(expr); |
76 | 84 | ||
@@ -108,7 +116,8 @@ static const struct nft_expr_ops nft_imm_ops = { | |||
108 | .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), | 116 | .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), |
109 | .eval = nft_immediate_eval, | 117 | .eval = nft_immediate_eval, |
110 | .init = nft_immediate_init, | 118 | .init = nft_immediate_init, |
111 | .destroy = nft_immediate_destroy, | 119 | .activate = nft_immediate_activate, |
120 | .deactivate = nft_immediate_deactivate, | ||
112 | .dump = nft_immediate_dump, | 121 | .dump = nft_immediate_dump, |
113 | .validate = nft_immediate_validate, | 122 | .validate = nft_immediate_validate, |
114 | }; | 123 | }; |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 71325fef647d..cb7cb300c3bc 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -183,6 +183,9 @@ struct xt_match *xt_find_match(u8 af, const char *name, u8 revision) | |||
183 | struct xt_match *m; | 183 | struct xt_match *m; |
184 | int err = -ENOENT; | 184 | int err = -ENOENT; |
185 | 185 | ||
186 | if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN) | ||
187 | return ERR_PTR(-EINVAL); | ||
188 | |||
186 | mutex_lock(&xt[af].mutex); | 189 | mutex_lock(&xt[af].mutex); |
187 | list_for_each_entry(m, &xt[af].match, list) { | 190 | list_for_each_entry(m, &xt[af].match, list) { |
188 | if (strcmp(m->name, name) == 0) { | 191 | if (strcmp(m->name, name) == 0) { |
@@ -229,6 +232,9 @@ struct xt_target *xt_find_target(u8 af, const char *name, u8 revision) | |||
229 | struct xt_target *t; | 232 | struct xt_target *t; |
230 | int err = -ENOENT; | 233 | int err = -ENOENT; |
231 | 234 | ||
235 | if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN) | ||
236 | return ERR_PTR(-EINVAL); | ||
237 | |||
232 | mutex_lock(&xt[af].mutex); | 238 | mutex_lock(&xt[af].mutex); |
233 | list_for_each_entry(t, &xt[af].target, list) { | 239 | list_for_each_entry(t, &xt[af].target, list) { |
234 | if (strcmp(t->name, name) == 0) { | 240 | if (strcmp(t->name, name) == 0) { |