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

netfilter: nf_tables: validate NFPROTO_* family

Several expressions explicitly refer to NF_INET_* hook definitions
from expr->ops->validate, however, family is not validated.

Bail out with EOPNOTSUPP in case they are used from unsupported
families.

Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables")
Fixes: a3c90f7a2323 ("netfilter: nf_tables: flow offload expression")
Fixes: 2fa841938c64 ("netfilter: nf_tables: introduce routing expression")
Fixes: 554ced0a6e29 ("netfilter: nf_tables: add support for native socket matching")
Fixes: ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support")
Fixes: 4ed8eb6570a4 ("netfilter: nf_tables: Add native tproxy support")
Fixes: 6c47260250fc ("netfilter: nf_tables: add xfrm expression")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+47 -2
+12
net/netfilter/nft_compat.c
··· 350 350 unsigned int hook_mask = 0; 351 351 int ret; 352 352 353 + if (ctx->family != NFPROTO_IPV4 && 354 + ctx->family != NFPROTO_IPV6 && 355 + ctx->family != NFPROTO_BRIDGE && 356 + ctx->family != NFPROTO_ARP) 357 + return -EOPNOTSUPP; 358 + 353 359 if (nft_is_base_chain(ctx->chain)) { 354 360 const struct nft_base_chain *basechain = 355 361 nft_base_chain(ctx->chain); ··· 600 594 struct xt_match *match = expr->ops->data; 601 595 unsigned int hook_mask = 0; 602 596 int ret; 597 + 598 + if (ctx->family != NFPROTO_IPV4 && 599 + ctx->family != NFPROTO_IPV6 && 600 + ctx->family != NFPROTO_BRIDGE && 601 + ctx->family != NFPROTO_ARP) 602 + return -EOPNOTSUPP; 603 603 604 604 if (nft_is_base_chain(ctx->chain)) { 605 605 const struct nft_base_chain *basechain =
+5
net/netfilter/nft_flow_offload.c
··· 384 384 { 385 385 unsigned int hook_mask = (1 << NF_INET_FORWARD); 386 386 387 + if (ctx->family != NFPROTO_IPV4 && 388 + ctx->family != NFPROTO_IPV6 && 389 + ctx->family != NFPROTO_INET) 390 + return -EOPNOTSUPP; 391 + 387 392 return nft_chain_validate_hooks(ctx->chain, hook_mask); 388 393 } 389 394
+5
net/netfilter/nft_nat.c
··· 143 143 struct nft_nat *priv = nft_expr_priv(expr); 144 144 int err; 145 145 146 + if (ctx->family != NFPROTO_IPV4 && 147 + ctx->family != NFPROTO_IPV6 && 148 + ctx->family != NFPROTO_INET) 149 + return -EOPNOTSUPP; 150 + 146 151 err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); 147 152 if (err < 0) 148 153 return err;
+5
net/netfilter/nft_rt.c
··· 166 166 const struct nft_rt *priv = nft_expr_priv(expr); 167 167 unsigned int hooks; 168 168 169 + if (ctx->family != NFPROTO_IPV4 && 170 + ctx->family != NFPROTO_IPV6 && 171 + ctx->family != NFPROTO_INET) 172 + return -EOPNOTSUPP; 173 + 169 174 switch (priv->key) { 170 175 case NFT_RT_NEXTHOP4: 171 176 case NFT_RT_NEXTHOP6:
+5
net/netfilter/nft_socket.c
··· 242 242 const struct nft_expr *expr, 243 243 const struct nft_data **data) 244 244 { 245 + if (ctx->family != NFPROTO_IPV4 && 246 + ctx->family != NFPROTO_IPV6 && 247 + ctx->family != NFPROTO_INET) 248 + return -EOPNOTSUPP; 249 + 245 250 return nft_chain_validate_hooks(ctx->chain, 246 251 (1 << NF_INET_PRE_ROUTING) | 247 252 (1 << NF_INET_LOCAL_IN) |
+5 -2
net/netfilter/nft_synproxy.c
··· 186 186 break; 187 187 #endif 188 188 case NFPROTO_INET: 189 - case NFPROTO_BRIDGE: 190 189 err = nf_synproxy_ipv4_init(snet, ctx->net); 191 190 if (err) 192 191 goto nf_ct_failure; ··· 218 219 break; 219 220 #endif 220 221 case NFPROTO_INET: 221 - case NFPROTO_BRIDGE: 222 222 nf_synproxy_ipv4_fini(snet, ctx->net); 223 223 nf_synproxy_ipv6_fini(snet, ctx->net); 224 224 break; ··· 251 253 const struct nft_expr *expr, 252 254 const struct nft_data **data) 253 255 { 256 + if (ctx->family != NFPROTO_IPV4 && 257 + ctx->family != NFPROTO_IPV6 && 258 + ctx->family != NFPROTO_INET) 259 + return -EOPNOTSUPP; 260 + 254 261 return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) | 255 262 (1 << NF_INET_FORWARD)); 256 263 }
+5
net/netfilter/nft_tproxy.c
··· 316 316 const struct nft_expr *expr, 317 317 const struct nft_data **data) 318 318 { 319 + if (ctx->family != NFPROTO_IPV4 && 320 + ctx->family != NFPROTO_IPV6 && 321 + ctx->family != NFPROTO_INET) 322 + return -EOPNOTSUPP; 323 + 319 324 return nft_chain_validate_hooks(ctx->chain, 1 << NF_INET_PRE_ROUTING); 320 325 } 321 326
+5
net/netfilter/nft_xfrm.c
··· 235 235 const struct nft_xfrm *priv = nft_expr_priv(expr); 236 236 unsigned int hooks; 237 237 238 + if (ctx->family != NFPROTO_IPV4 && 239 + ctx->family != NFPROTO_IPV6 && 240 + ctx->family != NFPROTO_INET) 241 + return -EOPNOTSUPP; 242 + 238 243 switch (priv->dir) { 239 244 case XFRM_POLICY_IN: 240 245 hooks = (1 << NF_INET_FORWARD) |