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/IPVS fixes for net

The following patchset contains Netfilter/IPVS fixes for net:

1) Fix incorrect sockopts unregistration from error path,
   from Florian Westphal.

2) A few patches to provide better error reporting when missing kernel
   netfilter options are missing in .config.

3) Fix dormant table flag updates.

4) Memleak in IPVS  when adding service with IP_VS_SVC_F_HASHED flag.

* git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf:
  ipvs: ignore IP_VS_SVC_F_HASHED flag when adding service
  netfilter: nf_tables: fix table flag updates
  netfilter: nf_tables: extended netlink error reporting for chain type
  netfilter: nf_tables: missing error reporting for not selected expressions
  netfilter: conntrack: unregister ipv4 sockopts on error unwind
====================

Link: https://lore.kernel.org/r/20210527190115.98503-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed May 27, 2021
2 parents fb91702 + 56e4ee8 commit 44991d6
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 35 deletions.
6 changes: 0 additions & 6 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -1506,16 +1506,10 @@ struct nft_trans_chain {

struct nft_trans_table {
bool update;
u8 state;
u32 flags;
};

#define nft_trans_table_update(trans) \
(((struct nft_trans_table *)trans->data)->update)
#define nft_trans_table_state(trans) \
(((struct nft_trans_table *)trans->data)->state)
#define nft_trans_table_flags(trans) \
(((struct nft_trans_table *)trans->data)->flags)

struct nft_trans_elem {
struct nft_set *set;
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/ipvs/ip_vs_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1367,7 +1367,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
ip_vs_addr_copy(svc->af, &svc->addr, &u->addr);
svc->port = u->port;
svc->fwmark = u->fwmark;
svc->flags = u->flags;
svc->flags = u->flags & ~IP_VS_SVC_F_HASHED;
svc->timeout = u->timeout * HZ;
svc->netmask = u->netmask;
svc->ipvs = ipvs;
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/nf_conntrack_proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ int nf_conntrack_proto_init(void)

#if IS_ENABLED(CONFIG_IPV6)
cleanup_sockopt:
nf_unregister_sockopt(&so_getorigdst6);
nf_unregister_sockopt(&so_getorigdst);
#endif
return ret;
}
Expand Down
84 changes: 57 additions & 27 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,8 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
goto nla_put_failure;

if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
nla_put_be32(skb, NFTA_TABLE_FLAGS,
htonl(table->flags & NFT_TABLE_F_MASK)) ||
nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
NFTA_TABLE_PAD))
Expand Down Expand Up @@ -947,20 +948,22 @@ static int nf_tables_table_enable(struct net *net, struct nft_table *table)

static void nf_tables_table_disable(struct net *net, struct nft_table *table)
{
table->flags &= ~NFT_TABLE_F_DORMANT;
nft_table_disable(net, table, 0);
table->flags |= NFT_TABLE_F_DORMANT;
}

enum {
NFT_TABLE_STATE_UNCHANGED = 0,
NFT_TABLE_STATE_DORMANT,
NFT_TABLE_STATE_WAKEUP
};
#define __NFT_TABLE_F_INTERNAL (NFT_TABLE_F_MASK + 1)
#define __NFT_TABLE_F_WAS_DORMANT (__NFT_TABLE_F_INTERNAL << 0)
#define __NFT_TABLE_F_WAS_AWAKEN (__NFT_TABLE_F_INTERNAL << 1)
#define __NFT_TABLE_F_UPDATE (__NFT_TABLE_F_WAS_DORMANT | \
__NFT_TABLE_F_WAS_AWAKEN)

static int nf_tables_updtable(struct nft_ctx *ctx)
{
struct nft_trans *trans;
u32 flags;
int ret = 0;
int ret;

if (!ctx->nla[NFTA_TABLE_FLAGS])
return 0;
Expand All @@ -985,21 +988,27 @@ static int nf_tables_updtable(struct nft_ctx *ctx)

if ((flags & NFT_TABLE_F_DORMANT) &&
!(ctx->table->flags & NFT_TABLE_F_DORMANT)) {
nft_trans_table_state(trans) = NFT_TABLE_STATE_DORMANT;
ctx->table->flags |= NFT_TABLE_F_DORMANT;
if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE))
ctx->table->flags |= __NFT_TABLE_F_WAS_AWAKEN;
} else if (!(flags & NFT_TABLE_F_DORMANT) &&
ctx->table->flags & NFT_TABLE_F_DORMANT) {
ret = nf_tables_table_enable(ctx->net, ctx->table);
if (ret >= 0)
nft_trans_table_state(trans) = NFT_TABLE_STATE_WAKEUP;
ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE)) {
ret = nf_tables_table_enable(ctx->net, ctx->table);
if (ret < 0)
goto err_register_hooks;

ctx->table->flags |= __NFT_TABLE_F_WAS_DORMANT;
}
}
if (ret < 0)
goto err;

nft_trans_table_flags(trans) = flags;
nft_trans_table_update(trans) = true;
nft_trans_commit_list_add_tail(ctx->net, trans);

return 0;
err:

err_register_hooks:
nft_trans_destroy(trans);
return ret;
}
Expand Down Expand Up @@ -1905,7 +1914,7 @@ static int nft_chain_parse_netdev(struct net *net,
static int nft_chain_parse_hook(struct net *net,
const struct nlattr * const nla[],
struct nft_chain_hook *hook, u8 family,
bool autoload)
struct netlink_ext_ack *extack, bool autoload)
{
struct nftables_pernet *nft_net = nft_pernet(net);
struct nlattr *ha[NFTA_HOOK_MAX + 1];
Expand Down Expand Up @@ -1935,8 +1944,10 @@ static int nft_chain_parse_hook(struct net *net,
if (nla[NFTA_CHAIN_TYPE]) {
type = nf_tables_chain_type_lookup(net, nla[NFTA_CHAIN_TYPE],
family, autoload);
if (IS_ERR(type))
if (IS_ERR(type)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TYPE]);
return PTR_ERR(type);
}
}
if (hook->num >= NFT_MAX_HOOKS || !(type->hook_mask & (1 << hook->num)))
return -EOPNOTSUPP;
Expand All @@ -1945,8 +1956,11 @@ static int nft_chain_parse_hook(struct net *net,
hook->priority <= NF_IP_PRI_CONNTRACK)
return -EOPNOTSUPP;

if (!try_module_get(type->owner))
if (!try_module_get(type->owner)) {
if (nla[NFTA_CHAIN_TYPE])
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TYPE]);
return -ENOENT;
}

hook->type = type;

Expand Down Expand Up @@ -2057,7 +2071,8 @@ static int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
static u64 chain_id;

static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
u8 policy, u32 flags)
u8 policy, u32 flags,
struct netlink_ext_ack *extack)
{
const struct nlattr * const *nla = ctx->nla;
struct nft_table *table = ctx->table;
Expand All @@ -2079,7 +2094,8 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (flags & NFT_CHAIN_BINDING)
return -EOPNOTSUPP;

err = nft_chain_parse_hook(net, nla, &hook, family, true);
err = nft_chain_parse_hook(net, nla, &hook, family, extack,
true);
if (err < 0)
return err;

Expand Down Expand Up @@ -2234,7 +2250,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
return -EEXIST;
}
err = nft_chain_parse_hook(ctx->net, nla, &hook, ctx->family,
false);
extack, false);
if (err < 0)
return err;

Expand Down Expand Up @@ -2447,7 +2463,7 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
extack);
}

return nf_tables_addchain(&ctx, family, genmask, policy, flags);
return nf_tables_addchain(&ctx, family, genmask, policy, flags, extack);
}

static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
Expand Down Expand Up @@ -3328,8 +3344,10 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
if (n == NFT_RULE_MAXEXPRS)
goto err1;
err = nf_tables_expr_parse(&ctx, tmp, &expr_info[n]);
if (err < 0)
if (err < 0) {
NL_SET_BAD_ATTR(extack, tmp);
goto err1;
}
size += expr_info[n].ops->size;
n++;
}
Expand Down Expand Up @@ -8547,10 +8565,14 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
switch (trans->msg_type) {
case NFT_MSG_NEWTABLE:
if (nft_trans_table_update(trans)) {
if (nft_trans_table_state(trans) == NFT_TABLE_STATE_DORMANT)
if (!(trans->ctx.table->flags & __NFT_TABLE_F_UPDATE)) {
nft_trans_destroy(trans);
break;
}
if (trans->ctx.table->flags & NFT_TABLE_F_DORMANT)
nf_tables_table_disable(net, trans->ctx.table);

trans->ctx.table->flags = nft_trans_table_flags(trans);
trans->ctx.table->flags &= ~__NFT_TABLE_F_UPDATE;
} else {
nft_clear(net, trans->ctx.table);
}
Expand Down Expand Up @@ -8768,9 +8790,17 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
switch (trans->msg_type) {
case NFT_MSG_NEWTABLE:
if (nft_trans_table_update(trans)) {
if (nft_trans_table_state(trans) == NFT_TABLE_STATE_WAKEUP)
if (!(trans->ctx.table->flags & __NFT_TABLE_F_UPDATE)) {
nft_trans_destroy(trans);
break;
}
if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_DORMANT) {
nf_tables_table_disable(net, trans->ctx.table);

trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
} else if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_AWAKEN) {
trans->ctx.table->flags &= ~NFT_TABLE_F_DORMANT;
}
trans->ctx.table->flags &= ~__NFT_TABLE_F_UPDATE;
nft_trans_destroy(trans);
} else {
list_del_rcu(&trans->ctx.table->list);
Expand Down

0 comments on commit 44991d6

Please sign in to comment.