Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Nicolas Dichtel updates MAINTAINERS file to add Netfilter IRC channel. 2) Skip non-IPv6 packets in nft_exthdr. 3) Skip non-TCP packets in nft_osf. 4) Skip non-TCP/UDP packets in nft_tproxy. 5) Memleak in hardware offload infrastructure when counters are used for first time in a rule. 6) The VLAN transfer routine must use FLOW_DISSECTOR_KEY_BASIC instead of FLOW_DISSECTOR_KEY_CONTROL. Moreover, make a more robust check for 802.1q and 802.1ad to restore simple matching on transport protocols. 7) Fix bogus EPERM when listing a ruleset when table ownership flag is set on. 8) Honor table ownership flag when table is referenced by handle. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
f4b29d2ee9
|
@ -12659,6 +12659,7 @@ W: http://www.netfilter.org/
|
|||
W: http://www.iptables.org/
|
||||
W: http://www.nftables.org/
|
||||
Q: http://patchwork.ozlabs.org/project/netfilter-devel/list/
|
||||
C: irc://irc.libera.chat/netfilter
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git
|
||||
F: include/linux/netfilter*
|
||||
|
|
|
@ -571,7 +571,7 @@ static struct nft_table *nft_table_lookup(const struct net *net,
|
|||
table->family == family &&
|
||||
nft_active_genmask(table, genmask)) {
|
||||
if (nft_table_has_owner(table) &&
|
||||
table->nlpid != nlpid)
|
||||
nlpid && table->nlpid != nlpid)
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
return table;
|
||||
|
@ -583,7 +583,7 @@ static struct nft_table *nft_table_lookup(const struct net *net,
|
|||
|
||||
static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
|
||||
const struct nlattr *nla,
|
||||
u8 genmask)
|
||||
u8 genmask, u32 nlpid)
|
||||
{
|
||||
struct nftables_pernet *nft_net;
|
||||
struct nft_table *table;
|
||||
|
@ -591,8 +591,13 @@ static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
|
|||
nft_net = nft_pernet(net);
|
||||
list_for_each_entry(table, &nft_net->tables, list) {
|
||||
if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
|
||||
nft_active_genmask(table, genmask))
|
||||
nft_active_genmask(table, genmask)) {
|
||||
if (nft_table_has_owner(table) &&
|
||||
nlpid && table->nlpid != nlpid)
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
@ -1279,7 +1284,8 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
|
||||
if (nla[NFTA_TABLE_HANDLE]) {
|
||||
attr = nla[NFTA_TABLE_HANDLE];
|
||||
table = nft_table_lookup_byhandle(net, attr, genmask);
|
||||
table = nft_table_lookup_byhandle(net, attr, genmask,
|
||||
NETLINK_CB(skb).portid);
|
||||
} else {
|
||||
attr = nla[NFTA_TABLE_NAME];
|
||||
table = nft_table_lookup(net, attr, family, genmask,
|
||||
|
@ -3243,9 +3249,9 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
u8 genmask = nft_genmask_next(info->net);
|
||||
struct nft_rule *rule, *old_rule = NULL;
|
||||
struct nft_expr_info *expr_info = NULL;
|
||||
struct nft_flow_rule *flow = NULL;
|
||||
int family = nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
struct nft_flow_rule *flow;
|
||||
struct nft_userdata *udata;
|
||||
struct nft_table *table;
|
||||
struct nft_chain *chain;
|
||||
|
@ -3340,13 +3346,13 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
|
||||
err = -EINVAL;
|
||||
if (nla_type(tmp) != NFTA_LIST_ELEM)
|
||||
goto err1;
|
||||
goto err_release_expr;
|
||||
if (n == NFT_RULE_MAXEXPRS)
|
||||
goto err1;
|
||||
goto err_release_expr;
|
||||
err = nf_tables_expr_parse(&ctx, tmp, &expr_info[n]);
|
||||
if (err < 0) {
|
||||
NL_SET_BAD_ATTR(extack, tmp);
|
||||
goto err1;
|
||||
goto err_release_expr;
|
||||
}
|
||||
size += expr_info[n].ops->size;
|
||||
n++;
|
||||
|
@ -3355,7 +3361,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
/* Check for overflow of dlen field */
|
||||
err = -EFBIG;
|
||||
if (size >= 1 << 12)
|
||||
goto err1;
|
||||
goto err_release_expr;
|
||||
|
||||
if (nla[NFTA_RULE_USERDATA]) {
|
||||
ulen = nla_len(nla[NFTA_RULE_USERDATA]);
|
||||
|
@ -3366,7 +3372,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
err = -ENOMEM;
|
||||
rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL);
|
||||
if (rule == NULL)
|
||||
goto err1;
|
||||
goto err_release_expr;
|
||||
|
||||
nft_activate_next(net, rule);
|
||||
|
||||
|
@ -3385,7 +3391,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
err = nf_tables_newexpr(&ctx, &expr_info[i], expr);
|
||||
if (err < 0) {
|
||||
NL_SET_BAD_ATTR(extack, expr_info[i].attr);
|
||||
goto err2;
|
||||
goto err_release_rule;
|
||||
}
|
||||
|
||||
if (expr_info[i].ops->validate)
|
||||
|
@ -3395,16 +3401,24 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
expr = nft_expr_next(expr);
|
||||
}
|
||||
|
||||
if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
|
||||
flow = nft_flow_rule_create(net, rule);
|
||||
if (IS_ERR(flow)) {
|
||||
err = PTR_ERR(flow);
|
||||
goto err_release_rule;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
|
||||
trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
|
||||
if (trans == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto err2;
|
||||
goto err_destroy_flow_rule;
|
||||
}
|
||||
err = nft_delrule(&ctx, old_rule);
|
||||
if (err < 0) {
|
||||
nft_trans_destroy(trans);
|
||||
goto err2;
|
||||
goto err_destroy_flow_rule;
|
||||
}
|
||||
|
||||
list_add_tail_rcu(&rule->list, &old_rule->list);
|
||||
|
@ -3412,7 +3426,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
|
||||
if (!trans) {
|
||||
err = -ENOMEM;
|
||||
goto err2;
|
||||
goto err_destroy_flow_rule;
|
||||
}
|
||||
|
||||
if (info->nlh->nlmsg_flags & NLM_F_APPEND) {
|
||||
|
@ -3430,21 +3444,19 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
kvfree(expr_info);
|
||||
chain->use++;
|
||||
|
||||
if (flow)
|
||||
nft_trans_flow_rule(trans) = flow;
|
||||
|
||||
if (nft_net->validate_state == NFT_VALIDATE_DO)
|
||||
return nft_table_validate(net, table);
|
||||
|
||||
if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
|
||||
flow = nft_flow_rule_create(net, rule);
|
||||
if (IS_ERR(flow))
|
||||
return PTR_ERR(flow);
|
||||
|
||||
nft_trans_flow_rule(trans) = flow;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
|
||||
err_destroy_flow_rule:
|
||||
nft_flow_rule_destroy(flow);
|
||||
err_release_rule:
|
||||
nf_tables_rule_release(&ctx, rule);
|
||||
err1:
|
||||
err_release_expr:
|
||||
for (i = 0; i < n; i++) {
|
||||
if (expr_info[i].ops) {
|
||||
module_put(expr_info[i].ops->type->owner);
|
||||
|
@ -8839,11 +8851,16 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
|
|||
nft_rule_expr_deactivate(&trans->ctx,
|
||||
nft_trans_rule(trans),
|
||||
NFT_TRANS_ABORT);
|
||||
if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
|
||||
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
|
||||
break;
|
||||
case NFT_MSG_DELRULE:
|
||||
trans->ctx.chain->use++;
|
||||
nft_clear(trans->ctx.net, nft_trans_rule(trans));
|
||||
nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
|
||||
if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
|
||||
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
|
||||
|
||||
nft_trans_destroy(trans);
|
||||
break;
|
||||
case NFT_MSG_NEWSET:
|
||||
|
|
|
@ -54,15 +54,10 @@ static void nft_flow_rule_transfer_vlan(struct nft_offload_ctx *ctx,
|
|||
struct nft_flow_rule *flow)
|
||||
{
|
||||
struct nft_flow_match *match = &flow->match;
|
||||
struct nft_offload_ethertype ethertype;
|
||||
|
||||
if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL) &&
|
||||
match->key.basic.n_proto != htons(ETH_P_8021Q) &&
|
||||
match->key.basic.n_proto != htons(ETH_P_8021AD))
|
||||
return;
|
||||
|
||||
ethertype.value = match->key.basic.n_proto;
|
||||
ethertype.mask = match->mask.basic.n_proto;
|
||||
struct nft_offload_ethertype ethertype = {
|
||||
.value = match->key.basic.n_proto,
|
||||
.mask = match->mask.basic.n_proto,
|
||||
};
|
||||
|
||||
if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_VLAN) &&
|
||||
(match->key.vlan.vlan_tpid == htons(ETH_P_8021Q) ||
|
||||
|
@ -76,7 +71,9 @@ static void nft_flow_rule_transfer_vlan(struct nft_offload_ctx *ctx,
|
|||
match->dissector.offset[FLOW_DISSECTOR_KEY_CVLAN] =
|
||||
offsetof(struct nft_flow_key, cvlan);
|
||||
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_CVLAN);
|
||||
} else {
|
||||
} else if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_BASIC) &&
|
||||
(match->key.basic.n_proto == htons(ETH_P_8021Q) ||
|
||||
match->key.basic.n_proto == htons(ETH_P_8021AD))) {
|
||||
match->key.basic.n_proto = match->key.vlan.vlan_tpid;
|
||||
match->mask.basic.n_proto = match->mask.vlan.vlan_tpid;
|
||||
match->key.vlan.vlan_tpid = ethertype.value;
|
||||
|
@ -594,23 +591,6 @@ int nft_flow_rule_offload_commit(struct net *net)
|
|||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(trans, &nft_net->commit_list, list) {
|
||||
if (trans->ctx.family != NFPROTO_NETDEV)
|
||||
continue;
|
||||
|
||||
switch (trans->msg_type) {
|
||||
case NFT_MSG_NEWRULE:
|
||||
case NFT_MSG_DELRULE:
|
||||
if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
|
||||
continue;
|
||||
|
||||
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
|
|||
unsigned int offset = 0;
|
||||
int err;
|
||||
|
||||
if (pkt->skb->protocol != htons(ETH_P_IPV6))
|
||||
goto err;
|
||||
|
||||
err = ipv6_find_hdr(pkt->skb, &offset, priv->type, NULL, NULL);
|
||||
if (priv->flags & NFT_EXTHDR_F_PRESENT) {
|
||||
nft_reg_store8(dest, err >= 0);
|
||||
|
|
|
@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
|||
struct nf_osf_data data;
|
||||
struct tcphdr _tcph;
|
||||
|
||||
if (pkt->tprot != IPPROTO_TCP) {
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
return;
|
||||
}
|
||||
|
||||
tcp = skb_header_pointer(skb, ip_hdrlen(skb),
|
||||
sizeof(struct tcphdr), &_tcph);
|
||||
if (!tcp) {
|
||||
|
|
|
@ -30,6 +30,12 @@ static void nft_tproxy_eval_v4(const struct nft_expr *expr,
|
|||
__be16 tport = 0;
|
||||
struct sock *sk;
|
||||
|
||||
if (pkt->tprot != IPPROTO_TCP &&
|
||||
pkt->tprot != IPPROTO_UDP) {
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
return;
|
||||
}
|
||||
|
||||
hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
|
||||
if (!hp) {
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
|
@ -91,7 +97,8 @@ static void nft_tproxy_eval_v6(const struct nft_expr *expr,
|
|||
|
||||
memset(&taddr, 0, sizeof(taddr));
|
||||
|
||||
if (!pkt->tprot_set) {
|
||||
if (pkt->tprot != IPPROTO_TCP &&
|
||||
pkt->tprot != IPPROTO_UDP) {
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue