Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

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

The following patchset contains Netfilter updates for net-next:

1) Rename 'searched' column to 'clashres' in conntrack /proc/ stats
   to amend a recent patch, from Florian Westphal.

2) Remove unused nft_data_debug(), from YueHaibing.

3) Remove unused definitions in IPVS, also from YueHaibing.

4) Fix user data memleak in tables and objects, this is also amending
   a recent patch, from Jose M. Guisado.

5) Use nla_memdup() to allocate user data in table and objects, also
   from Jose M. Guisado

6) User data support for chains, from Jose M. Guisado

7) Remove unused definition in nf_tables_offload, from YueHaibing.

8) Use kvzalloc() in ip_set_alloc(), from Vasily Averin.

9) Fix false positive reported by lockdep in nfnetlink mutexes,
   from Florian Westphal.

10) Extend fast variant of cmp for neq operation, from Phil Sutter.

11) Implement fast bitwise variant, also from Phil Sutter.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-10-04 14:35:53 -07:00
commit 321e921daa
12 changed files with 222 additions and 63 deletions

View File

@ -148,13 +148,6 @@ static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
memcpy(dst, src, len);
}
static inline void nft_data_debug(const struct nft_data *data)
{
pr_debug("data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n",
data->data[0], data->data[1],
data->data[2], data->data[3]);
}
/**
* struct nft_ctx - nf_tables rule/set context
*
@ -952,6 +945,8 @@ struct nft_chain {
bound:1,
genmask:2;
char *name;
u16 udlen;
u8 *udata;
/* Only used during control plane commit phase: */
struct nft_rule **rules_next;

View File

@ -23,10 +23,19 @@ extern struct nft_object_type nft_secmark_obj_type;
int nf_tables_core_module_init(void);
void nf_tables_core_module_exit(void);
struct nft_bitwise_fast_expr {
u32 mask;
u32 xor;
enum nft_registers sreg:8;
enum nft_registers dreg:8;
};
struct nft_cmp_fast_expr {
u32 data;
u32 mask;
enum nft_registers sreg:8;
u8 len;
bool inv;
};
struct nft_immediate_expr {
@ -66,6 +75,8 @@ struct nft_payload_set {
extern const struct nft_expr_ops nft_payload_fast_ops;
extern const struct nft_expr_ops nft_bitwise_fast_ops;
extern struct static_key_false nft_counters_enabled;
extern struct static_key_false nft_trace_enabled;

View File

@ -208,6 +208,7 @@ enum nft_chain_flags {
* @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
* @NFTA_CHAIN_FLAGS: chain flags
* @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
* @NFTA_CHAIN_USERDATA: user data (NLA_BINARY)
*/
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
@ -222,6 +223,7 @@ enum nft_chain_attributes {
NFTA_CHAIN_PAD,
NFTA_CHAIN_FLAGS,
NFTA_CHAIN_ID,
NFTA_CHAIN_USERDATA,
__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)

View File

@ -250,22 +250,7 @@ EXPORT_SYMBOL_GPL(ip_set_type_unregister);
void *
ip_set_alloc(size_t size)
{
void *members = NULL;
if (size < KMALLOC_MAX_SIZE)
members = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (members) {
pr_debug("%p: allocated with kmalloc\n", members);
return members;
}
members = vzalloc(size);
if (!members)
return NULL;
pr_debug("%p: allocated with vmalloc\n", members);
return members;
return kvzalloc(size, GFP_KERNEL_ACCOUNT);
}
EXPORT_SYMBOL_GPL(ip_set_alloc);

View File

@ -242,9 +242,6 @@ struct ip_vs_sync_thread_data {
| IPVS Sync Connection (1) |
*/
#define SYNC_MESG_HEADER_LEN 4
#define MAX_CONNS_PER_SYNCBUFF 255 /* nr_conns in ip_vs_sync_mesg is 8 bit */
/* Version 0 header */
struct ip_vs_sync_mesg_v0 {
__u8 nr_conns;

View File

@ -428,14 +428,14 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
const struct ip_conntrack_stat *st = v;
if (v == SEQ_START_TOKEN) {
seq_puts(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart\n");
seq_puts(seq, "entries clashres found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart\n");
return 0;
}
seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x "
"%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
nr_conntracks,
st->clash_resolve, /* was: searched */
st->clash_resolve,
st->found,
0,
st->invalid,

View File

@ -997,7 +997,6 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
struct nft_table *table;
struct nft_ctx ctx;
u32 flags = 0;
u16 udlen = 0;
int err;
lockdep_assert_held(&net->nft.commit_mutex);
@ -1034,13 +1033,11 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
goto err_strdup;
if (nla[NFTA_TABLE_USERDATA]) {
udlen = nla_len(nla[NFTA_TABLE_USERDATA]);
table->udata = kzalloc(udlen, GFP_KERNEL);
table->udata = nla_memdup(nla[NFTA_TABLE_USERDATA], GFP_KERNEL);
if (table->udata == NULL)
goto err_table_udata;
nla_memcpy(table->udata, nla[NFTA_TABLE_USERDATA], udlen);
table->udlen = udlen;
table->udlen = nla_len(nla[NFTA_TABLE_USERDATA]);
}
err = rhltable_init(&table->chains_ht, &nft_chain_ht_params);
@ -1222,6 +1219,7 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx)
rhltable_destroy(&ctx->table->chains_ht);
kfree(ctx->table->name);
kfree(ctx->table->udata);
kfree(ctx->table);
}
@ -1317,6 +1315,8 @@ static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
[NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
[NFTA_CHAIN_FLAGS] = { .type = NLA_U32 },
[NFTA_CHAIN_ID] = { .type = NLA_U32 },
[NFTA_CHAIN_USERDATA] = { .type = NLA_BINARY,
.len = NFT_USERDATA_MAXLEN },
};
static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
@ -1458,6 +1458,10 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
goto nla_put_failure;
if (chain->udata &&
nla_put(skb, NFTA_CHAIN_USERDATA, chain->udlen, chain->udata))
goto nla_put_failure;
nlmsg_end(skb, nlh);
return 0;
@ -1694,9 +1698,11 @@ void nf_tables_chain_destroy(struct nft_ctx *ctx)
free_percpu(rcu_dereference_raw(basechain->stats));
}
kfree(chain->name);
kfree(chain->udata);
kfree(basechain);
} else {
kfree(chain->name);
kfree(chain->udata);
kfree(chain);
}
}
@ -2050,7 +2056,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
} else {
if (!(flags & NFT_CHAIN_BINDING)) {
err = -EINVAL;
goto err1;
goto err_destroy_chain;
}
snprintf(name, sizeof(name), "__chain%llu", ++chain_id);
@ -2059,13 +2065,22 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (!chain->name) {
err = -ENOMEM;
goto err1;
goto err_destroy_chain;
}
if (nla[NFTA_CHAIN_USERDATA]) {
chain->udata = nla_memdup(nla[NFTA_CHAIN_USERDATA], GFP_KERNEL);
if (chain->udata == NULL) {
err = -ENOMEM;
goto err_destroy_chain;
}
chain->udlen = nla_len(nla[NFTA_CHAIN_USERDATA]);
}
rules = nf_tables_chain_alloc_rules(chain, 0);
if (!rules) {
err = -ENOMEM;
goto err1;
goto err_destroy_chain;
}
*rules = NULL;
@ -2074,12 +2089,12 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
err = nf_tables_register_hook(net, table, chain);
if (err < 0)
goto err1;
goto err_destroy_chain;
trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
goto err2;
goto err_unregister_hook;
}
nft_trans_chain_policy(trans) = NFT_CHAIN_POLICY_UNSET;
@ -2089,15 +2104,15 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
err = nft_chain_add(table, chain);
if (err < 0) {
nft_trans_destroy(trans);
goto err2;
goto err_unregister_hook;
}
table->use++;
return 0;
err2:
err_unregister_hook:
nf_tables_unregister_hook(net, table, chain);
err1:
err_destroy_chain:
nf_tables_chain_destroy(ctx);
return err;
@ -5906,7 +5921,6 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
struct nft_object *obj;
struct nft_ctx ctx;
u32 objtype;
u16 udlen;
int err;
if (!nla[NFTA_OBJ_TYPE] ||
@ -5963,13 +5977,11 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
}
if (nla[NFTA_OBJ_USERDATA]) {
udlen = nla_len(nla[NFTA_OBJ_USERDATA]);
obj->udata = kzalloc(udlen, GFP_KERNEL);
obj->udata = nla_memdup(nla[NFTA_OBJ_USERDATA], GFP_KERNEL);
if (obj->udata == NULL)
goto err_userdata;
nla_memcpy(obj->udata, nla[NFTA_OBJ_USERDATA], udlen);
obj->udlen = udlen;
obj->udlen = nla_len(nla[NFTA_OBJ_USERDATA]);
}
err = nft_trans_obj_add(&ctx, NFT_MSG_NEWOBJ, obj);
@ -6238,6 +6250,7 @@ static void nft_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
module_put(obj->ops->type->owner);
kfree(obj->key.name);
kfree(obj->udata);
kfree(obj);
}

View File

@ -47,13 +47,22 @@ static inline void nft_trace_packet(struct nft_traceinfo *info,
}
}
static void nft_bitwise_fast_eval(const struct nft_expr *expr,
struct nft_regs *regs)
{
const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
u32 *src = &regs->data[priv->sreg];
u32 *dst = &regs->data[priv->dreg];
*dst = (*src & priv->mask) ^ priv->xor;
}
static void nft_cmp_fast_eval(const struct nft_expr *expr,
struct nft_regs *regs)
{
const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
u32 mask = nft_cmp_fast_mask(priv->len);
if ((regs->data[priv->sreg] & mask) == priv->data)
if (((regs->data[priv->sreg] & priv->mask) == priv->data) ^ priv->inv)
return;
regs->verdict.code = NFT_BREAK;
}
@ -176,6 +185,8 @@ next_rule:
nft_rule_for_each_expr(expr, last, rule) {
if (expr->ops == &nft_cmp_fast_ops)
nft_cmp_fast_eval(expr, &regs);
else if (expr->ops == &nft_bitwise_fast_ops)
nft_bitwise_fast_eval(expr, &regs);
else if (expr->ops != &nft_payload_fast_ops ||
!nft_payload_fast_eval(expr, &regs, pkt))
expr_call_ops_eval(expr, &regs, pkt);

View File

@ -323,8 +323,6 @@ static int nft_indr_block_offload_cmd(struct nft_base_chain *basechain,
return nft_block_setup(basechain, &bo, cmd);
}
#define FLOW_SETUP_BLOCK TC_SETUP_BLOCK
static int nft_chain_offload_cmd(struct nft_base_chain *basechain,
struct net_device *dev,
enum flow_block_command cmd)

View File

@ -46,6 +46,23 @@ static struct {
const struct nfnetlink_subsystem __rcu *subsys;
} table[NFNL_SUBSYS_COUNT];
static struct lock_class_key nfnl_lockdep_keys[NFNL_SUBSYS_COUNT];
static const char *const nfnl_lockdep_names[NFNL_SUBSYS_COUNT] = {
[NFNL_SUBSYS_NONE] = "nfnl_subsys_none",
[NFNL_SUBSYS_CTNETLINK] = "nfnl_subsys_ctnetlink",
[NFNL_SUBSYS_CTNETLINK_EXP] = "nfnl_subsys_ctnetlink_exp",
[NFNL_SUBSYS_QUEUE] = "nfnl_subsys_queue",
[NFNL_SUBSYS_ULOG] = "nfnl_subsys_ulog",
[NFNL_SUBSYS_OSF] = "nfnl_subsys_osf",
[NFNL_SUBSYS_IPSET] = "nfnl_subsys_ipset",
[NFNL_SUBSYS_ACCT] = "nfnl_subsys_acct",
[NFNL_SUBSYS_CTNETLINK_TIMEOUT] = "nfnl_subsys_cttimeout",
[NFNL_SUBSYS_CTHELPER] = "nfnl_subsys_cthelper",
[NFNL_SUBSYS_NFTABLES] = "nfnl_subsys_nftables",
[NFNL_SUBSYS_NFT_COMPAT] = "nfnl_subsys_nftcompat",
};
static const int nfnl_group2type[NFNLGRP_MAX+1] = {
[NFNLGRP_CONNTRACK_NEW] = NFNL_SUBSYS_CTNETLINK,
[NFNLGRP_CONNTRACK_UPDATE] = NFNL_SUBSYS_CTNETLINK,
@ -632,7 +649,7 @@ static int __init nfnetlink_init(void)
BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE);
for (i=0; i<NFNL_SUBSYS_COUNT; i++)
mutex_init(&table[i].mutex);
__mutex_init(&table[i].mutex, nfnl_lockdep_names[i], &nfnl_lockdep_keys[i]);
return register_pernet_subsys(&nfnetlink_net_ops);
}

View File

@ -163,11 +163,6 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
u32 len;
int err;
if (!tb[NFTA_BITWISE_SREG] ||
!tb[NFTA_BITWISE_DREG] ||
!tb[NFTA_BITWISE_LEN])
return -EINVAL;
err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
if (err < 0)
return err;
@ -292,9 +287,143 @@ static const struct nft_expr_ops nft_bitwise_ops = {
.offload = nft_bitwise_offload,
};
static int
nft_bitwise_extract_u32_data(const struct nlattr * const tb, u32 *out)
{
struct nft_data_desc desc;
struct nft_data data;
int err = 0;
err = nft_data_init(NULL, &data, sizeof(data), &desc, tb);
if (err < 0)
return err;
if (desc.type != NFT_DATA_VALUE || desc.len != sizeof(u32)) {
err = -EINVAL;
goto err;
}
*out = data.data[0];
err:
nft_data_release(&data, desc.type);
return err;
}
static int nft_bitwise_fast_init(const struct nft_ctx *ctx,
const struct nft_expr *expr,
const struct nlattr * const tb[])
{
struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
int err;
priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
err = nft_validate_register_load(priv->sreg, sizeof(u32));
if (err < 0)
return err;
priv->dreg = nft_parse_register(tb[NFTA_BITWISE_DREG]);
err = nft_validate_register_store(ctx, priv->dreg, NULL,
NFT_DATA_VALUE, sizeof(u32));
if (err < 0)
return err;
if (tb[NFTA_BITWISE_DATA])
return -EINVAL;
if (!tb[NFTA_BITWISE_MASK] ||
!tb[NFTA_BITWISE_XOR])
return -EINVAL;
err = nft_bitwise_extract_u32_data(tb[NFTA_BITWISE_MASK], &priv->mask);
if (err < 0)
return err;
err = nft_bitwise_extract_u32_data(tb[NFTA_BITWISE_XOR], &priv->xor);
if (err < 0)
return err;
return 0;
}
static int
nft_bitwise_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
struct nft_data data;
if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg))
return -1;
if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg))
return -1;
if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(sizeof(u32))))
return -1;
if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(NFT_BITWISE_BOOL)))
return -1;
data.data[0] = priv->mask;
if (nft_data_dump(skb, NFTA_BITWISE_MASK, &data,
NFT_DATA_VALUE, sizeof(u32)) < 0)
return -1;
data.data[0] = priv->xor;
if (nft_data_dump(skb, NFTA_BITWISE_XOR, &data,
NFT_DATA_VALUE, sizeof(u32)) < 0)
return -1;
return 0;
}
static int nft_bitwise_fast_offload(struct nft_offload_ctx *ctx,
struct nft_flow_rule *flow,
const struct nft_expr *expr)
{
const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
if (priv->xor || priv->sreg != priv->dreg || reg->len != sizeof(u32))
return -EOPNOTSUPP;
reg->mask.data[0] = priv->mask;
return 0;
}
const struct nft_expr_ops nft_bitwise_fast_ops = {
.type = &nft_bitwise_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise_fast_expr)),
.eval = NULL, /* inlined */
.init = nft_bitwise_fast_init,
.dump = nft_bitwise_fast_dump,
.offload = nft_bitwise_fast_offload,
};
static const struct nft_expr_ops *
nft_bitwise_select_ops(const struct nft_ctx *ctx,
const struct nlattr * const tb[])
{
int err;
u32 len;
if (!tb[NFTA_BITWISE_LEN] ||
!tb[NFTA_BITWISE_SREG] ||
!tb[NFTA_BITWISE_DREG])
return ERR_PTR(-EINVAL);
err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
if (err < 0)
return ERR_PTR(err);
if (len != sizeof(u32))
return &nft_bitwise_ops;
if (tb[NFTA_BITWISE_OP] &&
ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])) != NFT_BITWISE_BOOL)
return &nft_bitwise_ops;
return &nft_bitwise_fast_ops;
}
struct nft_expr_type nft_bitwise_type __read_mostly = {
.name = "bitwise",
.ops = &nft_bitwise_ops,
.select_ops = nft_bitwise_select_ops,
.policy = nft_bitwise_policy,
.maxattr = NFTA_BITWISE_MAX,
.owner = THIS_MODULE,

View File

@ -167,7 +167,6 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
struct nft_data_desc desc;
struct nft_data data;
u32 mask;
int err;
err = nft_data_init(NULL, &data, sizeof(data), &desc,
@ -181,10 +180,11 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
return err;
desc.len *= BITS_PER_BYTE;
mask = nft_cmp_fast_mask(desc.len);
priv->data = data.data[0] & mask;
priv->mask = nft_cmp_fast_mask(desc.len);
priv->data = data.data[0] & priv->mask;
priv->len = desc.len;
priv->inv = ntohl(nla_get_be32(tb[NFTA_CMP_OP])) != NFT_CMP_EQ;
return 0;
}
@ -201,7 +201,7 @@ static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx,
},
.sreg = priv->sreg,
.len = priv->len / BITS_PER_BYTE,
.op = NFT_CMP_EQ,
.op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ,
};
return __nft_cmp_offload(ctx, flow, &cmp);
@ -210,11 +210,12 @@ static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx,
static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
enum nft_cmp_ops op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ;
struct nft_data data;
if (nft_dump_register(skb, NFTA_CMP_SREG, priv->sreg))
goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ)))
if (nla_put_be32(skb, NFTA_CMP_OP, htonl(op)))
goto nla_put_failure;
data.data[0] = priv->data;
@ -272,7 +273,7 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
goto err1;
}
if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ)
if (desc.len <= sizeof(u32) && (op == NFT_CMP_EQ || op == NFT_CMP_NEQ))
return &nft_cmp_fast_ops;
return &nft_cmp_ops;