Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Unbreak br_netfilter physdev match support, from Florian Westphal. 2) Use GFP_KERNEL_ACCOUNT for stateful/policy objects, from Chen Aotian. 3) Use IS_ENABLED() in nf_reset_trace(), from Florian Westphal. 4) Fix validation of catch-all set element. 5) Tighten requirements for catch-all set elements. * git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_tables: tighten netlink attribute requirements for catch-all elements netfilter: nf_tables: validate catch-all set elements netfilter: nf_tables: fix ifdef to also consider nf_tables=m netfilter: nf_tables: Modify nla_memdup's flag to GFP_KERNEL_ACCOUNT netfilter: br_netfilter: fix recent physdev match breakage ==================== Link: https://lore.kernel.org/r/20230418145048.67270-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
92e8c732d8
|
@ -294,6 +294,7 @@ struct nf_bridge_info {
|
||||||
u8 pkt_otherhost:1;
|
u8 pkt_otherhost:1;
|
||||||
u8 in_prerouting:1;
|
u8 in_prerouting:1;
|
||||||
u8 bridged_dnat:1;
|
u8 bridged_dnat:1;
|
||||||
|
u8 sabotage_in_done:1;
|
||||||
__u16 frag_max_size;
|
__u16 frag_max_size;
|
||||||
struct net_device *physindev;
|
struct net_device *physindev;
|
||||||
|
|
||||||
|
@ -4712,7 +4713,7 @@ static inline void nf_reset_ct(struct sk_buff *skb)
|
||||||
|
|
||||||
static inline void nf_reset_trace(struct sk_buff *skb)
|
static inline void nf_reset_trace(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
|
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || IS_ENABLED(CONFIG_NF_TABLES)
|
||||||
skb->nf_trace = 0;
|
skb->nf_trace = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -4732,7 +4733,7 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src,
|
||||||
dst->_nfct = src->_nfct;
|
dst->_nfct = src->_nfct;
|
||||||
nf_conntrack_get(skb_nfct(src));
|
nf_conntrack_get(skb_nfct(src));
|
||||||
#endif
|
#endif
|
||||||
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
|
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || IS_ENABLED(CONFIG_NF_TABLES)
|
||||||
if (copy)
|
if (copy)
|
||||||
dst->nf_trace = src->nf_trace;
|
dst->nf_trace = src->nf_trace;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1085,6 +1085,10 @@ struct nft_chain {
|
||||||
};
|
};
|
||||||
|
|
||||||
int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain);
|
int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain);
|
||||||
|
int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
|
||||||
|
const struct nft_set_iter *iter,
|
||||||
|
struct nft_set_elem *elem);
|
||||||
|
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set);
|
||||||
|
|
||||||
enum nft_chain_types {
|
enum nft_chain_types {
|
||||||
NFT_CHAIN_T_DEFAULT = 0,
|
NFT_CHAIN_T_DEFAULT = 0,
|
||||||
|
|
|
@ -868,12 +868,17 @@ static unsigned int ip_sabotage_in(void *priv,
|
||||||
{
|
{
|
||||||
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
||||||
|
|
||||||
if (nf_bridge && !nf_bridge->in_prerouting &&
|
if (nf_bridge) {
|
||||||
!netif_is_l3_master(skb->dev) &&
|
if (nf_bridge->sabotage_in_done)
|
||||||
!netif_is_l3_slave(skb->dev)) {
|
return NF_ACCEPT;
|
||||||
nf_bridge_info_free(skb);
|
|
||||||
state->okfn(state->net, state->sk, skb);
|
if (!nf_bridge->in_prerouting &&
|
||||||
return NF_STOLEN;
|
!netif_is_l3_master(skb->dev) &&
|
||||||
|
!netif_is_l3_slave(skb->dev)) {
|
||||||
|
nf_bridge->sabotage_in_done = 1;
|
||||||
|
state->okfn(state->net, state->sk, skb);
|
||||||
|
return NF_STOLEN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
|
@ -3447,6 +3447,64 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
|
||||||
|
const struct nft_set_iter *iter,
|
||||||
|
struct nft_set_elem *elem)
|
||||||
|
{
|
||||||
|
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
|
||||||
|
struct nft_ctx *pctx = (struct nft_ctx *)ctx;
|
||||||
|
const struct nft_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
|
||||||
|
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
data = nft_set_ext_data(ext);
|
||||||
|
switch (data->verdict.code) {
|
||||||
|
case NFT_JUMP:
|
||||||
|
case NFT_GOTO:
|
||||||
|
pctx->level++;
|
||||||
|
err = nft_chain_validate(ctx, data->verdict.chain);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
pctx->level--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nft_set_elem_catchall {
|
||||||
|
struct list_head list;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
void *elem;
|
||||||
|
};
|
||||||
|
|
||||||
|
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set)
|
||||||
|
{
|
||||||
|
u8 genmask = nft_genmask_next(ctx->net);
|
||||||
|
struct nft_set_elem_catchall *catchall;
|
||||||
|
struct nft_set_elem elem;
|
||||||
|
struct nft_set_ext *ext;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
|
||||||
|
ext = nft_set_elem_ext(set, catchall->elem);
|
||||||
|
if (!nft_set_elem_active(ext, genmask))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
elem.priv = catchall->elem;
|
||||||
|
ret = nft_setelem_validate(ctx, set, NULL, &elem);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
|
static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
|
||||||
const struct nft_chain *chain,
|
const struct nft_chain *chain,
|
||||||
const struct nlattr *nla);
|
const struct nlattr *nla);
|
||||||
|
@ -4759,12 +4817,6 @@ err_set_name:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nft_set_elem_catchall {
|
|
||||||
struct list_head list;
|
|
||||||
struct rcu_head rcu;
|
|
||||||
void *elem;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
|
static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
|
||||||
struct nft_set *set)
|
struct nft_set *set)
|
||||||
{
|
{
|
||||||
|
@ -6056,7 +6108,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
|
if (((flags & NFT_SET_ELEM_CATCHALL) && nla[NFTA_SET_ELEM_KEY]) ||
|
||||||
|
(!(flags & NFT_SET_ELEM_CATCHALL) && !nla[NFTA_SET_ELEM_KEY]))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (flags != 0) {
|
if (flags != 0) {
|
||||||
|
@ -7052,7 +7105,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nla[NFTA_OBJ_USERDATA]) {
|
if (nla[NFTA_OBJ_USERDATA]) {
|
||||||
obj->udata = nla_memdup(nla[NFTA_OBJ_USERDATA], GFP_KERNEL);
|
obj->udata = nla_memdup(nla[NFTA_OBJ_USERDATA], GFP_KERNEL_ACCOUNT);
|
||||||
if (obj->udata == NULL)
|
if (obj->udata == NULL)
|
||||||
goto err_userdata;
|
goto err_userdata;
|
||||||
|
|
||||||
|
|
|
@ -199,37 +199,6 @@ nla_put_failure:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nft_lookup_validate_setelem(const struct nft_ctx *ctx,
|
|
||||||
struct nft_set *set,
|
|
||||||
const struct nft_set_iter *iter,
|
|
||||||
struct nft_set_elem *elem)
|
|
||||||
{
|
|
||||||
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
|
|
||||||
struct nft_ctx *pctx = (struct nft_ctx *)ctx;
|
|
||||||
const struct nft_data *data;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
|
|
||||||
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
data = nft_set_ext_data(ext);
|
|
||||||
switch (data->verdict.code) {
|
|
||||||
case NFT_JUMP:
|
|
||||||
case NFT_GOTO:
|
|
||||||
pctx->level++;
|
|
||||||
err = nft_chain_validate(ctx, data->verdict.chain);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
pctx->level--;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nft_lookup_validate(const struct nft_ctx *ctx,
|
static int nft_lookup_validate(const struct nft_ctx *ctx,
|
||||||
const struct nft_expr *expr,
|
const struct nft_expr *expr,
|
||||||
const struct nft_data **d)
|
const struct nft_data **d)
|
||||||
|
@ -245,9 +214,12 @@ static int nft_lookup_validate(const struct nft_ctx *ctx,
|
||||||
iter.skip = 0;
|
iter.skip = 0;
|
||||||
iter.count = 0;
|
iter.count = 0;
|
||||||
iter.err = 0;
|
iter.err = 0;
|
||||||
iter.fn = nft_lookup_validate_setelem;
|
iter.fn = nft_setelem_validate;
|
||||||
|
|
||||||
priv->set->ops->walk(ctx, priv->set, &iter);
|
priv->set->ops->walk(ctx, priv->set, &iter);
|
||||||
|
if (!iter.err)
|
||||||
|
iter.err = nft_set_catchall_validate(ctx, priv->set);
|
||||||
|
|
||||||
if (iter.err < 0)
|
if (iter.err < 0)
|
||||||
return iter.err;
|
return iter.err;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue