Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter patches for your net tree:

1) Fix NULL pointer dereference from nf_nat_decode_session() if NAT is
   not loaded, from Prashant Bhole.

2) Fix socket extension module autoload.

3) Don't bogusly reject sets with the NFT_SET_EVAL flag set on from
   the dynset extension.

4) Fix races with nf_tables module removal and netns exit path,
   patches from Florian Westphal.

5) Don't hit BUG_ON if jumpstack goes too deep, instead hit
   WARN_ON_ONCE, from Taehee Yoo.

6) Another NULL pointer dereference from ctnetlink, again if NAT is
   not loaded, from Florian Westphal.

7) Fix x_tables match list corruption in xt_connmark module removal
   path, also from Florian.

8) nf_conncount doesn't properly deal with conntrack zones, hence
   garbage collector may get rid of entries in a different zone.
   From Yi-Hung Wei.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Jun 13, 2018
2 parents 57f230a + 21ba884 commit 60d061e
Show file tree
Hide file tree
Showing 13 changed files with 52 additions and 23 deletions.
2 changes: 1 addition & 1 deletion include/linux/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)

rcu_read_lock();
nat_hook = rcu_dereference(nf_nat_hook);
if (nat_hook->decode_session)
if (nat_hook && nat_hook->decode_session)
nat_hook->decode_session(skb, fl);
rcu_read_unlock();
#endif
Expand Down
3 changes: 2 additions & 1 deletion include/net/netfilter/nf_conntrack_count.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,
bool *addit);

bool nf_conncount_add(struct hlist_head *head,
const struct nf_conntrack_tuple *tuple);
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone);

void nf_conncount_cache_free(struct hlist_head *hhead);

Expand Down
2 changes: 1 addition & 1 deletion include/uapi/linux/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ enum nft_rule_compat_attributes {
* @NFT_SET_INTERVAL: set contains intervals
* @NFT_SET_MAP: set is used as a dictionary
* @NFT_SET_TIMEOUT: set uses timeouts
* @NFT_SET_EVAL: set contains expressions for evaluation
* @NFT_SET_EVAL: set can be updated from the evaluation path
* @NFT_SET_OBJECT: set contains stateful objects
*/
enum nft_set_flags {
Expand Down
13 changes: 9 additions & 4 deletions net/netfilter/nf_conncount.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
struct nf_conncount_tuple {
struct hlist_node node;
struct nf_conntrack_tuple tuple;
struct nf_conntrack_zone zone;
};

struct nf_conncount_rb {
Expand Down Expand Up @@ -80,14 +81,16 @@ static int key_diff(const u32 *a, const u32 *b, unsigned int klen)
}

bool nf_conncount_add(struct hlist_head *head,
const struct nf_conntrack_tuple *tuple)
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone)
{
struct nf_conncount_tuple *conn;

conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC);
if (conn == NULL)
return false;
conn->tuple = *tuple;
conn->zone = *zone;
hlist_add_head(&conn->node, head);
return true;
}
Expand All @@ -108,7 +111,7 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,

/* check the saved connections */
hlist_for_each_entry_safe(conn, n, head, node) {
found = nf_conntrack_find_get(net, zone, &conn->tuple);
found = nf_conntrack_find_get(net, &conn->zone, &conn->tuple);
if (found == NULL) {
hlist_del(&conn->node);
kmem_cache_free(conncount_conn_cachep, conn);
Expand All @@ -117,7 +120,8 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,

found_ct = nf_ct_tuplehash_to_ctrack(found);

if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple)) {
if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple) &&
nf_ct_zone_equal(found_ct, zone, zone->dir)) {
/*
* Just to be sure we have it only once in the list.
* We should not see tuples twice unless someone hooks
Expand Down Expand Up @@ -196,7 +200,7 @@ count_tree(struct net *net, struct rb_root *root,
if (!addit)
return count;

if (!nf_conncount_add(&rbconn->hhead, tuple))
if (!nf_conncount_add(&rbconn->hhead, tuple, zone))
return 0; /* hotdrop */

return count + 1;
Expand Down Expand Up @@ -238,6 +242,7 @@ count_tree(struct net *net, struct rb_root *root,
}

conn->tuple = *tuple;
conn->zone = *zone;
memcpy(rbconn->key, key, sizeof(u32) * keylen);

INIT_HLIST_HEAD(&rbconn->hhead);
Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/nf_conntrack_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1446,7 +1446,8 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
}
nfnl_lock(NFNL_SUBSYS_CTNETLINK);
rcu_read_lock();
if (nat_hook->parse_nat_setup)
nat_hook = rcu_dereference(nf_nat_hook);
if (nat_hook)
return -EAGAIN;
#endif
return -EOPNOTSUPP;
Expand Down
25 changes: 19 additions & 6 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -5837,18 +5837,23 @@ static int nf_tables_flowtable_event(struct notifier_block *this,
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct nft_flowtable *flowtable;
struct nft_table *table;
struct net *net;

if (event != NETDEV_UNREGISTER)
return 0;

net = maybe_get_net(dev_net(dev));
if (!net)
return 0;

nfnl_lock(NFNL_SUBSYS_NFTABLES);
list_for_each_entry(table, &dev_net(dev)->nft.tables, list) {
list_for_each_entry(table, &net->nft.tables, list) {
list_for_each_entry(flowtable, &table->flowtables, list) {
nft_flowtable_event(event, dev, flowtable);
}
}
nfnl_unlock(NFNL_SUBSYS_NFTABLES);

put_net(net);
return NOTIFY_DONE;
}

Expand Down Expand Up @@ -6439,7 +6444,7 @@ static void nf_tables_abort_release(struct nft_trans *trans)
kfree(trans);
}

static int nf_tables_abort(struct net *net, struct sk_buff *skb)
static int __nf_tables_abort(struct net *net)
{
struct nft_trans *trans, *next;
struct nft_trans_elem *te;
Expand Down Expand Up @@ -6555,6 +6560,11 @@ static void nf_tables_cleanup(struct net *net)
nft_validate_state_update(net, NFT_VALIDATE_SKIP);
}

static int nf_tables_abort(struct net *net, struct sk_buff *skb)
{
return __nf_tables_abort(net);
}

static bool nf_tables_valid_genid(struct net *net, u32 genid)
{
return net->nft.base_seq == genid;
Expand Down Expand Up @@ -7149,9 +7159,12 @@ static int __net_init nf_tables_init_net(struct net *net)

static void __net_exit nf_tables_exit_net(struct net *net)
{
nfnl_lock(NFNL_SUBSYS_NFTABLES);
if (!list_empty(&net->nft.commit_list))
__nf_tables_abort(net);
__nft_release_tables(net);
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
WARN_ON_ONCE(!list_empty(&net->nft.tables));
WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
}

static struct pernet_operations nf_tables_net_ops = {
Expand Down Expand Up @@ -7193,13 +7206,13 @@ static int __init nf_tables_module_init(void)

static void __exit nf_tables_module_exit(void)
{
unregister_pernet_subsys(&nf_tables_net_ops);
nfnetlink_subsys_unregister(&nf_tables_subsys);
unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
nft_chain_filter_fini();
unregister_pernet_subsys(&nf_tables_net_ops);
rcu_barrier();
nf_tables_core_module_exit();
kfree(info);
nft_chain_filter_fini();
}

module_init(nf_tables_module_init);
Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/nf_tables_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)

switch (regs.verdict.code) {
case NFT_JUMP:
BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE))
return NF_DROP;
jumpstack[stackptr].chain = chain;
jumpstack[stackptr].rules = rules + 1;
stackptr++;
Expand Down
10 changes: 7 additions & 3 deletions net/netfilter/nfnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
*/
if (err == -EAGAIN) {
status |= NFNL_BATCH_REPLAY;
goto next;
goto done;
}
}
ack:
Expand All @@ -456,15 +456,19 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err)
status |= NFNL_BATCH_FAILURE;
}
next:

msglen = NLMSG_ALIGN(nlh->nlmsg_len);
if (msglen > skb->len)
msglen = skb->len;
skb_pull(skb, msglen);
}
done:
if (status & NFNL_BATCH_REPLAY) {
ss->abort(net, oskb);
const struct nfnetlink_subsystem *ss2;

ss2 = nfnl_dereference_protected(subsys_id);
if (ss2 == ss)
ss->abort(net, oskb);
nfnl_err_reset(&err_list);
nfnl_unlock(subsys_id);
kfree_skb(skb);
Expand Down
5 changes: 5 additions & 0 deletions net/netfilter/nft_chain_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ static int nf_tables_netdev_event(struct notifier_block *this,
event != NETDEV_CHANGENAME)
return NOTIFY_DONE;

ctx.net = maybe_get_net(ctx.net);
if (!ctx.net)
return NOTIFY_DONE;

nfnl_lock(NFNL_SUBSYS_NFTABLES);
list_for_each_entry(table, &ctx.net->nft.tables, list) {
if (table->family != NFPROTO_NETDEV)
Expand All @@ -334,6 +338,7 @@ static int nf_tables_netdev_event(struct notifier_block *this,
}
}
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
put_net(ctx.net);

return NOTIFY_DONE;
}
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/nft_connlimit.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
if (!addit)
goto out;

if (!nf_conncount_add(&priv->hhead, tuple_ptr)) {
if (!nf_conncount_add(&priv->hhead, tuple_ptr, zone)) {
regs->verdict.code = NF_DROP;
spin_unlock_bh(&priv->lock);
return;
Expand Down
4 changes: 1 addition & 3 deletions net/netfilter/nft_dynset.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
goto err1;
set->ops->gc_init(set);
}

} else if (set->flags & NFT_SET_EVAL)
return -EINVAL;
}

nft_set_ext_prepare(&priv->tmpl);
nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_KEY, set->klen);
Expand Down
1 change: 1 addition & 0 deletions net/netfilter/nft_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,4 @@ module_exit(nft_socket_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Máté Eckl");
MODULE_DESCRIPTION("nf_tables socket match module");
MODULE_ALIAS_NFT_EXPR("socket");
2 changes: 1 addition & 1 deletion net/netfilter/xt_connmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static int __init connmark_mt_init(void)
static void __exit connmark_mt_exit(void)
{
xt_unregister_match(&connmark_mt_reg);
xt_unregister_target(connmark_tg_reg);
xt_unregister_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
}

module_init(connmark_mt_init);
Expand Down

0 comments on commit 60d061e

Please sign in to comment.