Commit 72f6d4d1 authored by David S. Miller's avatar David S. Miller

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

Pablo Neira Ayuso says:

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

This is the first batch of Netfilter fixes for your net tree:

1) Fix endless loop in nf_tables rules netlink dump, from Phil Sutter.

2) Reference counter leak in object from the error path, from Taehee Yoo.

3) Selective rule dump requires table and chain.

4) Fix DNAT with nft_flow_offload reverse route lookup, from wenxu.

5) Use GFP_KERNEL_ACCOUNT in vmalloc allocation from ebtables, from
   Shakeel Butt.

6) Set ifindex from route to fix interaction with VRF slave device,
   also from wenxu.

7) Use nfct_help() to check for conntrack helper, IPS_HELPER status
   flag is only set from explicit helpers via -j CT, from Henry Yen.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7939f8be 2314e879
...@@ -84,7 +84,6 @@ struct flow_offload { ...@@ -84,7 +84,6 @@ struct flow_offload {
struct nf_flow_route { struct nf_flow_route {
struct { struct {
struct dst_entry *dst; struct dst_entry *dst;
int ifindex;
} tuple[FLOW_OFFLOAD_DIR_MAX]; } tuple[FLOW_OFFLOAD_DIR_MAX];
}; };
......
...@@ -1137,14 +1137,16 @@ static int do_replace(struct net *net, const void __user *user, ...@@ -1137,14 +1137,16 @@ static int do_replace(struct net *net, const void __user *user,
tmp.name[sizeof(tmp.name) - 1] = 0; tmp.name[sizeof(tmp.name) - 1] = 0;
countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
newinfo = vmalloc(sizeof(*newinfo) + countersize); newinfo = __vmalloc(sizeof(*newinfo) + countersize, GFP_KERNEL_ACCOUNT,
PAGE_KERNEL);
if (!newinfo) if (!newinfo)
return -ENOMEM; return -ENOMEM;
if (countersize) if (countersize)
memset(newinfo->counters, 0, countersize); memset(newinfo->counters, 0, countersize);
newinfo->entries = vmalloc(tmp.entries_size); newinfo->entries = __vmalloc(tmp.entries_size, GFP_KERNEL_ACCOUNT,
PAGE_KERNEL);
if (!newinfo->entries) { if (!newinfo->entries) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_newinfo; goto free_newinfo;
......
...@@ -28,6 +28,7 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, ...@@ -28,6 +28,7 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
{ {
struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple; struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple; struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
struct dst_entry *other_dst = route->tuple[!dir].dst;
struct dst_entry *dst = route->tuple[dir].dst; struct dst_entry *dst = route->tuple[dir].dst;
ft->dir = dir; ft->dir = dir;
...@@ -50,8 +51,8 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, ...@@ -50,8 +51,8 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
ft->src_port = ctt->src.u.tcp.port; ft->src_port = ctt->src.u.tcp.port;
ft->dst_port = ctt->dst.u.tcp.port; ft->dst_port = ctt->dst.u.tcp.port;
ft->iifidx = route->tuple[dir].ifindex; ft->iifidx = other_dst->dev->ifindex;
ft->oifidx = route->tuple[!dir].ifindex; ft->oifidx = dst->dev->ifindex;
ft->dst_cache = dst; ft->dst_cache = dst;
} }
......
...@@ -2304,7 +2304,6 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2304,7 +2304,6 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
unsigned int s_idx = cb->args[0]; unsigned int s_idx = cb->args[0];
const struct nft_rule *rule; const struct nft_rule *rule;
int rc = 1;
list_for_each_entry_rcu(rule, &chain->rules, list) { list_for_each_entry_rcu(rule, &chain->rules, list) {
if (!nft_is_active(net, rule)) if (!nft_is_active(net, rule))
...@@ -2321,16 +2320,13 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2321,16 +2320,13 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
NLM_F_MULTI | NLM_F_APPEND, NLM_F_MULTI | NLM_F_APPEND,
table->family, table->family,
table, chain, rule) < 0) table, chain, rule) < 0)
goto out_unfinished; return 1;
nl_dump_check_consistent(cb, nlmsg_hdr(skb)); nl_dump_check_consistent(cb, nlmsg_hdr(skb));
cont: cont:
(*idx)++; (*idx)++;
} }
rc = 0; return 0;
out_unfinished:
cb->args[0] = *idx;
return rc;
} }
static int nf_tables_dump_rules(struct sk_buff *skb, static int nf_tables_dump_rules(struct sk_buff *skb,
...@@ -2354,7 +2350,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2354,7 +2350,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
if (ctx && ctx->table && strcmp(ctx->table, table->name) != 0) if (ctx && ctx->table && strcmp(ctx->table, table->name) != 0)
continue; continue;
if (ctx && ctx->chain) { if (ctx && ctx->table && ctx->chain) {
struct rhlist_head *list, *tmp; struct rhlist_head *list, *tmp;
list = rhltable_lookup(&table->chains_ht, ctx->chain, list = rhltable_lookup(&table->chains_ht, ctx->chain,
...@@ -2382,6 +2378,8 @@ static int nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2382,6 +2378,8 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
} }
done: done:
rcu_read_unlock(); rcu_read_unlock();
cb->args[0] = idx;
return skb->len; return skb->len;
} }
...@@ -4508,6 +4506,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4508,6 +4506,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
err5: err5:
kfree(trans); kfree(trans);
err4: err4:
if (obj)
obj->use--;
kfree(elem.priv); kfree(elem.priv);
err3: err3:
if (nla[NFTA_SET_ELEM_DATA] != NULL) if (nla[NFTA_SET_ELEM_DATA] != NULL)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <net/netfilter/nf_conntrack_core.h> #include <net/netfilter/nf_conntrack_core.h>
#include <linux/netfilter/nf_conntrack_common.h> #include <linux/netfilter/nf_conntrack_common.h>
#include <net/netfilter/nf_flow_table.h> #include <net/netfilter/nf_flow_table.h>
#include <net/netfilter/nf_conntrack_helper.h>
struct nft_flow_offload { struct nft_flow_offload {
struct nft_flowtable *flowtable; struct nft_flowtable *flowtable;
...@@ -29,10 +30,12 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, ...@@ -29,10 +30,12 @@ static int nft_flow_route(const struct nft_pktinfo *pkt,
memset(&fl, 0, sizeof(fl)); memset(&fl, 0, sizeof(fl));
switch (nft_pf(pkt)) { switch (nft_pf(pkt)) {
case NFPROTO_IPV4: case NFPROTO_IPV4:
fl.u.ip4.daddr = ct->tuplehash[!dir].tuple.dst.u3.ip; fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex;
break; break;
case NFPROTO_IPV6: case NFPROTO_IPV6:
fl.u.ip6.daddr = ct->tuplehash[!dir].tuple.dst.u3.in6; fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex;
break; break;
} }
...@@ -41,9 +44,7 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, ...@@ -41,9 +44,7 @@ static int nft_flow_route(const struct nft_pktinfo *pkt,
return -ENOENT; return -ENOENT;
route->tuple[dir].dst = this_dst; route->tuple[dir].dst = this_dst;
route->tuple[dir].ifindex = nft_in(pkt)->ifindex;
route->tuple[!dir].dst = other_dst; route->tuple[!dir].dst = other_dst;
route->tuple[!dir].ifindex = nft_out(pkt)->ifindex;
return 0; return 0;
} }
...@@ -66,6 +67,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, ...@@ -66,6 +67,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
{ {
struct nft_flow_offload *priv = nft_expr_priv(expr); struct nft_flow_offload *priv = nft_expr_priv(expr);
struct nf_flowtable *flowtable = &priv->flowtable->data; struct nf_flowtable *flowtable = &priv->flowtable->data;
const struct nf_conn_help *help;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_flow_route route; struct nf_flow_route route;
struct flow_offload *flow; struct flow_offload *flow;
...@@ -88,7 +90,8 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, ...@@ -88,7 +90,8 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
goto out; goto out;
} }
if (test_bit(IPS_HELPER_BIT, &ct->status)) help = nfct_help(ct);
if (help)
goto out; goto out;
if (ctinfo == IP_CT_NEW || if (ctinfo == IP_CT_NEW ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment