Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: x_tables: add context to know if extension runs from nft_compat

Currently, we have four xtables extensions that cannot be used from the
xt over nft compat layer. The problem is that they need real access to
the full blown xt_entry to validate that the rule comes with the right
dependencies. This check was introduced to overcome the lack of
sufficient userspace dependency validation in iptables.

To resolve this problem, this patch introduces a new field to the
xt_tgchk_param structure that tell us if the extension is run from
nft_compat context.

The three affected extensions are:

1) CLUSTERIP, this target has been superseded by xt_cluster. So just
bail out by returning -EINVAL.

2) TCPMSS. Relax the checking when used from nft_compat. If used with
the wrong configuration, it will corrupt !syn packets by adding TCP
MSS option.

3) ebt_stp. Relax the check to make sure it uses the reserved
destination MAC address for STP.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Tested-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>

+19 -2
+2
include/linux/netfilter/x_tables.h
··· 62 62 void *matchinfo; 63 63 unsigned int hook_mask; 64 64 u_int8_t family; 65 + bool nft_compat; 65 66 }; 66 67 67 68 /** ··· 93 92 void *targinfo; 94 93 unsigned int hook_mask; 95 94 u_int8_t family; 95 + bool nft_compat; 96 96 }; 97 97 98 98 /* Target destructor parameters */
+4 -2
net/bridge/netfilter/ebt_stp.c
··· 164 164 !(info->bitmask & EBT_STP_MASK)) 165 165 return -EINVAL; 166 166 /* Make sure the match only receives stp frames */ 167 - if (!ether_addr_equal(e->destmac, bridge_ula) || 168 - !ether_addr_equal(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC)) 167 + if (!par->nft_compat && 168 + (!ether_addr_equal(e->destmac, bridge_ula) || 169 + !ether_addr_equal(e->destmsk, msk) || 170 + !(e->bitmask & EBT_DESTMAC))) 169 171 return -EINVAL; 170 172 171 173 return 0;
+5
net/ipv4/netfilter/ipt_CLUSTERIP.c
··· 367 367 struct clusterip_config *config; 368 368 int ret; 369 369 370 + if (par->nft_compat) { 371 + pr_err("cannot use CLUSTERIP target from nftables compat\n"); 372 + return -EOPNOTSUPP; 373 + } 374 + 370 375 if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && 371 376 cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && 372 377 cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
+2
net/netfilter/nft_compat.c
··· 161 161 par->hook_mask = 0; 162 162 } 163 163 par->family = ctx->afi->family; 164 + par->nft_compat = true; 164 165 } 165 166 166 167 static void target_compat_from_user(struct xt_target *t, void *in, void *out) ··· 378 377 par->hook_mask = 0; 379 378 } 380 379 par->family = ctx->afi->family; 380 + par->nft_compat = true; 381 381 } 382 382 383 383 static void match_compat_from_user(struct xt_match *m, void *in, void *out)
+6
net/netfilter/xt_TCPMSS.c
··· 277 277 "FORWARD, OUTPUT and POSTROUTING hooks\n"); 278 278 return -EINVAL; 279 279 } 280 + if (par->nft_compat) 281 + return 0; 282 + 280 283 xt_ematch_foreach(ematch, e) 281 284 if (find_syn_match(ematch)) 282 285 return 0; ··· 302 299 "FORWARD, OUTPUT and POSTROUTING hooks\n"); 303 300 return -EINVAL; 304 301 } 302 + if (par->nft_compat) 303 + return 0; 304 + 305 305 xt_ematch_foreach(ematch, e) 306 306 if (find_syn_match(ematch)) 307 307 return 0;