aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2009-11-23 04:43:57 -0500
committerPatrick McHardy <kaber@trash.net>2009-11-23 04:43:57 -0500
commit3a0429292daa0e1ec848bd26479f5e48b0d54a42 (patch)
treeef63c29a31efc7942e2d364a11edfab627e6bc33 /net
parentc4832c7bbc3f7a4813347e871d7238651bf437d3 (diff)
netfilter: xtables: fix conntrack match v1 ipt-save output
commit d6d3f08b0fd998b647a05540cedd11a067b72867 (netfilter: xtables: conntrack match revision 2) does break the v1 conntrack match iptables-save output in a subtle way. Problem is as follows: up = kmalloc(sizeof(*up), GFP_KERNEL); [..] /* * The strategy here is to minimize the overhead of v1 matching, * by prebuilding a v2 struct and putting the pointer into the * v1 dataspace. */ memcpy(up, info, offsetof(typeof(*info), state_mask)); [..] *(void **)info = up; As the v2 struct pointer is saved in the match data space, it clobbers the first structure member (->origsrc_addr). Because the _v1 match function grabs this pointer and does not actually look at the v1 origsrc, run time functionality does not break. But iptables -nvL (or iptables-save) cannot know that v1 origsrc_addr has been overloaded in this way: $ iptables -p tcp -A OUTPUT -m conntrack --ctorigsrc 10.0.0.1 -j ACCEPT $ iptables-save -A OUTPUT -p tcp -m conntrack --ctorigsrc 128.173.134.206 -j ACCEPT (128.173... is the address to the v2 match structure). To fix this, we take advantage of the fact that the v1 and v2 structures are identical with exception of the last two structure members (u8 in v1, u16 in v2). We extract them as early as possible and prevent the v2 matching function from looking at those two members directly. Previously reported by Michel Messerschmidt via Ben Hutchings, also see Debian Bug tracker #556587. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/xt_conntrack.c61
1 files changed, 17 insertions, 44 deletions
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 6dc4652f2fe8..ae66305f0fe5 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -113,7 +113,8 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
113} 113}
114 114
115static bool 115static bool
116conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) 116conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par,
117 u16 state_mask, u16 status_mask)
117{ 118{
118 const struct xt_conntrack_mtinfo2 *info = par->matchinfo; 119 const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
119 enum ip_conntrack_info ctinfo; 120 enum ip_conntrack_info ctinfo;
@@ -136,7 +137,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
136 if (test_bit(IPS_DST_NAT_BIT, &ct->status)) 137 if (test_bit(IPS_DST_NAT_BIT, &ct->status))
137 statebit |= XT_CONNTRACK_STATE_DNAT; 138 statebit |= XT_CONNTRACK_STATE_DNAT;
138 } 139 }
139 if (!!(info->state_mask & statebit) ^ 140 if (!!(state_mask & statebit) ^
140 !(info->invert_flags & XT_CONNTRACK_STATE)) 141 !(info->invert_flags & XT_CONNTRACK_STATE))
141 return false; 142 return false;
142 } 143 }
@@ -172,7 +173,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
172 return false; 173 return false;
173 174
174 if ((info->match_flags & XT_CONNTRACK_STATUS) && 175 if ((info->match_flags & XT_CONNTRACK_STATUS) &&
175 (!!(info->status_mask & ct->status) ^ 176 (!!(status_mask & ct->status) ^
176 !(info->invert_flags & XT_CONNTRACK_STATUS))) 177 !(info->invert_flags & XT_CONNTRACK_STATUS)))
177 return false; 178 return false;
178 179
@@ -192,11 +193,17 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
192static bool 193static bool
193conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) 194conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
194{ 195{
195 const struct xt_conntrack_mtinfo2 *const *info = par->matchinfo; 196 const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
196 struct xt_match_param newpar = *par;
197 197
198 newpar.matchinfo = *info; 198 return conntrack_mt(skb, par, info->state_mask, info->status_mask);
199 return conntrack_mt(skb, &newpar); 199}
200
201static bool
202conntrack_mt_v2(const struct sk_buff *skb, const struct xt_match_param *par)
203{
204 const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
205
206 return conntrack_mt(skb, par, info->state_mask, info->status_mask);
200} 207}
201 208
202static bool conntrack_mt_check(const struct xt_mtchk_param *par) 209static bool conntrack_mt_check(const struct xt_mtchk_param *par)
@@ -209,45 +216,11 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par)
209 return true; 216 return true;
210} 217}
211 218
212static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par)
213{
214 struct xt_conntrack_mtinfo1 *info = par->matchinfo;
215 struct xt_conntrack_mtinfo2 *up;
216 int ret = conntrack_mt_check(par);
217
218 if (ret < 0)
219 return ret;
220
221 up = kmalloc(sizeof(*up), GFP_KERNEL);
222 if (up == NULL) {
223 nf_ct_l3proto_module_put(par->family);
224 return -ENOMEM;
225 }
226
227 /*
228 * The strategy here is to minimize the overhead of v1 matching,
229 * by prebuilding a v2 struct and putting the pointer into the
230 * v1 dataspace.
231 */
232 memcpy(up, info, offsetof(typeof(*info), state_mask));
233 up->state_mask = info->state_mask;
234 up->status_mask = info->status_mask;
235 *(void **)info = up;
236 return true;
237}
238
239static void conntrack_mt_destroy(const struct xt_mtdtor_param *par) 219static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
240{ 220{
241 nf_ct_l3proto_module_put(par->family); 221 nf_ct_l3proto_module_put(par->family);
242} 222}
243 223
244static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par)
245{
246 struct xt_conntrack_mtinfo2 **info = par->matchinfo;
247 kfree(*info);
248 conntrack_mt_destroy(par);
249}
250
251static struct xt_match conntrack_mt_reg[] __read_mostly = { 224static struct xt_match conntrack_mt_reg[] __read_mostly = {
252 { 225 {
253 .name = "conntrack", 226 .name = "conntrack",
@@ -255,8 +228,8 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = {
255 .family = NFPROTO_UNSPEC, 228 .family = NFPROTO_UNSPEC,
256 .matchsize = sizeof(struct xt_conntrack_mtinfo1), 229 .matchsize = sizeof(struct xt_conntrack_mtinfo1),
257 .match = conntrack_mt_v1, 230 .match = conntrack_mt_v1,
258 .checkentry = conntrack_mt_check_v1, 231 .checkentry = conntrack_mt_check,
259 .destroy = conntrack_mt_destroy_v1, 232 .destroy = conntrack_mt_destroy,
260 .me = THIS_MODULE, 233 .me = THIS_MODULE,
261 }, 234 },
262 { 235 {
@@ -264,7 +237,7 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = {
264 .revision = 2, 237 .revision = 2,
265 .family = NFPROTO_UNSPEC, 238 .family = NFPROTO_UNSPEC,
266 .matchsize = sizeof(struct xt_conntrack_mtinfo2), 239 .matchsize = sizeof(struct xt_conntrack_mtinfo2),
267 .match = conntrack_mt, 240 .match = conntrack_mt_v2,
268 .checkentry = conntrack_mt_check, 241 .checkentry = conntrack_mt_check,
269 .destroy = conntrack_mt_destroy, 242 .destroy = conntrack_mt_destroy,
270 .me = THIS_MODULE, 243 .me = THIS_MODULE,