Skip to content

Commit 109bf4c

Browse files
committed
Merge tag 'nf-next-23-12-22' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
Pablo Neira Ayuso says: ==================== netfilter pull request 23-12-22 The following patchset contains Netfilter updates for net-next: 1) Add locking for NFT_MSG_GETSETELEM_RESET requests, to address a race scenario with two concurrent processes running a dump-and-reset which exposes negative counters to userspace, from Phil Sutter. 2) Use GFP_KERNEL in pipapo GC, from Florian Westphal. 3) Reorder nf_flowtable struct members, place the read-mostly parts accessed by the datapath first. From Florian Westphal. 4) Set on dead flag for NFT_MSG_NEWSET in abort path, from Florian Westphal. 5) Support filtering zone in ctnetlink, from Felix Huettner. 6) Bail out if user tries to redefine an existing chain with different type in nf_tables. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 240436c + aaba7dd commit 109bf4c

File tree

7 files changed

+567
-38
lines changed

7 files changed

+567
-38
lines changed

include/net/netfilter/nf_flow_table.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,13 @@ enum nf_flowtable_flags {
7474
};
7575

7676
struct nf_flowtable {
77-
struct list_head list;
78-
struct rhashtable rhashtable;
79-
int priority;
77+
unsigned int flags; /* readonly in datapath */
78+
int priority; /* control path (padding hole) */
79+
struct rhashtable rhashtable; /* datapath, read-mostly members come first */
80+
81+
struct list_head list; /* slowpath parts */
8082
const struct nf_flowtable_type *type;
8183
struct delayed_work gc_work;
82-
unsigned int flags;
8384
struct flow_block flow_block;
8485
struct rw_semaphore flow_block_lock; /* Guards flow_block */
8586
possible_net_t net;

net/netfilter/nf_conntrack_netlink.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -992,13 +992,13 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
992992
if (err)
993993
goto err_filter;
994994

995-
if (!cda[CTA_FILTER])
996-
return filter;
997-
998995
err = ctnetlink_parse_zone(cda[CTA_ZONE], &filter->zone);
999996
if (err < 0)
1000997
goto err_filter;
1001998

999+
if (!cda[CTA_FILTER])
1000+
return filter;
1001+
10021002
err = ctnetlink_parse_filter(cda[CTA_FILTER], filter);
10031003
if (err < 0)
10041004
goto err_filter;
@@ -1043,7 +1043,7 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
10431043

10441044
static bool ctnetlink_needs_filter(u8 family, const struct nlattr * const *cda)
10451045
{
1046-
return family || cda[CTA_MARK] || cda[CTA_FILTER] || cda[CTA_STATUS];
1046+
return family || cda[CTA_MARK] || cda[CTA_FILTER] || cda[CTA_STATUS] || cda[CTA_ZONE];
10471047
}
10481048

10491049
static int ctnetlink_start(struct netlink_callback *cb)
@@ -1148,6 +1148,10 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
11481148
if (filter->family && nf_ct_l3num(ct) != filter->family)
11491149
goto ignore_entry;
11501150

1151+
if (filter->zone.id != NF_CT_DEFAULT_ZONE_ID &&
1152+
!nf_ct_zone_equal_any(ct, &filter->zone))
1153+
goto ignore_entry;
1154+
11511155
if (filter->orig_flags) {
11521156
tuple = nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL);
11531157
if (!ctnetlink_filter_match_tuple(&filter->orig, tuple,

net/netfilter/nf_tables_api.c

Lines changed: 119 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,7 +2261,16 @@ static int nft_chain_parse_hook(struct net *net,
22612261
return -EOPNOTSUPP;
22622262
}
22632263

2264-
type = basechain->type;
2264+
if (nla[NFTA_CHAIN_TYPE]) {
2265+
type = __nf_tables_chain_type_lookup(nla[NFTA_CHAIN_TYPE],
2266+
family);
2267+
if (!type) {
2268+
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TYPE]);
2269+
return -ENOENT;
2270+
}
2271+
} else {
2272+
type = basechain->type;
2273+
}
22652274
}
22662275

22672276
if (!try_module_get(type->owner)) {
@@ -5817,10 +5826,6 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
58175826
nla_nest_end(skb, nest);
58185827
nlmsg_end(skb, nlh);
58195828

5820-
if (dump_ctx->reset && args.iter.count > args.iter.skip)
5821-
audit_log_nft_set_reset(table, cb->seq,
5822-
args.iter.count - args.iter.skip);
5823-
58245829
rcu_read_unlock();
58255830

58265831
if (args.iter.err && args.iter.err != -EMSGSIZE)
@@ -5836,6 +5841,26 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
58365841
return -ENOSPC;
58375842
}
58385843

5844+
static int nf_tables_dumpreset_set(struct sk_buff *skb,
5845+
struct netlink_callback *cb)
5846+
{
5847+
struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk));
5848+
struct nft_set_dump_ctx *dump_ctx = cb->data;
5849+
int ret, skip = cb->args[0];
5850+
5851+
mutex_lock(&nft_net->commit_mutex);
5852+
5853+
ret = nf_tables_dump_set(skb, cb);
5854+
5855+
if (cb->args[0] > skip)
5856+
audit_log_nft_set_reset(dump_ctx->ctx.table, cb->seq,
5857+
cb->args[0] - skip);
5858+
5859+
mutex_unlock(&nft_net->commit_mutex);
5860+
5861+
return ret;
5862+
}
5863+
58395864
static int nf_tables_dump_set_start(struct netlink_callback *cb)
58405865
{
58415866
struct nft_set_dump_ctx *dump_ctx = cb->data;
@@ -5910,7 +5935,7 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
59105935
return 0;
59115936
}
59125937

5913-
static int nft_setelem_parse_key(struct nft_ctx *ctx, struct nft_set *set,
5938+
static int nft_setelem_parse_key(struct nft_ctx *ctx, const struct nft_set *set,
59145939
struct nft_data *key, struct nlattr *attr)
59155940
{
59165941
struct nft_data_desc desc = {
@@ -5963,7 +5988,7 @@ static void *nft_setelem_catchall_get(const struct net *net,
59635988
return priv;
59645989
}
59655990

5966-
static int nft_setelem_get(struct nft_ctx *ctx, struct nft_set *set,
5991+
static int nft_setelem_get(struct nft_ctx *ctx, const struct nft_set *set,
59675992
struct nft_set_elem *elem, u32 flags)
59685993
{
59695994
void *priv;
@@ -5982,7 +6007,7 @@ static int nft_setelem_get(struct nft_ctx *ctx, struct nft_set *set,
59826007
return 0;
59836008
}
59846009

5985-
static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
6010+
static int nft_get_set_elem(struct nft_ctx *ctx, const struct nft_set *set,
59866011
const struct nlattr *attr, bool reset)
59876012
{
59886013
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
@@ -6039,21 +6064,18 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
60396064
return err;
60406065
}
60416066

6042-
/* called with rcu_read_lock held */
6043-
static int nf_tables_getsetelem(struct sk_buff *skb,
6044-
const struct nfnl_info *info,
6045-
const struct nlattr * const nla[])
6067+
static int nft_set_dump_ctx_init(struct nft_set_dump_ctx *dump_ctx,
6068+
const struct sk_buff *skb,
6069+
const struct nfnl_info *info,
6070+
const struct nlattr * const nla[],
6071+
bool reset)
60466072
{
60476073
struct netlink_ext_ack *extack = info->extack;
60486074
u8 genmask = nft_genmask_cur(info->net);
60496075
u8 family = info->nfmsg->nfgen_family;
6050-
int rem, err = 0, nelems = 0;
60516076
struct net *net = info->net;
60526077
struct nft_table *table;
60536078
struct nft_set *set;
6054-
struct nlattr *attr;
6055-
struct nft_ctx ctx;
6056-
bool reset = false;
60576079

60586080
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
60596081
genmask, 0);
@@ -6068,10 +6090,22 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
60686090
return PTR_ERR(set);
60696091
}
60706092

6071-
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
6093+
nft_ctx_init(&dump_ctx->ctx, net, skb,
6094+
info->nlh, family, table, NULL, nla);
6095+
dump_ctx->set = set;
6096+
dump_ctx->reset = reset;
6097+
return 0;
6098+
}
60726099

6073-
if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET)
6074-
reset = true;
6100+
/* called with rcu_read_lock held */
6101+
static int nf_tables_getsetelem(struct sk_buff *skb,
6102+
const struct nfnl_info *info,
6103+
const struct nlattr * const nla[])
6104+
{
6105+
struct netlink_ext_ack *extack = info->extack;
6106+
struct nft_set_dump_ctx dump_ctx;
6107+
struct nlattr *attr;
6108+
int rem, err = 0;
60756109

60766110
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
60776111
struct netlink_dump_control c = {
@@ -6080,31 +6114,87 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
60806114
.done = nf_tables_dump_set_done,
60816115
.module = THIS_MODULE,
60826116
};
6083-
struct nft_set_dump_ctx dump_ctx = {
6084-
.set = set,
6085-
.ctx = ctx,
6086-
.reset = reset,
6117+
6118+
err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false);
6119+
if (err)
6120+
return err;
6121+
6122+
c.data = &dump_ctx;
6123+
return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
6124+
}
6125+
6126+
if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
6127+
return -EINVAL;
6128+
6129+
err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false);
6130+
if (err)
6131+
return err;
6132+
6133+
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
6134+
err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, false);
6135+
if (err < 0) {
6136+
NL_SET_BAD_ATTR(extack, attr);
6137+
break;
6138+
}
6139+
}
6140+
6141+
return err;
6142+
}
6143+
6144+
static int nf_tables_getsetelem_reset(struct sk_buff *skb,
6145+
const struct nfnl_info *info,
6146+
const struct nlattr * const nla[])
6147+
{
6148+
struct nftables_pernet *nft_net = nft_pernet(info->net);
6149+
struct netlink_ext_ack *extack = info->extack;
6150+
struct nft_set_dump_ctx dump_ctx;
6151+
int rem, err = 0, nelems = 0;
6152+
struct nlattr *attr;
6153+
6154+
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
6155+
struct netlink_dump_control c = {
6156+
.start = nf_tables_dump_set_start,
6157+
.dump = nf_tables_dumpreset_set,
6158+
.done = nf_tables_dump_set_done,
6159+
.module = THIS_MODULE,
60876160
};
60886161

6162+
err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true);
6163+
if (err)
6164+
return err;
6165+
60896166
c.data = &dump_ctx;
60906167
return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
60916168
}
60926169

60936170
if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
60946171
return -EINVAL;
60956172

6173+
if (!try_module_get(THIS_MODULE))
6174+
return -EINVAL;
6175+
rcu_read_unlock();
6176+
mutex_lock(&nft_net->commit_mutex);
6177+
rcu_read_lock();
6178+
6179+
err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true);
6180+
if (err)
6181+
goto out_unlock;
6182+
60966183
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
6097-
err = nft_get_set_elem(&ctx, set, attr, reset);
6184+
err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, true);
60986185
if (err < 0) {
60996186
NL_SET_BAD_ATTR(extack, attr);
61006187
break;
61016188
}
61026189
nelems++;
61036190
}
6191+
audit_log_nft_set_reset(dump_ctx.ctx.table, nft_net->base_seq, nelems);
61046192

6105-
if (reset)
6106-
audit_log_nft_set_reset(table, nft_pernet(net)->base_seq,
6107-
nelems);
6193+
out_unlock:
6194+
rcu_read_unlock();
6195+
mutex_unlock(&nft_net->commit_mutex);
6196+
rcu_read_lock();
6197+
module_put(THIS_MODULE);
61086198

61096199
return err;
61106200
}
@@ -9078,7 +9168,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
90789168
.policy = nft_set_elem_list_policy,
90799169
},
90809170
[NFT_MSG_GETSETELEM_RESET] = {
9081-
.call = nf_tables_getsetelem,
9171+
.call = nf_tables_getsetelem_reset,
90829172
.type = NFNL_CB_RCU,
90839173
.attr_count = NFTA_SET_ELEM_LIST_MAX,
90849174
.policy = nft_set_elem_list_policy,
@@ -10383,6 +10473,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
1038310473
nft_trans_destroy(trans);
1038410474
break;
1038510475
}
10476+
nft_trans_set(trans)->dead = 1;
1038610477
list_del_rcu(&nft_trans_set(trans)->list);
1038710478
break;
1038810479
case NFT_MSG_DELSET:

net/netfilter/nft_set_pipapo.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,7 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
15971597
if (nft_set_elem_expired(&e->ext)) {
15981598
priv->dirty = true;
15991599

1600-
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
1600+
gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
16011601
if (!gc)
16021602
return;
16031603

tools/testing/selftests/netfilter/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
nf-queue
33
connect_close
44
audit_logread
5+
conntrack_dump_flush
6+
sctp_collision

tools/testing/selftests/netfilter/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ HOSTPKG_CONFIG := pkg-config
1414
CFLAGS += $(shell $(HOSTPKG_CONFIG) --cflags libmnl 2>/dev/null)
1515
LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl)
1616

17-
TEST_GEN_FILES = nf-queue connect_close audit_logread sctp_collision
17+
TEST_GEN_FILES = nf-queue connect_close audit_logread sctp_collision \
18+
conntrack_dump_flush
1819

1920
include ../lib.mk

0 commit comments

Comments
 (0)