Skip to content

Commit

Permalink
Merge tag 'nf-next-24-08-23' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/netfilter/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following batch contains Netfilter updates for net-next:

Patch #1 fix checksum calculation in nfnetlink_queue with SCTP,
	 segment GSO packet since skb_zerocopy() does not support
	 GSO_BY_FRAGS, from Antonio Ojea.

Patch #2 extend nfnetlink_queue coverage to handle SCTP packets,
	 from Antonio Ojea.

Patch #3 uses consume_skb() instead of kfree_skb() in nfnetlink,
         from Donald Hunter.

Patch #4 adds a dedicate commit list for sets to speed up
	 intra-transaction lookups, from Florian Westphal.

Patch #5 skips removal of element from abort path for the pipapo
         backend, ditching the shadow copy of this datastructure
	 is sufficient.

Patch #6 moves nf_ct_netns_get() out of nf_conncount_init() to
	 let users of conncoiunt decide when to enable conntrack,
	 this is needed by openvswitch, from Xin Long.

Patch #7 pass context to all nft_parse_register_load() in
	 preparation for the next patch.

Patches #8 and #9 reject loads from uninitialized registers from
	 control plane to remove register initialization from
	 datapath. From Florian Westphal.

* tag 'nf-next-24-08-23' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next:
  netfilter: nf_tables: don't initialize registers in nft_do_chain()
  netfilter: nf_tables: allow loads only when register is initialized
  netfilter: nf_tables: pass context structure to nft_parse_register_load
  netfilter: move nf_ct_netns_get out of nf_conncount_init
  netfilter: nf_tables: do not remove elements if set backend implements .abort
  netfilter: nf_tables: store new sets in dedicated list
  netfilter: nfnetlink: convert kfree_skb to consume_skb
  selftests: netfilter: nft_queue.sh: sctp coverage
  netfilter: nfnetlink_queue: unbreak SCTP traffic
====================

Link: https://patch.msgid.link/20240822221939.157858-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
kuba-moo committed Aug 26, 2024
2 parents 18aaa82 + c88baab commit b2ede25
Show file tree
Hide file tree
Showing 34 changed files with 226 additions and 84 deletions.
6 changes: 2 additions & 4 deletions include/net/netfilter/nf_conntrack_count.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ struct nf_conncount_list {
unsigned int count; /* length of list */
};

struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family,
unsigned int keylen);
void nf_conncount_destroy(struct net *net, unsigned int family,
struct nf_conncount_data *data);
struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen);
void nf_conncount_destroy(struct net *net, struct nf_conncount_data *data);

unsigned int nf_conncount_count(struct net *net,
struct nf_conncount_data *data,
Expand Down
6 changes: 5 additions & 1 deletion include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ struct nft_ctx {
u8 family;
u8 level;
bool report;
DECLARE_BITMAP(reg_inited, NFT_REG32_NUM);
};

enum nft_data_desc_flags {
Expand Down Expand Up @@ -254,7 +255,8 @@ static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);

int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len);
int nft_parse_register_load(const struct nft_ctx *ctx,
const struct nlattr *attr, u8 *sreg, u32 len);
int nft_parse_register_store(const struct nft_ctx *ctx,
const struct nlattr *attr, u8 *dreg,
const struct nft_data *data,
Expand Down Expand Up @@ -1674,6 +1676,7 @@ struct nft_trans_rule {

struct nft_trans_set {
struct nft_trans_binding nft_trans_binding;
struct list_head list_trans_newset;
struct nft_set *set;
u32 set_id;
u32 gc_int;
Expand Down Expand Up @@ -1875,6 +1878,7 @@ static inline int nft_request_module(struct net *net, const char *fmt, ...) { re
struct nftables_pernet {
struct list_head tables;
struct list_head commit_list;
struct list_head commit_set_list;
struct list_head binding_list;
struct list_head module_list;
struct list_head notify_list;
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/netfilter/nft_meta_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static int nft_meta_bridge_set_init(const struct nft_ctx *ctx,
}

priv->len = len;
err = nft_parse_register_load(tb[NFTA_META_SREG], &priv->sreg, len);
err = nft_parse_register_load(ctx, tb[NFTA_META_SREG], &priv->sreg, len);
if (err < 0)
return err;

Expand Down
1 change: 1 addition & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -3387,6 +3387,7 @@ int skb_crc32c_csum_help(struct sk_buff *skb)
out:
return ret;
}
EXPORT_SYMBOL(skb_crc32c_csum_help);

__be16 skb_network_protocol(struct sk_buff *skb, int *depth)
{
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/netfilter/nft_dup_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ static int nft_dup_ipv4_init(const struct nft_ctx *ctx,
if (tb[NFTA_DUP_SREG_ADDR] == NULL)
return -EINVAL;

err = nft_parse_register_load(tb[NFTA_DUP_SREG_ADDR], &priv->sreg_addr,
err = nft_parse_register_load(ctx, tb[NFTA_DUP_SREG_ADDR], &priv->sreg_addr,
sizeof(struct in_addr));
if (err < 0)
return err;

if (tb[NFTA_DUP_SREG_DEV])
err = nft_parse_register_load(tb[NFTA_DUP_SREG_DEV],
err = nft_parse_register_load(ctx, tb[NFTA_DUP_SREG_DEV],
&priv->sreg_dev, sizeof(int));

return err;
Expand Down
4 changes: 2 additions & 2 deletions net/ipv6/netfilter/nft_dup_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ static int nft_dup_ipv6_init(const struct nft_ctx *ctx,
if (tb[NFTA_DUP_SREG_ADDR] == NULL)
return -EINVAL;

err = nft_parse_register_load(tb[NFTA_DUP_SREG_ADDR], &priv->sreg_addr,
err = nft_parse_register_load(ctx, tb[NFTA_DUP_SREG_ADDR], &priv->sreg_addr,
sizeof(struct in6_addr));
if (err < 0)
return err;

if (tb[NFTA_DUP_SREG_DEV])
err = nft_parse_register_load(tb[NFTA_DUP_SREG_DEV],
err = nft_parse_register_load(ctx, tb[NFTA_DUP_SREG_DEV],
&priv->sreg_dev, sizeof(int));

return err;
Expand Down
15 changes: 3 additions & 12 deletions net/netfilter/nf_conncount.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,10 @@ unsigned int nf_conncount_count(struct net *net,
}
EXPORT_SYMBOL_GPL(nf_conncount_count);

struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family,
unsigned int keylen)
struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen)
{
struct nf_conncount_data *data;
int ret, i;
int i;

if (keylen % sizeof(u32) ||
keylen / sizeof(u32) > MAX_KEYLEN ||
Expand All @@ -539,12 +538,6 @@ struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family
if (!data)
return ERR_PTR(-ENOMEM);

ret = nf_ct_netns_get(net, family);
if (ret < 0) {
kfree(data);
return ERR_PTR(ret);
}

for (i = 0; i < ARRAY_SIZE(data->root); ++i)
data->root[i] = RB_ROOT;

Expand Down Expand Up @@ -581,13 +574,11 @@ static void destroy_tree(struct rb_root *r)
}
}

void nf_conncount_destroy(struct net *net, unsigned int family,
struct nf_conncount_data *data)
void nf_conncount_destroy(struct net *net, struct nf_conncount_data *data)
{
unsigned int i;

cancel_work_sync(&data->gc_work);
nf_ct_netns_put(net, family);

for (i = 0; i < ARRAY_SIZE(data->root); ++i)
destroy_tree(&data->root[i]);
Expand Down
75 changes: 60 additions & 15 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ static void nft_ctx_init(struct nft_ctx *ctx,
ctx->report = nlmsg_report(nlh);
ctx->flags = nlh->nlmsg_flags;
ctx->seq = nlh->nlmsg_seq;

bitmap_zero(ctx->reg_inited, NFT_REG32_NUM);
}

static struct nft_trans *nft_trans_alloc_gfp(const struct nft_ctx *ctx,
Expand Down Expand Up @@ -393,6 +395,7 @@ static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *tr
{
struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans_binding *binding;
struct nft_trans_set *trans_set;

list_add_tail(&trans->list, &nft_net->commit_list);

Expand All @@ -402,9 +405,13 @@ static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *tr

switch (trans->msg_type) {
case NFT_MSG_NEWSET:
trans_set = nft_trans_container_set(trans);

if (!nft_trans_set_update(trans) &&
nft_set_is_anonymous(nft_trans_set(trans)))
list_add_tail(&binding->binding_list, &nft_net->binding_list);

list_add_tail(&trans_set->list_trans_newset, &nft_net->commit_set_list);
break;
case NFT_MSG_NEWCHAIN:
if (!nft_trans_chain_update(trans) &&
Expand Down Expand Up @@ -611,6 +618,7 @@ static int __nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,

trans_set = nft_trans_container_set(trans);
INIT_LIST_HEAD(&trans_set->nft_trans_binding.binding_list);
INIT_LIST_HEAD(&trans_set->list_trans_newset);

if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] && !desc) {
nft_trans_set_id(trans) =
Expand Down Expand Up @@ -4485,17 +4493,16 @@ static struct nft_set *nft_set_lookup_byid(const struct net *net,
{
struct nftables_pernet *nft_net = nft_pernet(net);
u32 id = ntohl(nla_get_be32(nla));
struct nft_trans *trans;
struct nft_trans_set *trans;

list_for_each_entry(trans, &nft_net->commit_list, list) {
if (trans->msg_type == NFT_MSG_NEWSET) {
struct nft_set *set = nft_trans_set(trans);
/* its likely the id we need is at the tail, not at start */
list_for_each_entry_reverse(trans, &nft_net->commit_set_list, list_trans_newset) {
struct nft_set *set = trans->set;

if (id == nft_trans_set_id(trans) &&
set->table == table &&
nft_active_genmask(set, genmask))
return set;
}
if (id == trans->set_id &&
set->table == table &&
nft_active_genmask(set, genmask))
return set;
}
return ERR_PTR(-ENOENT);
}
Expand Down Expand Up @@ -10447,6 +10454,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
break;
case NFT_MSG_NEWSET:
list_del(&nft_trans_container_set(trans)->list_trans_newset);
if (nft_trans_set_update(trans)) {
struct nft_set *set = nft_trans_set(trans);

Expand Down Expand Up @@ -10755,6 +10763,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSET:
list_del(&nft_trans_container_set(trans)->list_trans_newset);
if (nft_trans_set_update(trans)) {
nft_trans_destroy(trans);
break;
Expand Down Expand Up @@ -10782,7 +10791,10 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
break;
}
te = nft_trans_container_elem(trans);
nft_setelem_remove(net, te->set, te->elem_priv);
if (!te->set->ops->abort ||
nft_setelem_is_catchall(te->set, te->elem_priv))
nft_setelem_remove(net, te->set, te->elem_priv);

if (!nft_setelem_is_catchall(te->set, te->elem_priv))
atomic_dec(&te->set->nelems);

Expand Down Expand Up @@ -10850,6 +10862,8 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
}
}

WARN_ON_ONCE(!list_empty(&nft_net->commit_set_list));

nft_set_abort_update(&set_update_list);

synchronize_rcu();
Expand Down Expand Up @@ -11026,10 +11040,11 @@ static int nft_validate_register_load(enum nft_registers reg, unsigned int len)
return 0;
}

int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len)
int nft_parse_register_load(const struct nft_ctx *ctx,
const struct nlattr *attr, u8 *sreg, u32 len)
{
u32 reg;
int err;
int err, invalid_reg;
u32 reg, next_register;

err = nft_parse_register(attr, &reg);
if (err < 0)
Expand All @@ -11039,11 +11054,36 @@ int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len)
if (err < 0)
return err;

next_register = DIV_ROUND_UP(len, NFT_REG32_SIZE) + reg;

/* Can't happen: nft_validate_register_load() should have failed */
if (WARN_ON_ONCE(next_register > NFT_REG32_NUM))
return -EINVAL;

/* find first register that did not see an earlier store. */
invalid_reg = find_next_zero_bit(ctx->reg_inited, NFT_REG32_NUM, reg);

/* invalid register within the range that we're loading from? */
if (invalid_reg < next_register)
return -ENODATA;

*sreg = reg;
return 0;
}
EXPORT_SYMBOL_GPL(nft_parse_register_load);

static void nft_saw_register_store(const struct nft_ctx *__ctx,
int reg, unsigned int len)
{
unsigned int registers = DIV_ROUND_UP(len, NFT_REG32_SIZE);
struct nft_ctx *ctx = (struct nft_ctx *)__ctx;

if (WARN_ON_ONCE(len == 0 || reg < 0))
return;

bitmap_set(ctx->reg_inited, reg, registers);
}

static int nft_validate_register_store(const struct nft_ctx *ctx,
enum nft_registers reg,
const struct nft_data *data,
Expand All @@ -11065,7 +11105,7 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
return err;
}

return 0;
break;
default:
if (type != NFT_DATA_VALUE)
return -EINVAL;
Expand All @@ -11078,8 +11118,11 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
sizeof_field(struct nft_regs, data))
return -ERANGE;

return 0;
break;
}

nft_saw_register_store(ctx, reg, len);
return 0;
}

int nft_parse_register_store(const struct nft_ctx *ctx,
Expand Down Expand Up @@ -11519,6 +11562,7 @@ static int __net_init nf_tables_init_net(struct net *net)

INIT_LIST_HEAD(&nft_net->tables);
INIT_LIST_HEAD(&nft_net->commit_list);
INIT_LIST_HEAD(&nft_net->commit_set_list);
INIT_LIST_HEAD(&nft_net->binding_list);
INIT_LIST_HEAD(&nft_net->module_list);
INIT_LIST_HEAD(&nft_net->notify_list);
Expand Down Expand Up @@ -11549,6 +11593,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
gc_seq = nft_gc_seq_begin(nft_net);

WARN_ON_ONCE(!list_empty(&nft_net->commit_list));
WARN_ON_ONCE(!list_empty(&nft_net->commit_set_list));

if (!list_empty(&nft_net->module_list))
nf_tables_module_autoload_cleanup(net);
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/nf_tables_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)
const struct net *net = nft_net(pkt);
const struct nft_expr *expr, *last;
const struct nft_rule_dp *rule;
struct nft_regs regs = {};
struct nft_regs regs;
unsigned int stackptr = 0;
struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
bool genbit = READ_ONCE(net->nft.gencursor);
Expand Down
14 changes: 7 additions & 7 deletions net/netfilter/nfnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,27 +402,27 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
{
nfnl_unlock(subsys_id);
netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
return kfree_skb(skb);
return consume_skb(skb);
}
}

if (!ss->valid_genid || !ss->commit || !ss->abort) {
nfnl_unlock(subsys_id);
netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
return kfree_skb(skb);
return consume_skb(skb);
}

if (!try_module_get(ss->owner)) {
nfnl_unlock(subsys_id);
netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
return kfree_skb(skb);
return consume_skb(skb);
}

if (!ss->valid_genid(net, genid)) {
module_put(ss->owner);
nfnl_unlock(subsys_id);
netlink_ack(oskb, nlh, -ERESTART, NULL);
return kfree_skb(skb);
return consume_skb(skb);
}

nfnl_unlock(subsys_id);
Expand Down Expand Up @@ -567,7 +567,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
if (status & NFNL_BATCH_REPLAY) {
ss->abort(net, oskb, NFNL_ABORT_AUTOLOAD);
nfnl_err_reset(&err_list);
kfree_skb(skb);
consume_skb(skb);
module_put(ss->owner);
goto replay;
} else if (status == NFNL_BATCH_DONE) {
Expand All @@ -593,15 +593,15 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
err = ss->abort(net, oskb, abort_action);
if (err == -EAGAIN) {
nfnl_err_reset(&err_list);
kfree_skb(skb);
consume_skb(skb);
module_put(ss->owner);
status |= NFNL_BATCH_FAILURE;
goto replay_abort;
}
}

nfnl_err_deliver(&err_list, oskb);
kfree_skb(skb);
consume_skb(skb);
module_put(ss->owner);
}

Expand Down
Loading

0 comments on commit b2ede25

Please sign in to comment.