diff options
author | David S. Miller <davem@davemloft.net> | 2014-05-21 01:24:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-21 01:24:19 -0400 |
commit | d050de607f062233cf5e75b2e8f40f20c4b04b91 (patch) | |
tree | ddfa81805a7a4df07b4d95a27091909fe38ddb55 /net | |
parent | e1618d461ca18d40f9c3ef70598abb72e75d27ae (diff) | |
parent | 3b084e99a3fabaeb0f9c65a0806cde30f0b2835e (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says:
====================
Netfilter/nftables fixes for net
The following patchset contains nftables fixes for your net tree, they
are:
1) Fix crash when using the goto action in a rule by making sure that
we always fall back on the base chain. Otherwise, this may try to
access the counter memory area of non-base chains, which does not
exists.
2) Fix several aspects of the rule tracing that are currently broken:
* Reset rule number counter after goto/jump action, otherwise the
tracing reports a bogus rule number.
* Fix tracing of the goto action.
* Fix bogus rule number counter after goto.
* Fix missing return trace after finishing the walk through the
non-base chain.
* Fix missing trace when matching non-terminal rule.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_tables_core.c | 49 |
1 files changed, 23 insertions, 26 deletions
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index 804105391b9a..345acfb1720b 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c | |||
@@ -66,20 +66,6 @@ struct nft_jumpstack { | |||
66 | int rulenum; | 66 | int rulenum; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | static inline void | ||
70 | nft_chain_stats(const struct nft_chain *this, const struct nft_pktinfo *pkt, | ||
71 | struct nft_jumpstack *jumpstack, unsigned int stackptr) | ||
72 | { | ||
73 | struct nft_stats __percpu *stats; | ||
74 | const struct nft_chain *chain = stackptr ? jumpstack[0].chain : this; | ||
75 | |||
76 | rcu_read_lock_bh(); | ||
77 | stats = rcu_dereference(nft_base_chain(chain)->stats); | ||
78 | __this_cpu_inc(stats->pkts); | ||
79 | __this_cpu_add(stats->bytes, pkt->skb->len); | ||
80 | rcu_read_unlock_bh(); | ||
81 | } | ||
82 | |||
83 | enum nft_trace { | 69 | enum nft_trace { |
84 | NFT_TRACE_RULE, | 70 | NFT_TRACE_RULE, |
85 | NFT_TRACE_RETURN, | 71 | NFT_TRACE_RETURN, |
@@ -117,13 +103,14 @@ static void nft_trace_packet(const struct nft_pktinfo *pkt, | |||
117 | unsigned int | 103 | unsigned int |
118 | nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) | 104 | nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) |
119 | { | 105 | { |
120 | const struct nft_chain *chain = ops->priv; | 106 | const struct nft_chain *chain = ops->priv, *basechain = chain; |
121 | const struct nft_rule *rule; | 107 | const struct nft_rule *rule; |
122 | const struct nft_expr *expr, *last; | 108 | const struct nft_expr *expr, *last; |
123 | struct nft_data data[NFT_REG_MAX + 1]; | 109 | struct nft_data data[NFT_REG_MAX + 1]; |
124 | unsigned int stackptr = 0; | 110 | unsigned int stackptr = 0; |
125 | struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; | 111 | struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; |
126 | int rulenum = 0; | 112 | struct nft_stats __percpu *stats; |
113 | int rulenum; | ||
127 | /* | 114 | /* |
128 | * Cache cursor to avoid problems in case that the cursor is updated | 115 | * Cache cursor to avoid problems in case that the cursor is updated |
129 | * while traversing the ruleset. | 116 | * while traversing the ruleset. |
@@ -131,6 +118,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) | |||
131 | unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor); | 118 | unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor); |
132 | 119 | ||
133 | do_chain: | 120 | do_chain: |
121 | rulenum = 0; | ||
134 | rule = list_entry(&chain->rules, struct nft_rule, list); | 122 | rule = list_entry(&chain->rules, struct nft_rule, list); |
135 | next_rule: | 123 | next_rule: |
136 | data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; | 124 | data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; |
@@ -156,8 +144,10 @@ next_rule: | |||
156 | switch (data[NFT_REG_VERDICT].verdict) { | 144 | switch (data[NFT_REG_VERDICT].verdict) { |
157 | case NFT_BREAK: | 145 | case NFT_BREAK: |
158 | data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; | 146 | data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; |
159 | /* fall through */ | 147 | continue; |
160 | case NFT_CONTINUE: | 148 | case NFT_CONTINUE: |
149 | if (unlikely(pkt->skb->nf_trace)) | ||
150 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); | ||
161 | continue; | 151 | continue; |
162 | } | 152 | } |
163 | break; | 153 | break; |
@@ -183,37 +173,44 @@ next_rule: | |||
183 | jumpstack[stackptr].rule = rule; | 173 | jumpstack[stackptr].rule = rule; |
184 | jumpstack[stackptr].rulenum = rulenum; | 174 | jumpstack[stackptr].rulenum = rulenum; |
185 | stackptr++; | 175 | stackptr++; |
186 | /* fall through */ | 176 | chain = data[NFT_REG_VERDICT].chain; |
177 | goto do_chain; | ||
187 | case NFT_GOTO: | 178 | case NFT_GOTO: |
179 | if (unlikely(pkt->skb->nf_trace)) | ||
180 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); | ||
181 | |||
188 | chain = data[NFT_REG_VERDICT].chain; | 182 | chain = data[NFT_REG_VERDICT].chain; |
189 | goto do_chain; | 183 | goto do_chain; |
190 | case NFT_RETURN: | 184 | case NFT_RETURN: |
191 | if (unlikely(pkt->skb->nf_trace)) | 185 | if (unlikely(pkt->skb->nf_trace)) |
192 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN); | 186 | nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN); |
193 | 187 | break; | |
194 | /* fall through */ | ||
195 | case NFT_CONTINUE: | 188 | case NFT_CONTINUE: |
189 | if (unlikely(pkt->skb->nf_trace && !(chain->flags & NFT_BASE_CHAIN))) | ||
190 | nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN); | ||
196 | break; | 191 | break; |
197 | default: | 192 | default: |
198 | WARN_ON(1); | 193 | WARN_ON(1); |
199 | } | 194 | } |
200 | 195 | ||
201 | if (stackptr > 0) { | 196 | if (stackptr > 0) { |
202 | if (unlikely(pkt->skb->nf_trace)) | ||
203 | nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN); | ||
204 | |||
205 | stackptr--; | 197 | stackptr--; |
206 | chain = jumpstack[stackptr].chain; | 198 | chain = jumpstack[stackptr].chain; |
207 | rule = jumpstack[stackptr].rule; | 199 | rule = jumpstack[stackptr].rule; |
208 | rulenum = jumpstack[stackptr].rulenum; | 200 | rulenum = jumpstack[stackptr].rulenum; |
209 | goto next_rule; | 201 | goto next_rule; |
210 | } | 202 | } |
211 | nft_chain_stats(chain, pkt, jumpstack, stackptr); | ||
212 | 203 | ||
213 | if (unlikely(pkt->skb->nf_trace)) | 204 | if (unlikely(pkt->skb->nf_trace)) |
214 | nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY); | 205 | nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY); |
206 | |||
207 | rcu_read_lock_bh(); | ||
208 | stats = rcu_dereference(nft_base_chain(basechain)->stats); | ||
209 | __this_cpu_inc(stats->pkts); | ||
210 | __this_cpu_add(stats->bytes, pkt->skb->len); | ||
211 | rcu_read_unlock_bh(); | ||
215 | 212 | ||
216 | return nft_base_chain(chain)->policy; | 213 | return nft_base_chain(basechain)->policy; |
217 | } | 214 | } |
218 | EXPORT_SYMBOL_GPL(nft_do_chain); | 215 | EXPORT_SYMBOL_GPL(nft_do_chain); |
219 | 216 | ||