Commit 086cb6a4 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

The following patchset contains a large batch with Netfilter fixes for
your net tree, they are:

1) Two patches to solve conntrack garbage collector cpu hogging, one to
   remove GC_MAX_EVICTS and another to look at the ratio (scanned entries
   vs. evicted entries) to make a decision on whether to reduce or not
   the scanning interval. From Florian Westphal.

2) Two patches to fix incorrect set element counting if NLM_F_EXCL is
   is not set. Moreover, don't decrenent set->nelems from abort patch
   if -ENFILE which leaks a spare slot in the set. This includes a
   patch to deconstify the set walk callback to update set->ndeact.

3) Two fixes for the fwmark_reflect sysctl feature: Propagate mark to
   reply packets both from nf_reject and local stack, from Pau Espin Pedrol.

4) Fix incorrect handling of loopback traffic in rpfilter and nf_tables
   fib expression, from Liping Zhang.

5) Fix oops on stateful objects netlink dump, when no filter is specified.
   Also from Liping Zhang.

6) Fix a build error if proc is not available in ipt_CLUSTERIP, related
   to fix that was applied in the previous batch for net. From Arnd Bergmann.

7) Fix lack of string validation in table, chain, set and stateful
   object names in nf_tables, from Liping Zhang. Moreover, restrict
   maximum log prefix length to 127 bytes, otherwise explicitly bail
   out.

8) Two patches to fix spelling and typos in nf_tables uapi header file
   and Kconfig, patches from Alexander Alemayhu and William Breathitt Gray.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 214767fa b2c11e4b
...@@ -207,9 +207,9 @@ struct nft_set_iter { ...@@ -207,9 +207,9 @@ struct nft_set_iter {
unsigned int skip; unsigned int skip;
int err; int err;
int (*fn)(const struct nft_ctx *ctx, int (*fn)(const struct nft_ctx *ctx,
const struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
const struct nft_set_elem *elem); struct nft_set_elem *elem);
}; };
/** /**
...@@ -301,7 +301,7 @@ struct nft_set_ops { ...@@ -301,7 +301,7 @@ struct nft_set_ops {
void (*remove)(const struct nft_set *set, void (*remove)(const struct nft_set *set,
const struct nft_set_elem *elem); const struct nft_set_elem *elem);
void (*walk)(const struct nft_ctx *ctx, void (*walk)(const struct nft_ctx *ctx,
const struct nft_set *set, struct nft_set *set,
struct nft_set_iter *iter); struct nft_set_iter *iter);
unsigned int (*privsize)(const struct nlattr * const nla[]); unsigned int (*privsize)(const struct nlattr * const nla[]);
......
...@@ -9,6 +9,12 @@ struct nft_fib { ...@@ -9,6 +9,12 @@ struct nft_fib {
extern const struct nla_policy nft_fib_policy[]; extern const struct nla_policy nft_fib_policy[];
static inline bool
nft_fib_is_loopback(const struct sk_buff *skb, const struct net_device *in)
{
return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
}
int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr); int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr);
int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr, int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
const struct nlattr * const tb[]); const struct nlattr * const tb[]);
......
...@@ -9,4 +9,6 @@ ...@@ -9,4 +9,6 @@
#define NF_LOG_MACDECODE 0x20 /* Decode MAC header */ #define NF_LOG_MACDECODE 0x20 /* Decode MAC header */
#define NF_LOG_MASK 0x2f #define NF_LOG_MASK 0x2f
#define NF_LOG_PREFIXLEN 128
#endif /* _NETFILTER_NF_LOG_H */ #endif /* _NETFILTER_NF_LOG_H */
...@@ -235,7 +235,7 @@ enum nft_rule_compat_flags { ...@@ -235,7 +235,7 @@ enum nft_rule_compat_flags {
/** /**
* enum nft_rule_compat_attributes - nf_tables rule compat attributes * enum nft_rule_compat_attributes - nf_tables rule compat attributes
* *
* @NFTA_RULE_COMPAT_PROTO: numerice value of handled protocol (NLA_U32) * @NFTA_RULE_COMPAT_PROTO: numeric value of handled protocol (NLA_U32)
* @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32) * @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32)
*/ */
enum nft_rule_compat_attributes { enum nft_rule_compat_attributes {
...@@ -499,7 +499,7 @@ enum nft_bitwise_attributes { ...@@ -499,7 +499,7 @@ enum nft_bitwise_attributes {
* enum nft_byteorder_ops - nf_tables byteorder operators * enum nft_byteorder_ops - nf_tables byteorder operators
* *
* @NFT_BYTEORDER_NTOH: network to host operator * @NFT_BYTEORDER_NTOH: network to host operator
* @NFT_BYTEORDER_HTON: host to network opertaor * @NFT_BYTEORDER_HTON: host to network operator
*/ */
enum nft_byteorder_ops { enum nft_byteorder_ops {
NFT_BYTEORDER_NTOH, NFT_BYTEORDER_NTOH,
......
...@@ -1629,6 +1629,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, ...@@ -1629,6 +1629,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
sk->sk_protocol = ip_hdr(skb)->protocol; sk->sk_protocol = ip_hdr(skb)->protocol;
sk->sk_bound_dev_if = arg->bound_dev_if; sk->sk_bound_dev_if = arg->bound_dev_if;
sk->sk_sndbuf = sysctl_wmem_default; sk->sk_sndbuf = sysctl_wmem_default;
sk->sk_mark = fl4.flowi4_mark;
err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
len, 0, &ipc, &rt, MSG_DONTWAIT); len, 0, &ipc, &rt, MSG_DONTWAIT);
if (unlikely(err)) { if (unlikely(err)) {
......
...@@ -144,7 +144,12 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry) ...@@ -144,7 +144,12 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry)
rcu_read_lock_bh(); rcu_read_lock_bh();
c = __clusterip_config_find(net, clusterip); c = __clusterip_config_find(net, clusterip);
if (c) { if (c) {
if (!c->pde || unlikely(!atomic_inc_not_zero(&c->refcount))) #ifdef CONFIG_PROC_FS
if (!c->pde)
c = NULL;
else
#endif
if (unlikely(!atomic_inc_not_zero(&c->refcount)))
c = NULL; c = NULL;
else if (entry) else if (entry)
atomic_inc(&c->entries); atomic_inc(&c->entries);
......
...@@ -63,10 +63,10 @@ static bool rpfilter_lookup_reverse(struct net *net, struct flowi4 *fl4, ...@@ -63,10 +63,10 @@ static bool rpfilter_lookup_reverse(struct net *net, struct flowi4 *fl4,
return dev_match || flags & XT_RPFILTER_LOOSE; return dev_match || flags & XT_RPFILTER_LOOSE;
} }
static bool rpfilter_is_local(const struct sk_buff *skb) static bool
rpfilter_is_loopback(const struct sk_buff *skb, const struct net_device *in)
{ {
const struct rtable *rt = skb_rtable(skb); return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
return rt && (rt->rt_flags & RTCF_LOCAL);
} }
static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
...@@ -79,7 +79,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -79,7 +79,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
info = par->matchinfo; info = par->matchinfo;
invert = info->flags & XT_RPFILTER_INVERT; invert = info->flags & XT_RPFILTER_INVERT;
if (rpfilter_is_local(skb)) if (rpfilter_is_loopback(skb, xt_in(par)))
return true ^ invert; return true ^ invert;
iph = ip_hdr(skb); iph = ip_hdr(skb);
......
...@@ -126,6 +126,8 @@ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook) ...@@ -126,6 +126,8 @@ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
/* ip_route_me_harder expects skb->dst to be set */ /* ip_route_me_harder expects skb->dst to be set */
skb_dst_set_noref(nskb, skb_dst(oldskb)); skb_dst_set_noref(nskb, skb_dst(oldskb));
nskb->mark = IP4_REPLY_MARK(net, oldskb->mark);
skb_reserve(nskb, LL_MAX_HEADER); skb_reserve(nskb, LL_MAX_HEADER);
niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP, niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
ip4_dst_hoplimit(skb_dst(nskb))); ip4_dst_hoplimit(skb_dst(nskb)));
......
...@@ -26,13 +26,6 @@ static __be32 get_saddr(__be32 addr) ...@@ -26,13 +26,6 @@ static __be32 get_saddr(__be32 addr)
return addr; return addr;
} }
static bool fib4_is_local(const struct sk_buff *skb)
{
const struct rtable *rt = skb_rtable(skb);
return rt && (rt->rt_flags & RTCF_LOCAL);
}
#define DSCP_BITS 0xfc #define DSCP_BITS 0xfc
void nft_fib4_eval_type(const struct nft_expr *expr, struct nft_regs *regs, void nft_fib4_eval_type(const struct nft_expr *expr, struct nft_regs *regs,
...@@ -95,8 +88,10 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs, ...@@ -95,8 +88,10 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
else else
oif = NULL; oif = NULL;
if (nft_hook(pkt) == NF_INET_PRE_ROUTING && fib4_is_local(pkt->skb)) { if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
nft_fib_store_result(dest, priv->result, pkt, LOOPBACK_IFINDEX); nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
nft_fib_store_result(dest, priv->result, pkt,
nft_in(pkt)->ifindex);
return; return;
} }
...@@ -131,7 +126,7 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs, ...@@ -131,7 +126,7 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
switch (res.type) { switch (res.type) {
case RTN_UNICAST: case RTN_UNICAST:
break; break;
case RTN_LOCAL: /* should not appear here, see fib4_is_local() above */ case RTN_LOCAL: /* Should not see RTN_LOCAL here */
return; return;
default: default:
break; break;
......
...@@ -72,10 +72,10 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb, ...@@ -72,10 +72,10 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
return ret; return ret;
} }
static bool rpfilter_is_local(const struct sk_buff *skb) static bool
rpfilter_is_loopback(const struct sk_buff *skb, const struct net_device *in)
{ {
const struct rt6_info *rt = (const void *) skb_dst(skb); return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
return rt && (rt->rt6i_flags & RTF_LOCAL);
} }
static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
...@@ -85,7 +85,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -85,7 +85,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
struct ipv6hdr *iph; struct ipv6hdr *iph;
bool invert = info->flags & XT_RPFILTER_INVERT; bool invert = info->flags & XT_RPFILTER_INVERT;
if (rpfilter_is_local(skb)) if (rpfilter_is_loopback(skb, xt_in(par)))
return true ^ invert; return true ^ invert;
iph = ipv6_hdr(skb); iph = ipv6_hdr(skb);
......
...@@ -157,6 +157,7 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) ...@@ -157,6 +157,7 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
fl6.fl6_sport = otcph->dest; fl6.fl6_sport = otcph->dest;
fl6.fl6_dport = otcph->source; fl6.fl6_dport = otcph->source;
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev); fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
dst = ip6_route_output(net, NULL, &fl6); dst = ip6_route_output(net, NULL, &fl6);
if (dst->error) { if (dst->error) {
...@@ -180,6 +181,8 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) ...@@ -180,6 +181,8 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
skb_dst_set(nskb, dst); skb_dst_set(nskb, dst);
nskb->mark = fl6.flowi6_mark;
skb_reserve(nskb, hh_len + dst->header_len); skb_reserve(nskb, hh_len + dst->header_len);
ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
ip6_dst_hoplimit(dst)); ip6_dst_hoplimit(dst));
......
...@@ -18,13 +18,6 @@ ...@@ -18,13 +18,6 @@
#include <net/ip6_fib.h> #include <net/ip6_fib.h>
#include <net/ip6_route.h> #include <net/ip6_route.h>
static bool fib6_is_local(const struct sk_buff *skb)
{
const struct rt6_info *rt = (const void *)skb_dst(skb);
return rt && (rt->rt6i_flags & RTF_LOCAL);
}
static int get_ifindex(const struct net_device *dev) static int get_ifindex(const struct net_device *dev)
{ {
return dev ? dev->ifindex : 0; return dev ? dev->ifindex : 0;
...@@ -164,8 +157,10 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs, ...@@ -164,8 +157,10 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif); lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif);
if (nft_hook(pkt) == NF_INET_PRE_ROUTING && fib6_is_local(pkt->skb)) { if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
nft_fib_store_result(dest, priv->result, pkt, LOOPBACK_IFINDEX); nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
nft_fib_store_result(dest, priv->result, pkt,
nft_in(pkt)->ifindex);
return; return;
} }
......
...@@ -840,6 +840,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 ...@@ -840,6 +840,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL); dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
if (!IS_ERR(dst)) { if (!IS_ERR(dst)) {
skb_dst_set(buff, dst); skb_dst_set(buff, dst);
ctl_sk->sk_mark = fl6.flowi6_mark;
ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass); ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
TCP_INC_STATS(net, TCP_MIB_OUTSEGS); TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
if (rst) if (rst)
......
...@@ -494,7 +494,7 @@ config NFT_CT ...@@ -494,7 +494,7 @@ config NFT_CT
depends on NF_CONNTRACK depends on NF_CONNTRACK
tristate "Netfilter nf_tables conntrack module" tristate "Netfilter nf_tables conntrack module"
help help
This option adds the "meta" expression that you can use to match This option adds the "ct" expression that you can use to match
connection tracking information such as the flow state. connection tracking information such as the flow state.
config NFT_SET_RBTREE config NFT_SET_RBTREE
......
...@@ -85,11 +85,11 @@ static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock); ...@@ -85,11 +85,11 @@ static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock);
static __read_mostly bool nf_conntrack_locks_all; static __read_mostly bool nf_conntrack_locks_all;
/* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */ /* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */
#define GC_MAX_BUCKETS_DIV 64u #define GC_MAX_BUCKETS_DIV 128u
/* upper bound of scan intervals */ /* upper bound of full table scan */
#define GC_INTERVAL_MAX (2 * HZ) #define GC_MAX_SCAN_JIFFIES (16u * HZ)
/* maximum conntracks to evict per gc run */ /* desired ratio of entries found to be expired */
#define GC_MAX_EVICTS 256u #define GC_EVICT_RATIO 50u
static struct conntrack_gc_work conntrack_gc_work; static struct conntrack_gc_work conntrack_gc_work;
...@@ -938,6 +938,7 @@ static noinline int early_drop(struct net *net, unsigned int _hash) ...@@ -938,6 +938,7 @@ static noinline int early_drop(struct net *net, unsigned int _hash)
static void gc_worker(struct work_struct *work) static void gc_worker(struct work_struct *work)
{ {
unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u);
unsigned int i, goal, buckets = 0, expired_count = 0; unsigned int i, goal, buckets = 0, expired_count = 0;
struct conntrack_gc_work *gc_work; struct conntrack_gc_work *gc_work;
unsigned int ratio, scanned = 0; unsigned int ratio, scanned = 0;
...@@ -979,8 +980,7 @@ static void gc_worker(struct work_struct *work) ...@@ -979,8 +980,7 @@ static void gc_worker(struct work_struct *work)
*/ */
rcu_read_unlock(); rcu_read_unlock();
cond_resched_rcu_qs(); cond_resched_rcu_qs();
} while (++buckets < goal && } while (++buckets < goal);
expired_count < GC_MAX_EVICTS);
if (gc_work->exiting) if (gc_work->exiting)
return; return;
...@@ -997,27 +997,25 @@ static void gc_worker(struct work_struct *work) ...@@ -997,27 +997,25 @@ static void gc_worker(struct work_struct *work)
* 1. Minimize time until we notice a stale entry * 1. Minimize time until we notice a stale entry
* 2. Maximize scan intervals to not waste cycles * 2. Maximize scan intervals to not waste cycles
* *
* Normally, expired_count will be 0, this increases the next_run time * Normally, expire ratio will be close to 0.
* to priorize 2) above.
* *
* As soon as a timed-out entry is found, move towards 1) and increase * As soon as a sizeable fraction of the entries have expired
* the scan frequency. * increase scan frequency.
* In case we have lots of evictions next scan is done immediately.
*/ */
ratio = scanned ? expired_count * 100 / scanned : 0; ratio = scanned ? expired_count * 100 / scanned : 0;
if (ratio >= 90 || expired_count == GC_MAX_EVICTS) { if (ratio > GC_EVICT_RATIO) {
gc_work->next_gc_run = 0; gc_work->next_gc_run = min_interval;
next_run = 0;
} else if (expired_count) {
gc_work->next_gc_run /= 2U;
next_run = msecs_to_jiffies(1);
} else { } else {
if (gc_work->next_gc_run < GC_INTERVAL_MAX) unsigned int max = GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV;
gc_work->next_gc_run += msecs_to_jiffies(1);
next_run = gc_work->next_gc_run; BUILD_BUG_ON((GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV) == 0);
gc_work->next_gc_run += min_interval;
if (gc_work->next_gc_run > max)
gc_work->next_gc_run = max;
} }
next_run = gc_work->next_gc_run;
gc_work->last_bucket = i; gc_work->last_bucket = i;
queue_delayed_work(system_long_wq, &gc_work->dwork, next_run); queue_delayed_work(system_long_wq, &gc_work->dwork, next_run);
} }
...@@ -1025,7 +1023,7 @@ static void gc_worker(struct work_struct *work) ...@@ -1025,7 +1023,7 @@ static void gc_worker(struct work_struct *work)
static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work) static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work)
{ {
INIT_DELAYED_WORK(&gc_work->dwork, gc_worker); INIT_DELAYED_WORK(&gc_work->dwork, gc_worker);
gc_work->next_gc_run = GC_INTERVAL_MAX; gc_work->next_gc_run = HZ;
gc_work->exiting = false; gc_work->exiting = false;
} }
...@@ -1917,7 +1915,7 @@ int nf_conntrack_init_start(void) ...@@ -1917,7 +1915,7 @@ int nf_conntrack_init_start(void)
nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED); nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
conntrack_gc_work_init(&conntrack_gc_work); conntrack_gc_work_init(&conntrack_gc_work);
queue_delayed_work(system_long_wq, &conntrack_gc_work.dwork, GC_INTERVAL_MAX); queue_delayed_work(system_long_wq, &conntrack_gc_work.dwork, HZ);
return 0; return 0;
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
/* Internal logging interface, which relies on the real /* Internal logging interface, which relies on the real
LOG target modules */ LOG target modules */
#define NF_LOG_PREFIXLEN 128
#define NFLOGGER_NAME_LEN 64 #define NFLOGGER_NAME_LEN 64
static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly; static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
......
...@@ -928,7 +928,8 @@ static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table, ...@@ -928,7 +928,8 @@ static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
} }
static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = { static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
[NFTA_CHAIN_TABLE] = { .type = NLA_STRING }, [NFTA_CHAIN_TABLE] = { .type = NLA_STRING,
.len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_CHAIN_HANDLE] = { .type = NLA_U64 }, [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
[NFTA_CHAIN_NAME] = { .type = NLA_STRING, [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
.len = NFT_CHAIN_MAXNAMELEN - 1 }, .len = NFT_CHAIN_MAXNAMELEN - 1 },
...@@ -1854,7 +1855,8 @@ static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain, ...@@ -1854,7 +1855,8 @@ static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
} }
static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = { static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
[NFTA_RULE_TABLE] = { .type = NLA_STRING }, [NFTA_RULE_TABLE] = { .type = NLA_STRING,
.len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_RULE_CHAIN] = { .type = NLA_STRING, [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
.len = NFT_CHAIN_MAXNAMELEN - 1 }, .len = NFT_CHAIN_MAXNAMELEN - 1 },
[NFTA_RULE_HANDLE] = { .type = NLA_U64 }, [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
...@@ -2443,7 +2445,8 @@ nft_select_set_ops(const struct nlattr * const nla[], ...@@ -2443,7 +2445,8 @@ nft_select_set_ops(const struct nlattr * const nla[],
} }
static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = { static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
[NFTA_SET_TABLE] = { .type = NLA_STRING }, [NFTA_SET_TABLE] = { .type = NLA_STRING,
.len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_NAME] = { .type = NLA_STRING, [NFTA_SET_NAME] = { .type = NLA_STRING,
.len = NFT_SET_MAXNAMELEN - 1 }, .len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_SET_FLAGS] = { .type = NLA_U32 }, [NFTA_SET_FLAGS] = { .type = NLA_U32 },
...@@ -3084,9 +3087,9 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk, ...@@ -3084,9 +3087,9 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
} }
static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
const struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
const struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
enum nft_registers dreg; enum nft_registers dreg;
...@@ -3192,8 +3195,10 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = { ...@@ -3192,8 +3195,10 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
}; };
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = { static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
[NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING }, [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING,
[NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING }, .len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING,
.len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED }, [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
[NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 }, [NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 },
}; };
...@@ -3303,9 +3308,9 @@ struct nft_set_dump_args { ...@@ -3303,9 +3308,9 @@ struct nft_set_dump_args {
}; };
static int nf_tables_dump_setelem(const struct nft_ctx *ctx, static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
const struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
const struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
struct nft_set_dump_args *args; struct nft_set_dump_args *args;
...@@ -3317,7 +3322,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -3317,7 +3322,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
{ {
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
u8 genmask = nft_genmask_cur(net); u8 genmask = nft_genmask_cur(net);
const struct nft_set *set; struct nft_set *set;
struct nft_set_dump_args args; struct nft_set_dump_args args;
struct nft_ctx ctx; struct nft_ctx ctx;
struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1]; struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
...@@ -3740,10 +3745,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -3740,10 +3745,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
goto err5; goto err5;
} }
if (set->size &&
!atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) {
err = -ENFILE;
goto err6;
}
nft_trans_elem(trans) = elem; nft_trans_elem(trans) = elem;
list_add_tail(&trans->list, &ctx->net->nft.commit_list); list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0; return 0;
err6:
set->ops->remove(set, &elem);
err5: err5:
kfree(trans); kfree(trans);
err4: err4:
...@@ -3790,15 +3803,9 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk, ...@@ -3790,15 +3803,9 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
return -EBUSY; return -EBUSY;
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
if (set->size &&
!atomic_add_unless(&set->nelems, 1, set->size + set->ndeact))
return -ENFILE;
err = nft_add_set_elem(&ctx, set, attr, nlh->nlmsg_flags); err = nft_add_set_elem(&ctx, set, attr, nlh->nlmsg_flags);
if (err < 0) { if (err < 0)
atomic_dec(&set->nelems);
break; break;
}
} }
return err; return err;
} }
...@@ -3883,9 +3890,9 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -3883,9 +3890,9 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
} }
static int nft_flush_set(const struct nft_ctx *ctx, static int nft_flush_set(const struct nft_ctx *ctx,
const struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
const struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
struct nft_trans *trans; struct nft_trans *trans;
int err; int err;
...@@ -3899,9 +3906,10 @@ static int nft_flush_set(const struct nft_ctx *ctx, ...@@ -3899,9 +3906,10 @@ static int nft_flush_set(const struct nft_ctx *ctx,
err = -ENOENT; err = -ENOENT;
goto err1; goto err1;
} }
set->ndeact++;
nft_trans_elem_set(trans) = (struct nft_set *)set; nft_trans_elem_set(trans) = set;
nft_trans_elem(trans) = *((struct nft_set_elem *)elem); nft_trans_elem(trans) = *elem;
list_add_tail(&trans->list, &ctx->net->nft.commit_list); list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0; return 0;
...@@ -4032,8 +4040,10 @@ struct nft_object *nf_tables_obj_lookup(const struct nft_table *table, ...@@ -4032,8 +4040,10 @@ struct nft_object *nf_tables_obj_lookup(const struct nft_table *table,
EXPORT_SYMBOL_GPL(nf_tables_obj_lookup); EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = { static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
[NFTA_OBJ_TABLE] = { .type = NLA_STRING }, [NFTA_OBJ_TABLE] = { .type = NLA_STRING,
[NFTA_OBJ_NAME] = { .type = NLA_STRING }, .len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_OBJ_NAME] = { .type = NLA_STRING,
.len = NFT_OBJ_MAXNAMELEN - 1 },
[NFTA_OBJ_TYPE] = { .type = NLA_U32 }, [NFTA_OBJ_TYPE] = { .type = NLA_U32 },
[NFTA_OBJ_DATA] = { .type = NLA_NESTED }, [NFTA_OBJ_DATA] = { .type = NLA_NESTED },
}; };
...@@ -4262,10 +4272,11 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -4262,10 +4272,11 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
if (idx > s_idx) if (idx > s_idx)
memset(&cb->args[1], 0, memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0])); sizeof(cb->args) - sizeof(cb->args[0]));
if (filter->table[0] && if (filter && filter->table[0] &&
strcmp(filter->table, table->name)) strcmp(filter->table, table->name))
goto cont; goto cont;
if (filter->type != NFT_OBJECT_UNSPEC && if (filter &&
filter->type != NFT_OBJECT_UNSPEC &&
obj->type->type != filter->type) obj->type->type != filter->type)
goto cont; goto cont;
...@@ -5009,9 +5020,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx, ...@@ -5009,9 +5020,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
const struct nft_chain *chain); const struct nft_chain *chain);
static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx, static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
const struct nft_set *set, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
const struct nft_set_elem *elem) struct nft_set_elem *elem)
{ {
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
const struct nft_data *data; const struct nft_data *data;
...@@ -5035,7 +5046,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx, ...@@ -5035,7 +5046,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
{ {
const struct nft_rule *rule; const struct nft_rule *rule;
const struct nft_expr *expr, *last; const struct nft_expr *expr, *last;
const struct nft_set *set; struct nft_set *set;
struct nft_set_binding *binding; struct nft_set_binding *binding;
struct nft_set_iter iter; struct nft_set_iter iter;
......
...@@ -98,7 +98,8 @@ static void nft_dynset_eval(const struct nft_expr *expr, ...@@ -98,7 +98,8 @@ static void nft_dynset_eval(const struct nft_expr *expr,
} }
static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = { static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
[NFTA_DYNSET_SET_NAME] = { .type = NLA_STRING }, [NFTA_DYNSET_SET_NAME] = { .type = NLA_STRING,
.len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_DYNSET_SET_ID] = { .type = NLA_U32 }, [NFTA_DYNSET_SET_ID] = { .type = NLA_U32 },
[NFTA_DYNSET_OP] = { .type = NLA_U32 }, [NFTA_DYNSET_OP] = { .type = NLA_U32 },
[NFTA_DYNSET_SREG_KEY] = { .type = NLA_U32 }, [NFTA_DYNSET_SREG_KEY] = { .type = NLA_U32 },
......
...@@ -39,7 +39,8 @@ static void nft_log_eval(const struct nft_expr *expr, ...@@ -39,7 +39,8 @@ static void nft_log_eval(const struct nft_expr *expr,
static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = { static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
[NFTA_LOG_GROUP] = { .type = NLA_U16 }, [NFTA_LOG_GROUP] = { .type = NLA_U16 },
[NFTA_LOG_PREFIX] = { .type = NLA_STRING }, [NFTA_LOG_PREFIX] = { .type = NLA_STRING,
.len = NF_LOG_PREFIXLEN - 1 },
[NFTA_LOG_SNAPLEN] = { .type = NLA_U32 }, [NFTA_LOG_SNAPLEN] = { .type = NLA_U32 },
[NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 }, [NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 },
[NFTA_LOG_LEVEL] = { .type = NLA_U32 }, [NFTA_LOG_LEVEL] = { .type = NLA_U32 },
......
...@@ -49,7 +49,8 @@ static void nft_lookup_eval(const struct nft_expr *expr, ...@@ -49,7 +49,8 @@ static void nft_lookup_eval(const struct nft_expr *expr,
} }
static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
[NFTA_LOOKUP_SET] = { .type = NLA_STRING }, [NFTA_LOOKUP_SET] = { .type = NLA_STRING,
.len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 },
[NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, [NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
[NFTA_LOOKUP_DREG] = { .type = NLA_U32 }, [NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
......
...@@ -193,10 +193,12 @@ nft_objref_select_ops(const struct nft_ctx *ctx, ...@@ -193,10 +193,12 @@ nft_objref_select_ops(const struct nft_ctx *ctx,
} }
static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = { static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
[NFTA_OBJREF_IMM_NAME] = { .type = NLA_STRING }, [NFTA_OBJREF_IMM_NAME] = { .type = NLA_STRING,
.len = NFT_OBJ_MAXNAMELEN - 1 },
[NFTA_OBJREF_IMM_TYPE] = { .type = NLA_U32 }, [NFTA_OBJREF_IMM_TYPE] = { .type = NLA_U32 },
[NFTA_OBJREF_SET_SREG] = { .type = NLA_U32 }, [NFTA_OBJREF_SET_SREG] = { .type = NLA_U32 },
[NFTA_OBJREF_SET_NAME] = { .type = NLA_STRING }, [NFTA_OBJREF_SET_NAME] = { .type = NLA_STRING,
.len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_OBJREF_SET_ID] = { .type = NLA_U32 }, [NFTA_OBJREF_SET_ID] = { .type = NLA_U32 },
}; };
......
...@@ -212,7 +212,7 @@ static void nft_hash_remove(const struct nft_set *set, ...@@ -212,7 +212,7 @@ static void nft_hash_remove(const struct nft_set *set,
rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params); rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params);
} }
static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_iter *iter) struct nft_set_iter *iter)
{ {
struct nft_hash *priv = nft_set_priv(set); struct nft_hash *priv = nft_set_priv(set);
......
...@@ -221,7 +221,7 @@ static void *nft_rbtree_deactivate(const struct net *net, ...@@ -221,7 +221,7 @@ static void *nft_rbtree_deactivate(const struct net *net,
} }
static void nft_rbtree_walk(const struct nft_ctx *ctx, static void nft_rbtree_walk(const struct nft_ctx *ctx,
const struct nft_set *set, struct nft_set *set,
struct nft_set_iter *iter) struct nft_set_iter *iter)
{ {
const struct nft_rbtree *priv = nft_set_priv(set); const struct nft_rbtree *priv = nft_set_priv(set);
......
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