From ae0662f84b105776734cb089703a7bf834bac195 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sat, 20 Jan 2018 04:27:58 +0800 Subject: netfilter: nf_tables: nf_tables_obj_lookup_byhandle() can be static Fixes: 3ecbfd65f50e ("netfilter: nf_tables: allocate handle and delete objects via handle") Signed-off-by: Fengguang Wu Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 8b9fe30de0cd..8cc7fc970f0c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4328,9 +4328,9 @@ struct nft_object *nf_tables_obj_lookup(const struct nft_table *table, } EXPORT_SYMBOL_GPL(nf_tables_obj_lookup); -struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table, - const struct nlattr *nla, - u32 objtype, u8 genmask) +static struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table, + const struct nlattr *nla, + u32 objtype, u8 genmask) { struct nft_object *obj; @@ -4850,7 +4850,7 @@ struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table, } EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup); -struct nft_flowtable * +static struct nft_flowtable * nf_tables_flowtable_lookup_byhandle(const struct nft_table *table, const struct nlattr *nla, u8 genmask) { -- cgit From cceae76ef3a1181242e4f7b559a7bfc904a9855c Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sun, 11 Feb 2018 19:17:20 +0900 Subject: netfilter: nfnetlink_acct: remove useless parameter parameter skb in nfnl_acct_overquota is not used anywhere. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_acct.c | 3 +-- net/netfilter/xt_nfacct.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index 88d427f9f9e6..b9505bcd3827 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c @@ -467,8 +467,7 @@ static void nfnl_overquota_report(struct net *net, struct nf_acct *nfacct) GFP_ATOMIC); } -int nfnl_acct_overquota(struct net *net, const struct sk_buff *skb, - struct nf_acct *nfacct) +int nfnl_acct_overquota(struct net *net, struct nf_acct *nfacct) { u64 now; u64 *quota; diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c index c8674deed4eb..6b56f4170860 100644 --- a/net/netfilter/xt_nfacct.c +++ b/net/netfilter/xt_nfacct.c @@ -28,7 +28,7 @@ static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par) nfnl_acct_update(skb, info->nfacct); - overquota = nfnl_acct_overquota(xt_net(par), skb, info->nfacct); + overquota = nfnl_acct_overquota(xt_net(par), info->nfacct); return overquota == NFACCT_UNDERQUOTA ? false : true; } -- cgit From 580c7d9e4cc69802189b872ad2df0d704c649441 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sun, 11 Feb 2018 22:57:29 +0900 Subject: netfilter: xt_cluster: get rid of xt_cluster_ipv6_is_multicast If use the ipv6_addr_is_multicast instead of xt_cluster_ipv6_is_multicast, then we can reduce code size. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_cluster.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c index 0068688995c8..dfbdbb2fc0ed 100644 --- a/net/netfilter/xt_cluster.c +++ b/net/netfilter/xt_cluster.c @@ -59,13 +59,6 @@ xt_cluster_hash(const struct nf_conn *ct, return reciprocal_scale(hash, info->total_nodes); } -static inline bool -xt_cluster_ipv6_is_multicast(const struct in6_addr *addr) -{ - __be32 st = addr->s6_addr32[0]; - return ((st & htonl(0xFF000000)) == htonl(0xFF000000)); -} - static inline bool xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family) { @@ -76,8 +69,7 @@ xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family) is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr); break; case NFPROTO_IPV6: - is_multicast = - xt_cluster_ipv6_is_multicast(&ipv6_hdr(skb)->daddr); + is_multicast = ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr); break; default: WARN_ON(1); -- cgit From 433029ecc62788296cacca50ceb24db90c17a4a2 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sun, 11 Feb 2018 23:28:18 +0900 Subject: netfilter: nf_conntrack_broadcast: remove useless parameter parameter protoff in nf_conntrack_broadcast_help is not used anywhere. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_broadcast.c | 1 - net/netfilter/nf_conntrack_netbios_ns.c | 5 +++-- net/netfilter/nf_conntrack_snmp.c | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c index ecc3ab784633..a1086bdec242 100644 --- a/net/netfilter/nf_conntrack_broadcast.c +++ b/net/netfilter/nf_conntrack_broadcast.c @@ -20,7 +20,6 @@ #include int nf_conntrack_broadcast_help(struct sk_buff *skb, - unsigned int protoff, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int timeout) diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c index 496ce173f0c1..a4a59dc7cf17 100644 --- a/net/netfilter/nf_conntrack_netbios_ns.c +++ b/net/netfilter/nf_conntrack_netbios_ns.c @@ -41,9 +41,10 @@ static struct nf_conntrack_expect_policy exp_policy = { }; static int netbios_ns_help(struct sk_buff *skb, unsigned int protoff, - struct nf_conn *ct, enum ip_conntrack_info ctinfo) + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) { - return nf_conntrack_broadcast_help(skb, protoff, ct, ctinfo, timeout); + return nf_conntrack_broadcast_help(skb, ct, ctinfo, timeout); } static struct nf_conntrack_helper helper __read_mostly = { diff --git a/net/netfilter/nf_conntrack_snmp.c b/net/netfilter/nf_conntrack_snmp.c index 87b95a2c270c..2d0f8e010821 100644 --- a/net/netfilter/nf_conntrack_snmp.c +++ b/net/netfilter/nf_conntrack_snmp.c @@ -36,11 +36,12 @@ int (*nf_nat_snmp_hook)(struct sk_buff *skb, EXPORT_SYMBOL_GPL(nf_nat_snmp_hook); static int snmp_conntrack_help(struct sk_buff *skb, unsigned int protoff, - struct nf_conn *ct, enum ip_conntrack_info ctinfo) + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) { typeof(nf_nat_snmp_hook) nf_nat_snmp; - nf_conntrack_broadcast_help(skb, protoff, ct, ctinfo, timeout); + nf_conntrack_broadcast_help(skb, ct, ctinfo, timeout); nf_nat_snmp = rcu_dereference(nf_nat_snmp_hook); if (nf_nat_snmp && ct->status & IPS_NAT_MASK) -- cgit From 07a9da51b4b6aece8bc71e0b1b601fc4c3eb8b64 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:27 +0100 Subject: netfilter: x_tables: check standard verdicts in core Userspace must provide a valid verdict to the standard target. The verdict can be either a jump (signed int > 0), or a return code. Allowed return codes are either RETURN (pop from stack), NF_ACCEPT, DROP and QUEUE (latter is allowed for legacy reasons). Jump offsets (verdict > 0) are checked in more detail later on when loop-detection is performed. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 49 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index d9deebe599ec..2e4d423e58e6 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -654,6 +654,31 @@ struct compat_xt_standard_target { compat_uint_t verdict; }; +static bool verdict_ok(int verdict) +{ + if (verdict > 0) + return true; + + if (verdict < 0) { + int v = -verdict - 1; + + if (verdict == XT_RETURN) + return true; + + switch (v) { + case NF_ACCEPT: return true; + case NF_DROP: return true; + case NF_QUEUE: return true; + default: + break; + } + + return false; + } + + return false; +} + int xt_compat_check_entry_offsets(const void *base, const char *elems, unsigned int target_offset, unsigned int next_offset) @@ -675,9 +700,15 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems, if (target_offset + t->u.target_size > next_offset) return -EINVAL; - if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && - COMPAT_XT_ALIGN(target_offset + sizeof(struct compat_xt_standard_target)) != next_offset) - return -EINVAL; + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) { + const struct compat_xt_standard_target *st = (const void *)t; + + if (COMPAT_XT_ALIGN(target_offset + sizeof(*st)) != next_offset) + return -EINVAL; + + if (!verdict_ok(st->verdict)) + return -EINVAL; + } /* compat_xt_entry match has less strict alignment requirements, * otherwise they are identical. In case of padding differences @@ -757,9 +788,15 @@ int xt_check_entry_offsets(const void *base, if (target_offset + t->u.target_size > next_offset) return -EINVAL; - if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && - XT_ALIGN(target_offset + sizeof(struct xt_standard_target)) != next_offset) - return -EINVAL; + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) { + const struct xt_standard_target *st = (const void *)t; + + if (XT_ALIGN(target_offset + sizeof(*st)) != next_offset) + return -EINVAL; + + if (!verdict_ok(st->verdict)) + return -EINVAL; + } return xt_check_entry_match(elems, base + target_offset, __alignof__(struct xt_entry_match)); -- cgit From 472ebdcd15ebdb8ebe20474ef1ce09abcb241e7d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:28 +0100 Subject: netfilter: x_tables: check error target size too Check that userspace ERROR target (custom user-defined chains) match expected format, and the chain name is null terminated. This is irrelevant for kernel, but iptables itself relies on sane input when it dumps rules from kernel. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 2e4d423e58e6..f045bb4f7063 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -654,6 +654,11 @@ struct compat_xt_standard_target { compat_uint_t verdict; }; +struct compat_xt_error_target { + struct compat_xt_entry_target t; + char errorname[XT_FUNCTION_MAXNAMELEN]; +}; + static bool verdict_ok(int verdict) { if (verdict > 0) @@ -679,6 +684,12 @@ static bool verdict_ok(int verdict) return false; } +static bool error_tg_ok(unsigned int usersize, unsigned int kernsize, + const char *msg, unsigned int msglen) +{ + return usersize == kernsize && strnlen(msg, msglen) < msglen; +} + int xt_compat_check_entry_offsets(const void *base, const char *elems, unsigned int target_offset, unsigned int next_offset) @@ -708,6 +719,12 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems, if (!verdict_ok(st->verdict)) return -EINVAL; + } else if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) { + const struct compat_xt_error_target *et = (const void *)t; + + if (!error_tg_ok(t->u.target_size, sizeof(*et), + et->errorname, sizeof(et->errorname))) + return -EINVAL; } /* compat_xt_entry match has less strict alignment requirements, @@ -796,6 +813,12 @@ int xt_check_entry_offsets(const void *base, if (!verdict_ok(st->verdict)) return -EINVAL; + } else if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) { + const struct xt_error_target *et = (const void *)t; + + if (!error_tg_ok(t->u.target_size, sizeof(*et), + et->errorname, sizeof(et->errorname))) + return -EINVAL; } return xt_check_entry_match(elems, base + target_offset, -- cgit From 1b293e30f759b03f246baae862bdf35e57b2c39e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:29 +0100 Subject: netfilter: x_tables: move hook entry checks into core Allow followup patch to change on location instead of three. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index f045bb4f7063..5d8ba89a8da8 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -518,6 +518,35 @@ static int xt_check_entry_match(const char *match, const char *target, return 0; } +/** xt_check_table_hooks - check hook entry points are sane + * + * @info xt_table_info to check + * @valid_hooks - hook entry points that we can enter from + * + * Validates that the hook entry and underflows points are set up. + * + * Return: 0 on success, negative errno on failure. + */ +int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_hooks) +{ + unsigned int i; + + BUILD_BUG_ON(ARRAY_SIZE(info->hook_entry) != ARRAY_SIZE(info->underflow)); + + for (i = 0; i < ARRAY_SIZE(info->hook_entry); i++) { + if (!(valid_hooks & (1 << i))) + continue; + + if (info->hook_entry[i] == 0xFFFFFFFF) + return -EINVAL; + if (info->underflow[i] == 0xFFFFFFFF) + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(xt_check_table_hooks); + #ifdef CONFIG_COMPAT int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) { -- cgit From e816a2ce49e49e3906f614009c919334a0c6ba6a Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:30 +0100 Subject: netfilter: x_tables: enforce unique and ascending entry points Harmless from kernel point of view, but iptables assumes that this is true when decoding a ruleset. iptables walks the dumped blob from kernel, and, for each entry that creates a new chain it prints out rule/chain information. Base chains (hook entry points) are thus only shown when they appear in the rule blob. One base chain that is referenced multiple times in hook blob is then only printed once. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 5d8ba89a8da8..4e6cbb38e616 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -529,10 +529,15 @@ static int xt_check_entry_match(const char *match, const char *target, */ int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_hooks) { - unsigned int i; + const char *err = "unsorted underflow"; + unsigned int i, max_uflow, max_entry; + bool check_hooks = false; BUILD_BUG_ON(ARRAY_SIZE(info->hook_entry) != ARRAY_SIZE(info->underflow)); + max_entry = 0; + max_uflow = 0; + for (i = 0; i < ARRAY_SIZE(info->hook_entry); i++) { if (!(valid_hooks & (1 << i))) continue; @@ -541,9 +546,33 @@ int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_ho return -EINVAL; if (info->underflow[i] == 0xFFFFFFFF) return -EINVAL; + + if (check_hooks) { + if (max_uflow > info->underflow[i]) + goto error; + + if (max_uflow == info->underflow[i]) { + err = "duplicate underflow"; + goto error; + } + if (max_entry > info->hook_entry[i]) { + err = "unsorted entry"; + goto error; + } + if (max_entry == info->hook_entry[i]) { + err = "duplicate entry"; + goto error; + } + } + max_entry = info->hook_entry[i]; + max_uflow = info->underflow[i]; + check_hooks = true; } return 0; +error: + pr_err_ratelimited("%s at hook %d\n", err, i); + return -EINVAL; } EXPORT_SYMBOL(xt_check_table_hooks); -- cgit From 19926968ea86a286aa6fbea16ee3f2e7442f10f0 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:31 +0100 Subject: netfilter: x_tables: cap allocations at 512 mbyte Arbitrary limit, however, this still allows huge rulesets (> 1 million rules). This helps with automated fuzzer as it prevents oom-killer invocation. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 4e6cbb38e616..dc68ac49614a 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -40,6 +40,7 @@ MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module"); #define XT_PCPU_BLOCK_SIZE 4096 +#define XT_MAX_TABLE_SIZE (512 * 1024 * 1024) struct compat_delta { unsigned int offset; /* offset in kernel */ @@ -1117,7 +1118,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size) struct xt_table_info *info = NULL; size_t sz = sizeof(*info) + size; - if (sz < sizeof(*info)) + if (sz < sizeof(*info) || sz >= XT_MAX_TABLE_SIZE) return NULL; /* __GFP_NORETRY is not fully supported by kvmalloc but it should -- cgit From 9d5c12a7c08f67999772065afd50fb222072114e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:32 +0100 Subject: netfilter: x_tables: limit allocation requests for blob rule heads This is a very conservative limit (134217728 rules), but good enough to not trigger frequent oom from syzkaller. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index dc68ac49614a..01f8e122e74e 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -894,6 +894,9 @@ EXPORT_SYMBOL(xt_check_entry_offsets); */ unsigned int *xt_alloc_entry_offsets(unsigned int size) { + if (size > XT_MAX_TABLE_SIZE / sizeof(unsigned int)) + return NULL; + return kvmalloc_array(size, sizeof(unsigned int), GFP_KERNEL | __GFP_ZERO); } -- cgit From c84ca954ac9fa67a6ce27f91f01e4451c74fd8f6 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:33 +0100 Subject: netfilter: x_tables: add counters allocation wrapper allows to have size checks in a single spot. This is supposed to reduce oom situations when fuzz-testing xtables. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 01f8e122e74e..82b1f8f52ac6 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1290,6 +1290,21 @@ static int xt_jumpstack_alloc(struct xt_table_info *i) return 0; } +struct xt_counters *xt_counters_alloc(unsigned int counters) +{ + struct xt_counters *mem; + + if (counters == 0 || counters > INT_MAX / sizeof(*mem)) + return NULL; + + counters *= sizeof(*mem); + if (counters > XT_MAX_TABLE_SIZE) + return NULL; + + return vzalloc(counters); +} +EXPORT_SYMBOL(xt_counters_alloc); + struct xt_table_info * xt_replace_table(struct xt_table *table, unsigned int num_counters, -- cgit From 9782a11efc072faaf91d4aa60e9d23553f918029 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:34 +0100 Subject: netfilter: compat: prepare xt_compat_init_offsets to return errors should have no impact, function still always returns 0. This patch is only to ease review. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 82b1f8f52ac6..e878c85a9268 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -632,10 +632,12 @@ int xt_compat_calc_jump(u_int8_t af, unsigned int offset) } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); -void xt_compat_init_offsets(u_int8_t af, unsigned int number) +int xt_compat_init_offsets(u8 af, unsigned int number) { xt[af].number = number; xt[af].cur = 0; + + return 0; } EXPORT_SYMBOL(xt_compat_init_offsets); -- cgit From 7d7d7e02111e9a4dc9d0658597f528f815d820fd Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:35 +0100 Subject: netfilter: compat: reject huge allocation requests no need to bother even trying to allocating huge compat offset arrays, such ruleset is rejected later on anyway becaus we refuse to allocate overly large rule blobs. However, compat translation happens before blob allocation, so we should add a check there too. This is supposed to help with fuzzing by avoiding oom-killer. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index e878c85a9268..33724b08b8f0 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -582,14 +582,8 @@ int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) { struct xt_af *xp = &xt[af]; - if (!xp->compat_tab) { - if (!xp->number) - return -EINVAL; - xp->compat_tab = vmalloc(sizeof(struct compat_delta) * xp->number); - if (!xp->compat_tab) - return -ENOMEM; - xp->cur = 0; - } + if (WARN_ON(!xp->compat_tab)) + return -ENOMEM; if (xp->cur >= xp->number) return -EINVAL; @@ -634,6 +628,22 @@ EXPORT_SYMBOL_GPL(xt_compat_calc_jump); int xt_compat_init_offsets(u8 af, unsigned int number) { + size_t mem; + + if (!number || number > (INT_MAX / sizeof(struct compat_delta))) + return -EINVAL; + + if (WARN_ON(xt[af].compat_tab)) + return -EINVAL; + + mem = sizeof(struct compat_delta) * number; + if (mem > XT_MAX_TABLE_SIZE) + return -ENOMEM; + + xt[af].compat_tab = vmalloc(mem); + if (!xt[af].compat_tab) + return -ENOMEM; + xt[af].number = number; xt[af].cur = 0; -- cgit From 89370860686a54fc0642c7ae68213cc1fc6d8e04 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:36 +0100 Subject: netfilter: x_tables: make sure compat af mutex is held Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 33724b08b8f0..7521e8a72c06 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -582,6 +582,8 @@ int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) { struct xt_af *xp = &xt[af]; + WARN_ON(!mutex_is_locked(&xt[af].compat_mutex)); + if (WARN_ON(!xp->compat_tab)) return -ENOMEM; @@ -599,6 +601,8 @@ EXPORT_SYMBOL_GPL(xt_compat_add_offset); void xt_compat_flush_offsets(u_int8_t af) { + WARN_ON(!mutex_is_locked(&xt[af].compat_mutex)); + if (xt[af].compat_tab) { vfree(xt[af].compat_tab); xt[af].compat_tab = NULL; @@ -630,6 +634,8 @@ int xt_compat_init_offsets(u8 af, unsigned int number) { size_t mem; + WARN_ON(!mutex_is_locked(&xt[af].compat_mutex)); + if (!number || number > (INT_MAX / sizeof(struct compat_delta))) return -EINVAL; -- cgit From 3427b2ab63faccafe774ea997fc2da7faf690c5a Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 1 Mar 2018 18:58:38 -0800 Subject: netfilter: make xt_rateest hash table per net As suggested by Eric, we need to make the xt_rateest hash table and its lock per netns to reduce lock contentions. Cc: Florian Westphal Cc: Eric Dumazet Cc: Pablo Neira Ayuso Signed-off-by: Cong Wang Reviewed-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_RATEEST.c | 91 +++++++++++++++++++++++++++++++++------------- net/netfilter/xt_rateest.c | 10 ++--- 2 files changed, 70 insertions(+), 31 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c index 141c295191f6..dec843cadf46 100644 --- a/net/netfilter/xt_RATEEST.c +++ b/net/netfilter/xt_RATEEST.c @@ -14,15 +14,21 @@ #include #include #include +#include #include #include #include -static DEFINE_MUTEX(xt_rateest_mutex); - #define RATEEST_HSIZE 16 -static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly; + +struct xt_rateest_net { + struct mutex hash_lock; + struct hlist_head hash[RATEEST_HSIZE]; +}; + +static unsigned int xt_rateest_id; + static unsigned int jhash_rnd __read_mostly; static unsigned int xt_rateest_hash(const char *name) @@ -31,21 +37,23 @@ static unsigned int xt_rateest_hash(const char *name) (RATEEST_HSIZE - 1); } -static void xt_rateest_hash_insert(struct xt_rateest *est) +static void xt_rateest_hash_insert(struct xt_rateest_net *xn, + struct xt_rateest *est) { unsigned int h; h = xt_rateest_hash(est->name); - hlist_add_head(&est->list, &rateest_hash[h]); + hlist_add_head(&est->list, &xn->hash[h]); } -static struct xt_rateest *__xt_rateest_lookup(const char *name) +static struct xt_rateest *__xt_rateest_lookup(struct xt_rateest_net *xn, + const char *name) { struct xt_rateest *est; unsigned int h; h = xt_rateest_hash(name); - hlist_for_each_entry(est, &rateest_hash[h], list) { + hlist_for_each_entry(est, &xn->hash[h], list) { if (strcmp(est->name, name) == 0) { est->refcnt++; return est; @@ -55,20 +63,23 @@ static struct xt_rateest *__xt_rateest_lookup(const char *name) return NULL; } -struct xt_rateest *xt_rateest_lookup(const char *name) +struct xt_rateest *xt_rateest_lookup(struct net *net, const char *name) { + struct xt_rateest_net *xn = net_generic(net, xt_rateest_id); struct xt_rateest *est; - mutex_lock(&xt_rateest_mutex); - est = __xt_rateest_lookup(name); - mutex_unlock(&xt_rateest_mutex); + mutex_lock(&xn->hash_lock); + est = __xt_rateest_lookup(xn, name); + mutex_unlock(&xn->hash_lock); return est; } EXPORT_SYMBOL_GPL(xt_rateest_lookup); -void xt_rateest_put(struct xt_rateest *est) +void xt_rateest_put(struct net *net, struct xt_rateest *est) { - mutex_lock(&xt_rateest_mutex); + struct xt_rateest_net *xn = net_generic(net, xt_rateest_id); + + mutex_lock(&xn->hash_lock); if (--est->refcnt == 0) { hlist_del(&est->list); gen_kill_estimator(&est->rate_est); @@ -78,7 +89,7 @@ void xt_rateest_put(struct xt_rateest *est) */ kfree_rcu(est, rcu); } - mutex_unlock(&xt_rateest_mutex); + mutex_unlock(&xn->hash_lock); } EXPORT_SYMBOL_GPL(xt_rateest_put); @@ -98,6 +109,7 @@ xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par) static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) { + struct xt_rateest_net *xn = net_generic(par->net, xt_rateest_id); struct xt_rateest_target_info *info = par->targinfo; struct xt_rateest *est; struct { @@ -108,10 +120,10 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) net_get_random_once(&jhash_rnd, sizeof(jhash_rnd)); - mutex_lock(&xt_rateest_mutex); - est = __xt_rateest_lookup(info->name); + mutex_lock(&xn->hash_lock); + est = __xt_rateest_lookup(xn, info->name); if (est) { - mutex_unlock(&xt_rateest_mutex); + mutex_unlock(&xn->hash_lock); /* * If estimator parameters are specified, they must match the * existing estimator. @@ -119,7 +131,7 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) if ((!info->interval && !info->ewma_log) || (info->interval != est->params.interval || info->ewma_log != est->params.ewma_log)) { - xt_rateest_put(est); + xt_rateest_put(par->net, est); return -EINVAL; } info->est = est; @@ -148,14 +160,14 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) goto err2; info->est = est; - xt_rateest_hash_insert(est); - mutex_unlock(&xt_rateest_mutex); + xt_rateest_hash_insert(xn, est); + mutex_unlock(&xn->hash_lock); return 0; err2: kfree(est); err1: - mutex_unlock(&xt_rateest_mutex); + mutex_unlock(&xn->hash_lock); return ret; } @@ -163,7 +175,7 @@ static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par) { struct xt_rateest_target_info *info = par->targinfo; - xt_rateest_put(info->est); + xt_rateest_put(par->net, info->est); } static struct xt_target xt_rateest_tg_reg __read_mostly = { @@ -178,19 +190,46 @@ static struct xt_target xt_rateest_tg_reg __read_mostly = { .me = THIS_MODULE, }; -static int __init xt_rateest_tg_init(void) +static __net_init int xt_rateest_net_init(struct net *net) +{ + struct xt_rateest_net *xn = net_generic(net, xt_rateest_id); + int i; + + mutex_init(&xn->hash_lock); + for (i = 0; i < ARRAY_SIZE(xn->hash); i++) + INIT_HLIST_HEAD(&xn->hash[i]); + return 0; +} + +static void __net_exit xt_rateest_net_exit(struct net *net) { - unsigned int i; + struct xt_rateest_net *xn = net_generic(net, xt_rateest_id); + int i; + + for (i = 0; i < ARRAY_SIZE(xn->hash); i++) + WARN_ON_ONCE(!hlist_empty(&xn->hash[i])); +} - for (i = 0; i < ARRAY_SIZE(rateest_hash); i++) - INIT_HLIST_HEAD(&rateest_hash[i]); +static struct pernet_operations xt_rateest_net_ops = { + .init = xt_rateest_net_init, + .exit = xt_rateest_net_exit, + .id = &xt_rateest_id, + .size = sizeof(struct xt_rateest_net), +}; + +static int __init xt_rateest_tg_init(void) +{ + int err = register_pernet_subsys(&xt_rateest_net_ops); + if (err) + return err; return xt_register_target(&xt_rateest_tg_reg); } static void __exit xt_rateest_tg_fini(void) { xt_unregister_target(&xt_rateest_tg_reg); + unregister_pernet_subsys(&xt_rateest_net_ops); } diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c index 755d2f6693a2..bf77326861af 100644 --- a/net/netfilter/xt_rateest.c +++ b/net/netfilter/xt_rateest.c @@ -95,13 +95,13 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) } ret = -ENOENT; - est1 = xt_rateest_lookup(info->name1); + est1 = xt_rateest_lookup(par->net, info->name1); if (!est1) goto err1; est2 = NULL; if (info->flags & XT_RATEEST_MATCH_REL) { - est2 = xt_rateest_lookup(info->name2); + est2 = xt_rateest_lookup(par->net, info->name2); if (!est2) goto err2; } @@ -111,7 +111,7 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) return 0; err2: - xt_rateest_put(est1); + xt_rateest_put(par->net, est1); err1: return ret; } @@ -120,9 +120,9 @@ static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par) { struct xt_rateest_match_info *info = par->matchinfo; - xt_rateest_put(info->est1); + xt_rateest_put(par->net, info->est1); if (info->est2) - xt_rateest_put(info->est2); + xt_rateest_put(par->net, info->est2); } static struct xt_match xt_rateest_mt_reg __read_mostly = { -- cgit From 010eacd968a73ddcb8592b14c1607e1004120ede Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 2 Mar 2018 14:59:54 +0100 Subject: netfilter: xt_limit: Spelling s/maxmum/maximum/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_limit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/netfilter') diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index 55d18cd67635..9f098ecb2449 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c @@ -46,7 +46,7 @@ MODULE_ALIAS("ip6t_limit"); See Alexey's formal explanation in net/sched/sch_tbf.c. - To get the maxmum range, we multiply by this factor (ie. you get N + To get the maximum range, we multiply by this factor (ie. you get N credits per jiffy). We want to allow a rate as low as 1 per day (slowest userspace tool allows), which means CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */ -- cgit From 72597135cdd2fe524f9a185d7f954c2c3980f3ee Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Mar 2018 08:26:00 +0100 Subject: netfilter: x_tables: fix build with CONFIG_COMPAT=n I placed the helpers within CONFIG_COMPAT section, move them outside. Fixes: 472ebdcd15ebdb ("netfilter: x_tables: check error target size too") Fixes: 07a9da51b4b6ae ("netfilter: x_tables: check standard verdicts in core") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 62 ++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 7521e8a72c06..bac932f1c582 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -577,6 +577,37 @@ error: } EXPORT_SYMBOL(xt_check_table_hooks); +static bool verdict_ok(int verdict) +{ + if (verdict > 0) + return true; + + if (verdict < 0) { + int v = -verdict - 1; + + if (verdict == XT_RETURN) + return true; + + switch (v) { + case NF_ACCEPT: return true; + case NF_DROP: return true; + case NF_QUEUE: return true; + default: + break; + } + + return false; + } + + return false; +} + +static bool error_tg_ok(unsigned int usersize, unsigned int kernsize, + const char *msg, unsigned int msglen) +{ + return usersize == kernsize && strnlen(msg, msglen) < msglen; +} + #ifdef CONFIG_COMPAT int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) { @@ -736,37 +767,6 @@ struct compat_xt_error_target { char errorname[XT_FUNCTION_MAXNAMELEN]; }; -static bool verdict_ok(int verdict) -{ - if (verdict > 0) - return true; - - if (verdict < 0) { - int v = -verdict - 1; - - if (verdict == XT_RETURN) - return true; - - switch (v) { - case NF_ACCEPT: return true; - case NF_DROP: return true; - case NF_QUEUE: return true; - default: - break; - } - - return false; - } - - return false; -} - -static bool error_tg_ok(unsigned int usersize, unsigned int kernsize, - const char *msg, unsigned int msglen) -{ - return usersize == kernsize && strnlen(msg, msglen) < msglen; -} - int xt_compat_check_entry_offsets(const void *base, const char *elems, unsigned int target_offset, unsigned int next_offset) -- cgit From a55efe1d416c345a73bef38848e1ac7109560e12 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 5 Mar 2018 15:35:57 -0600 Subject: ipvs: use true and false for boolean values Assign true or false to boolean variables instead of an integer value. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipvs/ip_vs_lblc.c | 4 ++-- net/netfilter/ipvs/ip_vs_lblcr.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 6a340c94c4b8..942e835caf7f 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -238,7 +238,7 @@ static void ip_vs_lblc_flush(struct ip_vs_service *svc) int i; spin_lock_bh(&svc->sched_lock); - tbl->dead = 1; + tbl->dead = true; for (i = 0; i < IP_VS_LBLC_TAB_SIZE; i++) { hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) { ip_vs_lblc_del(en); @@ -369,7 +369,7 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc) tbl->max_size = IP_VS_LBLC_TAB_SIZE*16; tbl->rover = 0; tbl->counter = 1; - tbl->dead = 0; + tbl->dead = false; tbl->svc = svc; /* diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 0627881128da..a5acab25c36b 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -404,7 +404,7 @@ static void ip_vs_lblcr_flush(struct ip_vs_service *svc) struct hlist_node *next; spin_lock_bh(&svc->sched_lock); - tbl->dead = 1; + tbl->dead = true; for (i = 0; i < IP_VS_LBLCR_TAB_SIZE; i++) { hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) { ip_vs_lblcr_free(en); @@ -532,7 +532,7 @@ static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc) tbl->max_size = IP_VS_LBLCR_TAB_SIZE*16; tbl->rover = 0; tbl->counter = 1; - tbl->dead = 0; + tbl->dead = false; tbl->svc = svc; /* -- cgit From 6aec208786c2a54cbf6135a0242b224e845bef98 Mon Sep 17 00:00:00 2001 From: Yi-Hung Wei Date: Sun, 4 Mar 2018 15:29:51 -0800 Subject: netfilter: Refactor nf_conncount Remove parameter 'family' in nf_conncount_count() and count_tree(). It is because the parameter is not useful after commit 625c556118f3 ("netfilter: connlimit: split xt_connlimit into front and backend"). Signed-off-by: Yi-Hung Wei Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conncount.c | 4 +--- net/netfilter/xt_connlimit.c | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index 6d65389e308f..9305a08b4422 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -158,7 +158,6 @@ static void tree_nodes_free(struct rb_root *root, static unsigned int count_tree(struct net *net, struct rb_root *root, const u32 *key, u8 keylen, - u8 family, const struct nf_conntrack_tuple *tuple, const struct nf_conntrack_zone *zone) { @@ -246,7 +245,6 @@ count_tree(struct net *net, struct rb_root *root, unsigned int nf_conncount_count(struct net *net, struct nf_conncount_data *data, const u32 *key, - unsigned int family, const struct nf_conntrack_tuple *tuple, const struct nf_conntrack_zone *zone) { @@ -259,7 +257,7 @@ unsigned int nf_conncount_count(struct net *net, spin_lock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]); - count = count_tree(net, root, key, data->keylen, family, tuple, zone); + count = count_tree(net, root, key, data->keylen, tuple, zone); spin_unlock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]); diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index b1b17b9353e1..6275106ccf50 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -67,8 +67,8 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) key[1] = zone->id; } - connections = nf_conncount_count(net, info->data, key, - xt_family(par), tuple_ptr, zone); + connections = nf_conncount_count(net, info->data, key, tuple_ptr, + zone); if (connections == 0) /* kmalloc failed, drop it entirely */ goto hotdrop; -- cgit From 35d8deb80c30fdb2dee3e2dac71eab00d8a6fed5 Mon Sep 17 00:00:00 2001 From: Yi-Hung Wei Date: Sun, 4 Mar 2018 15:29:52 -0800 Subject: netfilter: conncount: Support count only use case Currently, nf_conncount_count() counts the number of connections that matches key and inserts a conntrack 'tuple' with the same key into the accounting data structure. This patch supports another use case that only counts the number of connections where 'tuple' is not provided. Therefore, proper changes are made on nf_conncount_count() to support the case where 'tuple' is NULL. This could be useful for querying statistics or debugging purpose. Signed-off-by: Yi-Hung Wei Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conncount.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index 9305a08b4422..153e690e2893 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -104,7 +104,7 @@ static unsigned int check_hlist(struct net *net, struct nf_conn *found_ct; unsigned int length = 0; - *addit = true; + *addit = tuple ? true : false; /* check the saved connections */ hlist_for_each_entry_safe(conn, n, head, node) { @@ -117,7 +117,7 @@ static unsigned int check_hlist(struct net *net, found_ct = nf_ct_tuplehash_to_ctrack(found); - if (nf_ct_tuple_equal(&conn->tuple, tuple)) { + if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple)) { /* * Just to be sure we have it only once in the list. * We should not see tuples twice unless someone hooks @@ -220,6 +220,9 @@ count_tree(struct net *net, struct rb_root *root, goto restart; } + if (!tuple) + return 0; + /* no match, need to insert new node */ rbconn = kmem_cache_alloc(conncount_rb_cachep, GFP_ATOMIC); if (rbconn == NULL) @@ -242,6 +245,9 @@ count_tree(struct net *net, struct rb_root *root, return 1; } +/* Count and return number of conntrack entries in 'net' with particular 'key'. + * If 'tuple' is not null, insert it into the accounting data structure. + */ unsigned int nf_conncount_count(struct net *net, struct nf_conncount_data *data, const u32 *key, -- cgit From d719e3f21cf91d3f82bd827d46199ba41af2f73a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 9 Mar 2018 11:57:20 +0100 Subject: netfilter: nft_ct: add NFT_CT_{SRC,DST}_{IP,IP6} All existing keys, except the NFT_CT_SRC and NFT_CT_DST are assumed to have strict datatypes. This is causing problems with sets and concatenations given the specific length of these keys is not known. Signed-off-by: Pablo Neira Ayuso Acked-by: Florian Westphal --- net/netfilter/nft_ct.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'net/netfilter') diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 6ab274b14484..ea737fd789e8 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -196,6 +196,26 @@ static void nft_ct_get_eval(const struct nft_expr *expr, case NFT_CT_PROTO_DST: nft_reg_store16(dest, (__force u16)tuple->dst.u.all); return; + case NFT_CT_SRC_IP: + if (nf_ct_l3num(ct) != NFPROTO_IPV4) + goto err; + *dest = tuple->src.u3.ip; + return; + case NFT_CT_DST_IP: + if (nf_ct_l3num(ct) != NFPROTO_IPV4) + goto err; + *dest = tuple->dst.u3.ip; + return; + case NFT_CT_SRC_IP6: + if (nf_ct_l3num(ct) != NFPROTO_IPV6) + goto err; + memcpy(dest, tuple->src.u3.ip6, sizeof(struct in6_addr)); + return; + case NFT_CT_DST_IP6: + if (nf_ct_l3num(ct) != NFPROTO_IPV6) + goto err; + memcpy(dest, tuple->dst.u3.ip6, sizeof(struct in6_addr)); + return; default: break; } @@ -419,6 +439,20 @@ static int nft_ct_get_init(const struct nft_ctx *ctx, return -EAFNOSUPPORT; } break; + case NFT_CT_SRC_IP: + case NFT_CT_DST_IP: + if (tb[NFTA_CT_DIRECTION] == NULL) + return -EINVAL; + + len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u3.ip); + break; + case NFT_CT_SRC_IP6: + case NFT_CT_DST_IP6: + if (tb[NFTA_CT_DIRECTION] == NULL) + return -EINVAL; + + len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u3.ip6); + break; case NFT_CT_PROTO_SRC: case NFT_CT_PROTO_DST: if (tb[NFTA_CT_DIRECTION] == NULL) @@ -588,6 +622,10 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr) switch (priv->key) { case NFT_CT_SRC: case NFT_CT_DST: + case NFT_CT_SRC_IP: + case NFT_CT_DST_IP: + case NFT_CT_SRC_IP6: + case NFT_CT_DST_IP6: case NFT_CT_PROTO_SRC: case NFT_CT_PROTO_DST: if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir)) -- cgit From 8039ab43eeac029a9c47c0411918ea82c9ce87cd Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 12 Mar 2018 18:14:42 -0500 Subject: netfilter: cttimeout: remove VLA usage In preparation to enabling -Wvla, remove VLA and replace it with dynamic memory allocation. >From a security viewpoint, the use of Variable Length Arrays can be a vector for stack overflow attacks. Also, in general, as the code evolves it is easy to lose track of how big a VLA can get. Thus, we can end up having segfaults that are hard to debug. Also, fixed as part of the directive to remove all VLAs from the kernel: https://lkml.org/lkml/2018/3/7/621 While at it, remove likely() notation which is not necessary from the control plane code. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_cttimeout.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 95b04702a655..9ee5fa551fa6 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -51,19 +51,27 @@ ctnl_timeout_parse_policy(void *timeouts, const struct nf_conntrack_l4proto *l4proto, struct net *net, const struct nlattr *attr) { + struct nlattr **tb; int ret = 0; - if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) { - struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1]; + if (!l4proto->ctnl_timeout.nlattr_to_obj) + return 0; - ret = nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, - attr, l4proto->ctnl_timeout.nla_policy, - NULL); - if (ret < 0) - return ret; + tb = kcalloc(l4proto->ctnl_timeout.nlattr_max + 1, sizeof(*tb), + GFP_KERNEL); - ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts); - } + if (!tb) + return -ENOMEM; + + ret = nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, attr, + l4proto->ctnl_timeout.nla_policy, NULL); + if (ret < 0) + goto err; + + ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts); + +err: + kfree(tb); return ret; } -- cgit From 1446385904add0e89f990ee0518434365e50ce86 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 12 Mar 2018 19:21:38 -0500 Subject: netfilter: nfnetlink_cthelper: Remove VLA usage In preparation to enabling -Wvla, remove VLA and replace it with dynamic memory allocation. >From a security viewpoint, the use of Variable Length Arrays can be a vector for stack overflow attacks. Also, in general, as the code evolves it is easy to lose track of how big a VLA can get. Thus, we can end up having segfaults that are hard to debug. Also, fixed as part of the directive to remove all VLAs from the kernel: https://lkml.org/lkml/2018/3/7/621 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_cthelper.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index d33ce6d5ebce..4a4b293fb2e5 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -314,23 +314,30 @@ nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy, static int nfnl_cthelper_update_policy_all(struct nlattr *tb[], struct nf_conntrack_helper *helper) { - struct nf_conntrack_expect_policy new_policy[helper->expect_class_max + 1]; + struct nf_conntrack_expect_policy *new_policy; struct nf_conntrack_expect_policy *policy; - int i, err; + int i, ret = 0; + + new_policy = kmalloc_array(helper->expect_class_max + 1, + sizeof(*new_policy), GFP_KERNEL); + if (!new_policy) + return -ENOMEM; /* Check first that all policy attributes are well-formed, so we don't * leave things in inconsistent state on errors. */ for (i = 0; i < helper->expect_class_max + 1; i++) { - if (!tb[NFCTH_POLICY_SET + i]) - return -EINVAL; + if (!tb[NFCTH_POLICY_SET + i]) { + ret = -EINVAL; + goto err; + } - err = nfnl_cthelper_update_policy_one(&helper->expect_policy[i], + ret = nfnl_cthelper_update_policy_one(&helper->expect_policy[i], &new_policy[i], tb[NFCTH_POLICY_SET + i]); - if (err < 0) - return err; + if (ret < 0) + goto err; } /* Now we can safely update them. */ for (i = 0; i < helper->expect_class_max + 1; i++) { @@ -340,7 +347,9 @@ static int nfnl_cthelper_update_policy_all(struct nlattr *tb[], policy->timeout = new_policy->timeout; } - return 0; +err: + kfree(new_policy); + return ret; } static int nfnl_cthelper_update_policy(struct nf_conntrack_helper *helper, -- cgit From 5b4c6e3860daaf089c28e0161dffef7b5ad8000f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 12 Mar 2018 22:16:17 -0500 Subject: netfilter: nf_tables: remove VLA usage In preparation to enabling -Wvla, remove VLA and replace it with dynamic memory allocation. >From a security viewpoint, the use of Variable Length Arrays can be a vector for stack overflow attacks. Also, in general, as the code evolves it is easy to lose track of how big a VLA can get. Thus, we can end up having segfaults that are hard to debug. Also, fixed as part of the directive to remove all VLAs from the kernel: https://lkml.org/lkml/2018/3/7/621 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 8cc7fc970f0c..92f5606b0dea 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4357,16 +4357,20 @@ static struct nft_object *nft_obj_init(const struct nft_ctx *ctx, const struct nft_object_type *type, const struct nlattr *attr) { - struct nlattr *tb[type->maxattr + 1]; + struct nlattr **tb; const struct nft_object_ops *ops; struct nft_object *obj; - int err; + int err = -ENOMEM; + + tb = kmalloc_array(type->maxattr + 1, sizeof(*tb), GFP_KERNEL); + if (!tb) + goto err1; if (attr) { err = nla_parse_nested(tb, type->maxattr, attr, type->policy, NULL); if (err < 0) - goto err1; + goto err2; } else { memset(tb, 0, sizeof(tb[0]) * (type->maxattr + 1)); } @@ -4375,7 +4379,7 @@ static struct nft_object *nft_obj_init(const struct nft_ctx *ctx, ops = type->select_ops(ctx, (const struct nlattr * const *)tb); if (IS_ERR(ops)) { err = PTR_ERR(ops); - goto err1; + goto err2; } } else { ops = type->ops; @@ -4383,18 +4387,21 @@ static struct nft_object *nft_obj_init(const struct nft_ctx *ctx, err = -ENOMEM; obj = kzalloc(sizeof(*obj) + ops->size, GFP_KERNEL); - if (obj == NULL) - goto err1; + if (!obj) + goto err2; err = ops->init(ctx, (const struct nlattr * const *)tb, obj); if (err < 0) - goto err2; + goto err3; obj->ops = ops; + kfree(tb); return obj; -err2: +err3: kfree(obj); +err2: + kfree(tb); err1: return ERR_PTR(err); } -- cgit From 472a73e00757b971d613d796374d2727b2e4954d Mon Sep 17 00:00:00 2001 From: Jack Ma Date: Mon, 19 Mar 2018 09:41:59 +1300 Subject: netfilter: xt_conntrack: Support bit-shifting for CONNMARK & MARK targets. This patch introduces a new feature that allows bitshifting (left and right) operations to co-operate with existing iptables options. Reviewed-by: Florian Westphal Signed-off-by: Jack Ma Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connmark.c | 77 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 17 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 809639ce6f5a..773da82190dc 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -36,9 +36,10 @@ MODULE_ALIAS("ipt_connmark"); MODULE_ALIAS("ip6t_connmark"); static unsigned int -connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) +connmark_tg_shift(struct sk_buff *skb, + const struct xt_connmark_tginfo1 *info, + u8 shift_bits, u8 shift_dir) { - const struct xt_connmark_tginfo1 *info = par->targinfo; enum ip_conntrack_info ctinfo; struct nf_conn *ct; u_int32_t newmark; @@ -50,6 +51,10 @@ connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) switch (info->mode) { case XT_CONNMARK_SET: newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; + if (shift_dir == D_SHIFT_RIGHT) + newmark >>= shift_bits; + else + newmark <<= shift_bits; if (ct->mark != newmark) { ct->mark = newmark; nf_conntrack_event_cache(IPCT_MARK, ct); @@ -57,7 +62,11 @@ connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) break; case XT_CONNMARK_SAVE: newmark = (ct->mark & ~info->ctmask) ^ - (skb->mark & info->nfmask); + (skb->mark & info->nfmask); + if (shift_dir == D_SHIFT_RIGHT) + newmark >>= shift_bits; + else + newmark <<= shift_bits; if (ct->mark != newmark) { ct->mark = newmark; nf_conntrack_event_cache(IPCT_MARK, ct); @@ -65,14 +74,34 @@ connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) break; case XT_CONNMARK_RESTORE: newmark = (skb->mark & ~info->nfmask) ^ - (ct->mark & info->ctmask); + (ct->mark & info->ctmask); + if (shift_dir == D_SHIFT_RIGHT) + newmark >>= shift_bits; + else + newmark <<= shift_bits; skb->mark = newmark; break; } - return XT_CONTINUE; } +static unsigned int +connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_connmark_tginfo1 *info = par->targinfo; + + return connmark_tg_shift(skb, info, 0, 0); +} + +static unsigned int +connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_connmark_tginfo2 *info = par->targinfo; + + return connmark_tg_shift(skb, (const struct xt_connmark_tginfo1 *)info, + info->shift_bits, info->shift_dir); +} + static int connmark_tg_check(const struct xt_tgchk_param *par) { int ret; @@ -119,15 +148,27 @@ static void connmark_mt_destroy(const struct xt_mtdtor_param *par) nf_ct_netns_put(par->net, par->family); } -static struct xt_target connmark_tg_reg __read_mostly = { - .name = "CONNMARK", - .revision = 1, - .family = NFPROTO_UNSPEC, - .checkentry = connmark_tg_check, - .target = connmark_tg, - .targetsize = sizeof(struct xt_connmark_tginfo1), - .destroy = connmark_tg_destroy, - .me = THIS_MODULE, +static struct xt_target connmark_tg_reg[] __read_mostly = { + { + .name = "CONNMARK", + .revision = 1, + .family = NFPROTO_UNSPEC, + .checkentry = connmark_tg_check, + .target = connmark_tg, + .targetsize = sizeof(struct xt_connmark_tginfo1), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, + }, + { + .name = "CONNMARK", + .revision = 2, + .family = NFPROTO_UNSPEC, + .checkentry = connmark_tg_check, + .target = connmark_tg_v2, + .targetsize = sizeof(struct xt_connmark_tginfo2), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, + } }; static struct xt_match connmark_mt_reg __read_mostly = { @@ -145,12 +186,14 @@ static int __init connmark_mt_init(void) { int ret; - ret = xt_register_target(&connmark_tg_reg); + ret = xt_register_targets(connmark_tg_reg, + ARRAY_SIZE(connmark_tg_reg)); if (ret < 0) return ret; ret = xt_register_match(&connmark_mt_reg); if (ret < 0) { - xt_unregister_target(&connmark_tg_reg); + xt_unregister_targets(connmark_tg_reg, + ARRAY_SIZE(connmark_tg_reg)); return ret; } return 0; @@ -159,7 +202,7 @@ static int __init connmark_mt_init(void) static void __exit connmark_mt_exit(void) { xt_unregister_match(&connmark_mt_reg); - xt_unregister_target(&connmark_tg_reg); + xt_unregister_target(connmark_tg_reg); } module_init(connmark_mt_init); -- cgit From 5191d70f83fd1878c40029cffe69f6a2bf65fa0e Mon Sep 17 00:00:00 2001 From: Arushi Singhal Date: Mon, 12 Mar 2018 18:36:29 +0530 Subject: netfilter: Replace printk() with pr_*() and define pr_fmt() Using pr_() is more concise than printk(KERN_). This patch: * Replace printks having a log level with the appropriate pr_*() macros. * Define pr_fmt() to include relevant name. * Remove redundant prefixes from pr_*() calls. * Indent the code where possible. * Remove the useless output messages. * Remove periods from messages. Signed-off-by: Arushi Singhal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_acct.c | 6 ++++-- net/netfilter/nf_conntrack_ecache.c | 6 ++++-- net/netfilter/nf_conntrack_timestamp.c | 6 ++++-- net/netfilter/nf_nat_core.c | 4 +++- net/netfilter/nf_nat_ftp.c | 7 ++++--- net/netfilter/nf_nat_irc.c | 7 ++++--- net/netfilter/nfnetlink_queue.c | 14 +++++++------- net/netfilter/xt_time.c | 13 +++++++------ 8 files changed, 37 insertions(+), 26 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c index 866916712905..1d66de5151b2 100644 --- a/net/netfilter/nf_conntrack_acct.c +++ b/net/netfilter/nf_conntrack_acct.c @@ -8,6 +8,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -80,7 +82,7 @@ static int nf_conntrack_acct_init_sysctl(struct net *net) net->ct.acct_sysctl_header = register_net_sysctl(net, "net/netfilter", table); if (!net->ct.acct_sysctl_header) { - printk(KERN_ERR "nf_conntrack_acct: can't register to sysctl.\n"); + pr_err("can't register to sysctl\n"); goto out_register; } return 0; @@ -125,7 +127,7 @@ int nf_conntrack_acct_init(void) { int ret = nf_ct_extend_register(&acct_extend); if (ret < 0) - pr_err("nf_conntrack_acct: Unable to register extension\n"); + pr_err("Unable to register extension\n"); return ret; } diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index caac41ad9483..c11822a7d2bf 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -372,7 +374,7 @@ static int nf_conntrack_event_init_sysctl(struct net *net) net->ct.event_sysctl_header = register_net_sysctl(net, "net/netfilter", table); if (!net->ct.event_sysctl_header) { - printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n"); + pr_err("can't register to sysctl\n"); goto out_register; } return 0; @@ -419,7 +421,7 @@ int nf_conntrack_ecache_init(void) { int ret = nf_ct_extend_register(&event_extend); if (ret < 0) - pr_err("nf_ct_event: Unable to register event extension.\n"); + pr_err("Unable to register event extension\n"); BUILD_BUG_ON(__IPCT_MAX >= 16); /* ctmask, missed use u16 */ diff --git a/net/netfilter/nf_conntrack_timestamp.c b/net/netfilter/nf_conntrack_timestamp.c index 4c4734b78318..56766cb26e40 100644 --- a/net/netfilter/nf_conntrack_timestamp.c +++ b/net/netfilter/nf_conntrack_timestamp.c @@ -6,6 +6,8 @@ * published by the Free Software Foundation (or any later at your option). */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -58,7 +60,7 @@ static int nf_conntrack_tstamp_init_sysctl(struct net *net) net->ct.tstamp_sysctl_header = register_net_sysctl(net, "net/netfilter", table); if (!net->ct.tstamp_sysctl_header) { - printk(KERN_ERR "nf_ct_tstamp: can't register to sysctl.\n"); + pr_err("can't register to sysctl\n"); goto out_register; } return 0; @@ -104,7 +106,7 @@ int nf_conntrack_tstamp_init(void) int ret; ret = nf_ct_extend_register(&tstamp_extend); if (ret < 0) - pr_err("nf_ct_tstamp: Unable to register extension\n"); + pr_err("Unable to register extension\n"); return ret; } diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 6c38421e31f9..617693ff9f4c 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -8,6 +8,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -814,7 +816,7 @@ static int __init nf_nat_init(void) ret = nf_ct_extend_register(&nat_extend); if (ret < 0) { nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size); - printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); + pr_err("Unable to register extension\n"); return ret; } diff --git a/net/netfilter/nf_nat_ftp.c b/net/netfilter/nf_nat_ftp.c index d76afafdc699..5063cbf1689c 100644 --- a/net/netfilter/nf_nat_ftp.c +++ b/net/netfilter/nf_nat_ftp.c @@ -8,6 +8,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -71,7 +73,7 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb, char buffer[sizeof("|1||65535|") + INET6_ADDRSTRLEN]; unsigned int buflen; - pr_debug("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); + pr_debug("type %i, off %u len %u\n", type, matchoff, matchlen); /* Connection will come from wherever this packet goes, hence !dir */ newaddr = ct->tuplehash[!dir].tuple.dst.u3; @@ -136,8 +138,7 @@ static int __init nf_nat_ftp_init(void) /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ static int warn_set(const char *val, const struct kernel_param *kp) { - printk(KERN_INFO KBUILD_MODNAME - ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + pr_info("kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); return 0; } module_param_call(ports, warn_set, NULL, NULL, 0); diff --git a/net/netfilter/nf_nat_irc.c b/net/netfilter/nf_nat_irc.c index dcb5f6375d9d..3aa35a43100d 100644 --- a/net/netfilter/nf_nat_irc.c +++ b/net/netfilter/nf_nat_irc.c @@ -10,6 +10,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -79,7 +81,7 @@ static unsigned int help(struct sk_buff *skb, */ /* AAA = "us", ie. where server normally talks to. */ snprintf(buffer, sizeof(buffer), "%u %u", ntohl(newaddr.ip), port); - pr_debug("nf_nat_irc: inserting '%s' == %pI4, port %u\n", + pr_debug("inserting '%s' == %pI4, port %u\n", buffer, &newaddr.ip, port); if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, matchoff, @@ -108,8 +110,7 @@ static int __init nf_nat_irc_init(void) /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ static int warn_set(const char *val, const struct kernel_param *kp) { - printk(KERN_INFO KBUILD_MODNAME - ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + pr_info("kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); return 0; } module_param_call(ports, warn_set, NULL, NULL, 0); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 8bba23160a68..74a04638ef03 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -14,6 +14,9 @@ * published by the Free Software Foundation. * */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -833,11 +836,8 @@ nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff) if (diff > skb_tailroom(e->skb)) { nskb = skb_copy_expand(e->skb, skb_headroom(e->skb), diff, GFP_ATOMIC); - if (!nskb) { - printk(KERN_WARNING "nf_queue: OOM " - "in mangle, dropping packet\n"); + if (!nskb) return -ENOMEM; - } kfree_skb(e->skb); e->skb = nskb; } @@ -1536,20 +1536,20 @@ static int __init nfnetlink_queue_init(void) status = register_pernet_subsys(&nfnl_queue_net_ops); if (status < 0) { - pr_err("nf_queue: failed to register pernet ops\n"); + pr_err("failed to register pernet ops\n"); goto out; } netlink_register_notifier(&nfqnl_rtnl_notifier); status = nfnetlink_subsys_register(&nfqnl_subsys); if (status < 0) { - pr_err("nf_queue: failed to create netlink socket\n"); + pr_err("failed to create netlink socket\n"); goto cleanup_netlink_notifier; } status = register_netdevice_notifier(&nfqnl_dev_notifier); if (status < 0) { - pr_err("nf_queue: failed to register netdevice notifier\n"); + pr_err("failed to register netdevice notifier\n"); goto cleanup_netlink_subsys; } diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c index 0160f505e337..c13bcd0ab491 100644 --- a/net/netfilter/xt_time.c +++ b/net/netfilter/xt_time.c @@ -9,6 +9,9 @@ * This file is distributed under the terms of the GNU General Public * License (GPL). Copies of the GPL can be obtained from gnu.org/gpl. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -266,13 +269,11 @@ static int __init time_mt_init(void) int minutes = sys_tz.tz_minuteswest; if (minutes < 0) /* east of Greenwich */ - printk(KERN_INFO KBUILD_MODNAME - ": kernel timezone is +%02d%02d\n", - -minutes / 60, -minutes % 60); + pr_info("kernel timezone is +%02d%02d\n", + -minutes / 60, -minutes % 60); else /* west of Greenwich */ - printk(KERN_INFO KBUILD_MODNAME - ": kernel timezone is -%02d%02d\n", - minutes / 60, minutes % 60); + pr_info("kernel timezone is -%02d%02d\n", + minutes / 60, minutes % 60); return xt_register_match(&xt_time_mt_reg); } -- cgit From 20710b3b81895c89e92bcc32ce85c0bede1171f8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 20 Mar 2018 12:33:51 +0100 Subject: netfilter: ctnetlink: synproxy support This patch exposes synproxy information per-conntrack. Moreover, send sequence adjustment events once server sends us the SYN,ACK packet, so we can synchronize the sequence adjustment too for packets going as reply from the server, as part of the synproxy logic. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 87 ++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 8884d302d33a..11ef85a57244 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -440,6 +440,31 @@ err: return -1; } +static int ctnetlink_dump_ct_synproxy(struct sk_buff *skb, struct nf_conn *ct) +{ + struct nf_conn_synproxy *synproxy = nfct_synproxy(ct); + struct nlattr *nest_parms; + + if (!synproxy) + return 0; + + nest_parms = nla_nest_start(skb, CTA_SYNPROXY | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + + if (nla_put_be32(skb, CTA_SYNPROXY_ISN, htonl(synproxy->isn)) || + nla_put_be32(skb, CTA_SYNPROXY_ITS, htonl(synproxy->its)) || + nla_put_be32(skb, CTA_SYNPROXY_TSOFF, htonl(synproxy->tsoff))) + goto nla_put_failure; + + nla_nest_end(skb, nest_parms); + + return 0; + +nla_put_failure: + return -1; +} + static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) { if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct))) @@ -518,7 +543,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, ctnetlink_dump_id(skb, ct) < 0 || ctnetlink_dump_use(skb, ct) < 0 || ctnetlink_dump_master(skb, ct) < 0 || - ctnetlink_dump_ct_seq_adj(skb, ct) < 0) + ctnetlink_dump_ct_seq_adj(skb, ct) < 0 || + ctnetlink_dump_ct_synproxy(skb, ct) < 0) goto nla_put_failure; nlmsg_end(skb, nlh); @@ -730,6 +756,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) if (events & (1 << IPCT_SEQADJ) && ctnetlink_dump_ct_seq_adj(skb, ct) < 0) goto nla_put_failure; + + if (events & (1 << IPCT_SYNPROXY) && + ctnetlink_dump_ct_synproxy(skb, ct) < 0) + goto nla_put_failure; } #ifdef CONFIG_NF_CONNTRACK_MARK @@ -1689,6 +1719,39 @@ err: return ret; } +static const struct nla_policy synproxy_policy[CTA_SYNPROXY_MAX + 1] = { + [CTA_SYNPROXY_ISN] = { .type = NLA_U32 }, + [CTA_SYNPROXY_ITS] = { .type = NLA_U32 }, + [CTA_SYNPROXY_TSOFF] = { .type = NLA_U32 }, +}; + +static int ctnetlink_change_synproxy(struct nf_conn *ct, + const struct nlattr * const cda[]) +{ + struct nf_conn_synproxy *synproxy = nfct_synproxy(ct); + struct nlattr *tb[CTA_SYNPROXY_MAX + 1]; + int err; + + if (!synproxy) + return 0; + + err = nla_parse_nested(tb, CTA_SYNPROXY_MAX, cda[CTA_SYNPROXY], + synproxy_policy, NULL); + if (err < 0) + return err; + + if (!tb[CTA_SYNPROXY_ISN] || + !tb[CTA_SYNPROXY_ITS] || + !tb[CTA_SYNPROXY_TSOFF]) + return -EINVAL; + + synproxy->isn = ntohl(nla_get_be32(tb[CTA_SYNPROXY_ISN])); + synproxy->its = ntohl(nla_get_be32(tb[CTA_SYNPROXY_ITS])); + synproxy->tsoff = ntohl(nla_get_be32(tb[CTA_SYNPROXY_TSOFF])); + + return 0; +} + static int ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) { @@ -1759,6 +1822,12 @@ ctnetlink_change_conntrack(struct nf_conn *ct, return err; } + if (cda[CTA_SYNPROXY]) { + err = ctnetlink_change_synproxy(ct, cda); + if (err < 0) + return err; + } + if (cda[CTA_LABELS]) { err = ctnetlink_attach_labels(ct, cda); if (err < 0) @@ -1880,6 +1949,12 @@ ctnetlink_create_conntrack(struct net *net, goto err2; } + if (cda[CTA_SYNPROXY]) { + err = ctnetlink_change_synproxy(ct, cda); + if (err < 0) + goto err2; + } + #if defined(CONFIG_NF_CONNTRACK_MARK) if (cda[CTA_MARK]) ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); @@ -1991,7 +2066,9 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl, (1 << IPCT_HELPER) | (1 << IPCT_PROTOINFO) | (1 << IPCT_SEQADJ) | - (1 << IPCT_MARK) | events, + (1 << IPCT_MARK) | + (1 << IPCT_SYNPROXY) | + events, ct, NETLINK_CB(skb).portid, nlmsg_report(nlh)); nf_ct_put(ct); @@ -2012,7 +2089,8 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl, (1 << IPCT_LABEL) | (1 << IPCT_PROTOINFO) | (1 << IPCT_SEQADJ) | - (1 << IPCT_MARK), + (1 << IPCT_MARK) | + (1 << IPCT_SYNPROXY), ct, NETLINK_CB(skb).portid, nlmsg_report(nlh)); } @@ -2282,6 +2360,9 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct) ctnetlink_dump_ct_seq_adj(skb, ct) < 0) goto nla_put_failure; + if (ctnetlink_dump_ct_synproxy(skb, ct) < 0) + goto nla_put_failure; + #ifdef CONFIG_NF_CONNTRACK_MARK if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0) goto nla_put_failure; -- cgit From 1be3ac98444066a292de02c2c12e203bdf575e7d Mon Sep 17 00:00:00 2001 From: Bernie Harris Date: Wed, 21 Mar 2018 15:42:16 +1300 Subject: netfilter: ebtables: Add string filter This patch is part of a proposal to add a string filter to ebtables, which would be similar to the string filter in iptables. Like iptables, the ebtables filter uses the xt_string module. Signed-off-by: Bernie Harris Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_string.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/netfilter') diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c index 423293ee57c2..be1feddadcf0 100644 --- a/net/netfilter/xt_string.c +++ b/net/netfilter/xt_string.c @@ -21,6 +21,7 @@ MODULE_DESCRIPTION("Xtables: string-based matching"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_string"); MODULE_ALIAS("ip6t_string"); +MODULE_ALIAS("ebt_string"); static bool string_mt(const struct sk_buff *skb, struct xt_action_param *par) -- cgit From 32537e91847a5686d57d3811c075a46b2d9b6434 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 27 Mar 2018 11:53:05 +0200 Subject: netfilter: nf_tables: rename struct nf_chain_type Use nft_ prefix. By when I added chain types, I forgot to use the nftables prefix. Rename enum nft_chain_type to enum nft_chain_types too, otherwise there is an overlap. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 18 +++++++++--------- net/netfilter/nf_tables_inet.c | 2 +- net/netfilter/nf_tables_netdev.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 92f5606b0dea..bf564f491085 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -384,9 +384,9 @@ static inline u64 nf_tables_alloc_handle(struct nft_table *table) return ++table->hgenerator; } -static const struct nf_chain_type *chain_type[NFPROTO_NUMPROTO][NFT_CHAIN_T_MAX]; +static const struct nft_chain_type *chain_type[NFPROTO_NUMPROTO][NFT_CHAIN_T_MAX]; -static const struct nf_chain_type * +static const struct nft_chain_type * __nf_tables_chain_type_lookup(const struct nlattr *nla, u8 family) { int i; @@ -399,10 +399,10 @@ __nf_tables_chain_type_lookup(const struct nlattr *nla, u8 family) return NULL; } -static const struct nf_chain_type * +static const struct nft_chain_type * nf_tables_chain_type_lookup(const struct nlattr *nla, u8 family, bool autoload) { - const struct nf_chain_type *type; + const struct nft_chain_type *type; type = __nf_tables_chain_type_lookup(nla, family); if (type != NULL) @@ -859,7 +859,7 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx) kfree(ctx->table); } -int nft_register_chain_type(const struct nf_chain_type *ctype) +int nft_register_chain_type(const struct nft_chain_type *ctype) { int err = 0; @@ -878,7 +878,7 @@ out: } EXPORT_SYMBOL_GPL(nft_register_chain_type); -void nft_unregister_chain_type(const struct nf_chain_type *ctype) +void nft_unregister_chain_type(const struct nft_chain_type *ctype) { nfnl_lock(NFNL_SUBSYS_NFTABLES); chain_type[ctype->family][ctype->type] = NULL; @@ -1239,7 +1239,7 @@ static void nf_tables_chain_destroy(struct nft_chain *chain) struct nft_chain_hook { u32 num; s32 priority; - const struct nf_chain_type *type; + const struct nft_chain_type *type; struct net_device *dev; }; @@ -1249,7 +1249,7 @@ static int nft_chain_parse_hook(struct net *net, bool create) { struct nlattr *ha[NFTA_HOOK_MAX + 1]; - const struct nf_chain_type *type; + const struct nft_chain_type *type; struct net_device *dev; int err; @@ -6000,7 +6000,7 @@ static const struct nfnetlink_subsystem nf_tables_subsys = { }; int nft_chain_validate_dependency(const struct nft_chain *chain, - enum nft_chain_type type) + enum nft_chain_types type) { const struct nft_base_chain *basechain; diff --git a/net/netfilter/nf_tables_inet.c b/net/netfilter/nf_tables_inet.c index e30c7da09d0d..0aefe66ce558 100644 --- a/net/netfilter/nf_tables_inet.c +++ b/net/netfilter/nf_tables_inet.c @@ -38,7 +38,7 @@ static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb, return nft_do_chain(&pkt, priv); } -static const struct nf_chain_type filter_inet = { +static const struct nft_chain_type filter_inet = { .name = "filter", .type = NFT_CHAIN_T_DEFAULT, .family = NFPROTO_INET, diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c index 4041fafca934..88ea959211ac 100644 --- a/net/netfilter/nf_tables_netdev.c +++ b/net/netfilter/nf_tables_netdev.c @@ -38,7 +38,7 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb, return nft_do_chain(&pkt, priv); } -static const struct nf_chain_type nft_filter_chain_netdev = { +static const struct nft_chain_type nft_filter_chain_netdev = { .name = "filter", .type = NFT_CHAIN_T_DEFAULT, .family = NFPROTO_NETDEV, -- cgit From cc07eeb0e5ee18895241460bdccf91a4952731f9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 27 Mar 2018 11:53:06 +0200 Subject: netfilter: nf_tables: nft_register_chain_type() returns void Use WARN_ON() instead since it should not happen that neither family goes over NFPROTO_NUMPROTO nor there is already a chain of this type already registered. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 14 +++++--------- net/netfilter/nf_tables_inet.c | 4 +++- net/netfilter/nf_tables_netdev.c | 4 +--- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index bf564f491085..9e4b1614ee39 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -859,22 +859,18 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx) kfree(ctx->table); } -int nft_register_chain_type(const struct nft_chain_type *ctype) +void nft_register_chain_type(const struct nft_chain_type *ctype) { - int err = 0; - if (WARN_ON(ctype->family >= NFPROTO_NUMPROTO)) - return -EINVAL; + return; nfnl_lock(NFNL_SUBSYS_NFTABLES); - if (chain_type[ctype->family][ctype->type] != NULL) { - err = -EBUSY; - goto out; + if (WARN_ON(chain_type[ctype->family][ctype->type] != NULL)) { + nfnl_unlock(NFNL_SUBSYS_NFTABLES); + return; } chain_type[ctype->family][ctype->type] = ctype; -out: nfnl_unlock(NFNL_SUBSYS_NFTABLES); - return err; } EXPORT_SYMBOL_GPL(nft_register_chain_type); diff --git a/net/netfilter/nf_tables_inet.c b/net/netfilter/nf_tables_inet.c index 0aefe66ce558..202c4219969b 100644 --- a/net/netfilter/nf_tables_inet.c +++ b/net/netfilter/nf_tables_inet.c @@ -59,7 +59,9 @@ static const struct nft_chain_type filter_inet = { static int __init nf_tables_inet_init(void) { - return nft_register_chain_type(&filter_inet); + nft_register_chain_type(&filter_inet); + + return 0; } static void __exit nf_tables_inet_exit(void) diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c index 88ea959211ac..4c3835bca63e 100644 --- a/net/netfilter/nf_tables_netdev.c +++ b/net/netfilter/nf_tables_netdev.c @@ -112,9 +112,7 @@ static int __init nf_tables_netdev_init(void) { int ret; - ret = nft_register_chain_type(&nft_filter_chain_netdev); - if (ret) - return ret; + nft_register_chain_type(&nft_filter_chain_netdev); ret = register_netdevice_notifier(&nf_tables_netdev_notifier); if (ret) -- cgit From 02c7b25e5f54321b9063e18d4f52cce07f8e081d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 27 Mar 2018 11:53:07 +0200 Subject: netfilter: nf_tables: build-in filter chain type One module per supported filter chain family type takes too much memory for very little code - too much modularization - place all chain filter definitions in one single file. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/Kconfig | 4 +- net/netfilter/Makefile | 9 +- net/netfilter/nf_tables_api.c | 3 + net/netfilter/nf_tables_inet.c | 77 -------- net/netfilter/nf_tables_netdev.c | 140 -------------- net/netfilter/nft_chain_filter.c | 398 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 407 insertions(+), 224 deletions(-) delete mode 100644 net/netfilter/nf_tables_inet.c delete mode 100644 net/netfilter/nf_tables_netdev.c create mode 100644 net/netfilter/nft_chain_filter.c (limited to 'net/netfilter') diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index d3220b43c832..704b3832dbad 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -465,12 +465,12 @@ config NF_TABLES_INET depends on IPV6 select NF_TABLES_IPV4 select NF_TABLES_IPV6 - tristate "Netfilter nf_tables mixed IPv4/IPv6 tables support" + bool "Netfilter nf_tables mixed IPv4/IPv6 tables support" help This option enables support for a mixed IPv4/IPv6 "inet" table. config NF_TABLES_NETDEV - tristate "Netfilter nf_tables netdev tables support" + bool "Netfilter nf_tables netdev tables support" help This option enables support for the "netdev" table. diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 5d9b8b959e58..fd32bd2c9521 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -73,13 +73,12 @@ obj-$(CONFIG_NETFILTER_CONNCOUNT) += nf_conncount.o obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o # nf_tables -nf_tables-objs := nf_tables_core.o nf_tables_api.o nf_tables_trace.o \ - nft_immediate.o nft_cmp.o nft_range.o nft_bitwise.o \ - nft_byteorder.o nft_payload.o nft_lookup.o nft_dynset.o +nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \ + nf_tables_trace.o nft_immediate.o nft_cmp.o nft_range.o \ + nft_bitwise.o nft_byteorder.o nft_payload.o nft_lookup.o \ + nft_dynset.o obj-$(CONFIG_NF_TABLES) += nf_tables.o -obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o -obj-$(CONFIG_NF_TABLES_NETDEV) += nf_tables_netdev.o obj-$(CONFIG_NFT_COMPAT) += nft_compat.o obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o obj-$(CONFIG_NFT_META) += nft_meta.o diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 9e4b1614ee39..97ec1c388bfe 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6584,6 +6584,8 @@ static int __init nf_tables_module_init(void) { int err; + nft_chain_filter_init(); + info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS, GFP_KERNEL); if (info == NULL) { @@ -6618,6 +6620,7 @@ static void __exit nf_tables_module_exit(void) rcu_barrier(); nf_tables_core_module_exit(); kfree(info); + nft_chain_filter_fini(); } module_init(nf_tables_module_init); diff --git a/net/netfilter/nf_tables_inet.c b/net/netfilter/nf_tables_inet.c deleted file mode 100644 index 202c4219969b..000000000000 --- a/net/netfilter/nf_tables_inet.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2012-2014 Patrick McHardy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb, - const struct nf_hook_state *state) -{ - struct nft_pktinfo pkt; - - nft_set_pktinfo(&pkt, skb, state); - - switch (state->pf) { - case NFPROTO_IPV4: - nft_set_pktinfo_ipv4(&pkt, skb); - break; - case NFPROTO_IPV6: - nft_set_pktinfo_ipv6(&pkt, skb); - break; - default: - break; - } - - return nft_do_chain(&pkt, priv); -} - -static const struct nft_chain_type filter_inet = { - .name = "filter", - .type = NFT_CHAIN_T_DEFAULT, - .family = NFPROTO_INET, - .owner = THIS_MODULE, - .hook_mask = (1 << NF_INET_LOCAL_IN) | - (1 << NF_INET_LOCAL_OUT) | - (1 << NF_INET_FORWARD) | - (1 << NF_INET_PRE_ROUTING) | - (1 << NF_INET_POST_ROUTING), - .hooks = { - [NF_INET_LOCAL_IN] = nft_do_chain_inet, - [NF_INET_LOCAL_OUT] = nft_do_chain_inet, - [NF_INET_FORWARD] = nft_do_chain_inet, - [NF_INET_PRE_ROUTING] = nft_do_chain_inet, - [NF_INET_POST_ROUTING] = nft_do_chain_inet, - }, -}; - -static int __init nf_tables_inet_init(void) -{ - nft_register_chain_type(&filter_inet); - - return 0; -} - -static void __exit nf_tables_inet_exit(void) -{ - nft_unregister_chain_type(&filter_inet); -} - -module_init(nf_tables_inet_init); -module_exit(nf_tables_inet_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Patrick McHardy "); -MODULE_ALIAS_NFT_CHAIN(1, "filter"); diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c deleted file mode 100644 index 4c3835bca63e..000000000000 --- a/net/netfilter/nf_tables_netdev.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2015 Pablo Neira Ayuso - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned int -nft_do_chain_netdev(void *priv, struct sk_buff *skb, - const struct nf_hook_state *state) -{ - struct nft_pktinfo pkt; - - nft_set_pktinfo(&pkt, skb, state); - - switch (skb->protocol) { - case htons(ETH_P_IP): - nft_set_pktinfo_ipv4_validate(&pkt, skb); - break; - case htons(ETH_P_IPV6): - nft_set_pktinfo_ipv6_validate(&pkt, skb); - break; - default: - nft_set_pktinfo_unspec(&pkt, skb); - break; - } - - return nft_do_chain(&pkt, priv); -} - -static const struct nft_chain_type nft_filter_chain_netdev = { - .name = "filter", - .type = NFT_CHAIN_T_DEFAULT, - .family = NFPROTO_NETDEV, - .owner = THIS_MODULE, - .hook_mask = (1 << NF_NETDEV_INGRESS), - .hooks = { - [NF_NETDEV_INGRESS] = nft_do_chain_netdev, - }, -}; - -static void nft_netdev_event(unsigned long event, struct net_device *dev, - struct nft_ctx *ctx) -{ - struct nft_base_chain *basechain = nft_base_chain(ctx->chain); - - switch (event) { - case NETDEV_UNREGISTER: - if (strcmp(basechain->dev_name, dev->name) != 0) - return; - - __nft_release_basechain(ctx); - break; - case NETDEV_CHANGENAME: - if (dev->ifindex != basechain->ops.dev->ifindex) - return; - - strncpy(basechain->dev_name, dev->name, IFNAMSIZ); - break; - } -} - -static int nf_tables_netdev_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct nft_table *table; - struct nft_chain *chain, *nr; - struct nft_ctx ctx = { - .net = dev_net(dev), - }; - - if (event != NETDEV_UNREGISTER && - event != NETDEV_CHANGENAME) - return NOTIFY_DONE; - - nfnl_lock(NFNL_SUBSYS_NFTABLES); - list_for_each_entry(table, &ctx.net->nft.tables, list) { - if (table->family != NFPROTO_NETDEV) - continue; - - ctx.family = table->family; - ctx.table = table; - list_for_each_entry_safe(chain, nr, &table->chains, list) { - if (!nft_is_base_chain(chain)) - continue; - - ctx.chain = chain; - nft_netdev_event(event, dev, &ctx); - } - } - nfnl_unlock(NFNL_SUBSYS_NFTABLES); - - return NOTIFY_DONE; -} - -static struct notifier_block nf_tables_netdev_notifier = { - .notifier_call = nf_tables_netdev_event, -}; - -static int __init nf_tables_netdev_init(void) -{ - int ret; - - nft_register_chain_type(&nft_filter_chain_netdev); - - ret = register_netdevice_notifier(&nf_tables_netdev_notifier); - if (ret) - goto err_register_netdevice_notifier; - - return 0; - -err_register_netdevice_notifier: - nft_unregister_chain_type(&nft_filter_chain_netdev); - - return ret; -} - -static void __exit nf_tables_netdev_exit(void) -{ - unregister_netdevice_notifier(&nf_tables_netdev_notifier); - nft_unregister_chain_type(&nft_filter_chain_netdev); -} - -module_init(nf_tables_netdev_init); -module_exit(nf_tables_netdev_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pablo Neira Ayuso "); -MODULE_ALIAS_NFT_CHAIN(5, "filter"); /* NFPROTO_NETDEV */ diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c new file mode 100644 index 000000000000..84c902477a91 --- /dev/null +++ b/net/netfilter/nft_chain_filter.c @@ -0,0 +1,398 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_NF_TABLES_IPV4 +static unsigned int nft_do_chain_ipv4(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nft_pktinfo pkt; + + nft_set_pktinfo(&pkt, skb, state); + nft_set_pktinfo_ipv4(&pkt, skb); + + return nft_do_chain(&pkt, priv); +} + +static const struct nft_chain_type nft_chain_filter_ipv4 = { + .name = "filter", + .type = NFT_CHAIN_T_DEFAULT, + .family = NFPROTO_IPV4, + .hook_mask = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_FORWARD) | + (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_POST_ROUTING), + .hooks = { + [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, + [NF_INET_LOCAL_OUT] = nft_do_chain_ipv4, + [NF_INET_FORWARD] = nft_do_chain_ipv4, + [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, + [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, + }, +}; + +static void nft_chain_filter_ipv4_init(void) +{ + nft_register_chain_type(&nft_chain_filter_ipv4); +} +static void nft_chain_filter_ipv4_fini(void) +{ + nft_unregister_chain_type(&nft_chain_filter_ipv4); +} + +#else +static inline void nft_chain_filter_ipv4_init(void) {} +static inline void nft_chain_filter_ipv4_fini(void) {} +#endif /* CONFIG_NF_TABLES_IPV4 */ + +#ifdef CONFIG_NF_TABLES_ARP +static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nft_pktinfo pkt; + + nft_set_pktinfo(&pkt, skb, state); + nft_set_pktinfo_unspec(&pkt, skb); + + return nft_do_chain(&pkt, priv); +} + +static const struct nft_chain_type nft_chain_filter_arp = { + .name = "filter", + .type = NFT_CHAIN_T_DEFAULT, + .family = NFPROTO_ARP, + .owner = THIS_MODULE, + .hook_mask = (1 << NF_ARP_IN) | + (1 << NF_ARP_OUT), + .hooks = { + [NF_ARP_IN] = nft_do_chain_arp, + [NF_ARP_OUT] = nft_do_chain_arp, + }, +}; + +static void nft_chain_filter_arp_init(void) +{ + nft_register_chain_type(&nft_chain_filter_arp); +} + +static void nft_chain_filter_arp_fini(void) +{ + nft_unregister_chain_type(&nft_chain_filter_arp); +} +#else +static inline void nft_chain_filter_arp_init(void) {} +static inline void nft_chain_filter_arp_fini(void) {} +#endif /* CONFIG_NF_TABLES_ARP */ + +#ifdef CONFIG_NF_TABLES_IPV6 +static unsigned int nft_do_chain_ipv6(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nft_pktinfo pkt; + + nft_set_pktinfo(&pkt, skb, state); + nft_set_pktinfo_ipv6(&pkt, skb); + + return nft_do_chain(&pkt, priv); +} + +static const struct nft_chain_type nft_chain_filter_ipv6 = { + .name = "filter", + .type = NFT_CHAIN_T_DEFAULT, + .family = NFPROTO_IPV6, + .hook_mask = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_FORWARD) | + (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_POST_ROUTING), + .hooks = { + [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, + [NF_INET_LOCAL_OUT] = nft_do_chain_ipv6, + [NF_INET_FORWARD] = nft_do_chain_ipv6, + [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, + [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, + }, +}; + +static void nft_chain_filter_ipv6_init(void) +{ + nft_register_chain_type(&nft_chain_filter_ipv6); +} + +static void nft_chain_filter_ipv6_fini(void) +{ + nft_unregister_chain_type(&nft_chain_filter_ipv6); +} +#else +static inline void nft_chain_filter_ipv6_init(void) {} +static inline void nft_chain_filter_ipv6_fini(void) {} +#endif /* CONFIG_NF_TABLES_IPV6 */ + +#ifdef CONFIG_NF_TABLES_INET +static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nft_pktinfo pkt; + + nft_set_pktinfo(&pkt, skb, state); + + switch (state->pf) { + case NFPROTO_IPV4: + nft_set_pktinfo_ipv4(&pkt, skb); + break; + case NFPROTO_IPV6: + nft_set_pktinfo_ipv6(&pkt, skb); + break; + default: + break; + } + + return nft_do_chain(&pkt, priv); +} + +static const struct nft_chain_type nft_chain_filter_inet = { + .name = "filter", + .type = NFT_CHAIN_T_DEFAULT, + .family = NFPROTO_INET, + .hook_mask = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_FORWARD) | + (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_POST_ROUTING), + .hooks = { + [NF_INET_LOCAL_IN] = nft_do_chain_inet, + [NF_INET_LOCAL_OUT] = nft_do_chain_inet, + [NF_INET_FORWARD] = nft_do_chain_inet, + [NF_INET_PRE_ROUTING] = nft_do_chain_inet, + [NF_INET_POST_ROUTING] = nft_do_chain_inet, + }, +}; + +static void nft_chain_filter_inet_init(void) +{ + nft_register_chain_type(&nft_chain_filter_inet); +} + +static void nft_chain_filter_inet_fini(void) +{ + nft_unregister_chain_type(&nft_chain_filter_inet); +} +#else +static inline void nft_chain_filter_inet_init(void) {} +static inline void nft_chain_filter_inet_fini(void) {} +#endif /* CONFIG_NF_TABLES_IPV6 */ + +#ifdef CONFIG_NF_TABLES_BRIDGE +static unsigned int +nft_do_chain_bridge(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nft_pktinfo pkt; + + nft_set_pktinfo(&pkt, skb, state); + + switch (eth_hdr(skb)->h_proto) { + case htons(ETH_P_IP): + nft_set_pktinfo_ipv4_validate(&pkt, skb); + break; + case htons(ETH_P_IPV6): + nft_set_pktinfo_ipv6_validate(&pkt, skb); + break; + default: + nft_set_pktinfo_unspec(&pkt, skb); + break; + } + + return nft_do_chain(&pkt, priv); +} + +static const struct nft_chain_type nft_chain_filter_bridge = { + .name = "filter", + .type = NFT_CHAIN_T_DEFAULT, + .family = NFPROTO_BRIDGE, + .hook_mask = (1 << NF_BR_PRE_ROUTING) | + (1 << NF_BR_LOCAL_IN) | + (1 << NF_BR_FORWARD) | + (1 << NF_BR_LOCAL_OUT) | + (1 << NF_BR_POST_ROUTING), + .hooks = { + [NF_BR_PRE_ROUTING] = nft_do_chain_bridge, + [NF_BR_LOCAL_IN] = nft_do_chain_bridge, + [NF_BR_FORWARD] = nft_do_chain_bridge, + [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, + [NF_BR_POST_ROUTING] = nft_do_chain_bridge, + }, +}; + +static void nft_chain_filter_bridge_init(void) +{ + nft_register_chain_type(&nft_chain_filter_bridge); +} + +static void nft_chain_filter_bridge_fini(void) +{ + nft_unregister_chain_type(&nft_chain_filter_bridge); +} +#else +static inline void nft_chain_filter_bridge_init(void) {} +static inline void nft_chain_filter_bridge_fini(void) {} +#endif /* CONFIG_NF_TABLES_BRIDGE */ + +#ifdef CONFIG_NF_TABLES_NETDEV +static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nft_pktinfo pkt; + + nft_set_pktinfo(&pkt, skb, state); + + switch (skb->protocol) { + case htons(ETH_P_IP): + nft_set_pktinfo_ipv4_validate(&pkt, skb); + break; + case htons(ETH_P_IPV6): + nft_set_pktinfo_ipv6_validate(&pkt, skb); + break; + default: + nft_set_pktinfo_unspec(&pkt, skb); + break; + } + + return nft_do_chain(&pkt, priv); +} + +static const struct nft_chain_type nft_chain_filter_netdev = { + .name = "filter", + .type = NFT_CHAIN_T_DEFAULT, + .family = NFPROTO_NETDEV, + .hook_mask = (1 << NF_NETDEV_INGRESS), + .hooks = { + [NF_NETDEV_INGRESS] = nft_do_chain_netdev, + }, +}; + +static void nft_netdev_event(unsigned long event, struct net_device *dev, + struct nft_ctx *ctx) +{ + struct nft_base_chain *basechain = nft_base_chain(ctx->chain); + + switch (event) { + case NETDEV_UNREGISTER: + if (strcmp(basechain->dev_name, dev->name) != 0) + return; + + __nft_release_basechain(ctx); + break; + case NETDEV_CHANGENAME: + if (dev->ifindex != basechain->ops.dev->ifindex) + return; + + strncpy(basechain->dev_name, dev->name, IFNAMSIZ); + break; + } +} + +static int nf_tables_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct nft_table *table; + struct nft_chain *chain, *nr; + struct nft_ctx ctx = { + .net = dev_net(dev), + }; + + if (event != NETDEV_UNREGISTER && + event != NETDEV_CHANGENAME) + return NOTIFY_DONE; + + nfnl_lock(NFNL_SUBSYS_NFTABLES); + list_for_each_entry(table, &ctx.net->nft.tables, list) { + if (table->family != NFPROTO_NETDEV) + continue; + + ctx.family = table->family; + ctx.table = table; + list_for_each_entry_safe(chain, nr, &table->chains, list) { + if (!nft_is_base_chain(chain)) + continue; + + ctx.chain = chain; + nft_netdev_event(event, dev, &ctx); + } + } + nfnl_unlock(NFNL_SUBSYS_NFTABLES); + + return NOTIFY_DONE; +} + +static struct notifier_block nf_tables_netdev_notifier = { + .notifier_call = nf_tables_netdev_event, +}; + +static int nft_chain_filter_netdev_init(void) +{ + int err; + + nft_register_chain_type(&nft_chain_filter_netdev); + + err = register_netdevice_notifier(&nf_tables_netdev_notifier); + if (err) + goto err_register_netdevice_notifier; + + return 0; + +err_register_netdevice_notifier: + nft_unregister_chain_type(&nft_chain_filter_netdev); + + return err; +} + +static void nft_chain_filter_netdev_fini(void) +{ + nft_unregister_chain_type(&nft_chain_filter_netdev); + unregister_netdevice_notifier(&nf_tables_netdev_notifier); +} +#else +static inline int nft_chain_filter_netdev_init(void) { return 0; } +static inline void nft_chain_filter_netdev_fini(void) {} +#endif /* CONFIG_NF_TABLES_NETDEV */ + +int __init nft_chain_filter_init(void) +{ + int err; + + err = nft_chain_filter_netdev_init(); + if (err < 0) + return err; + + nft_chain_filter_ipv4_init(); + nft_chain_filter_ipv6_init(); + nft_chain_filter_arp_init(); + nft_chain_filter_inet_init(); + nft_chain_filter_bridge_init(); + + return 0; +} + +void __exit nft_chain_filter_fini(void) +{ + nft_chain_filter_bridge_fini(); + nft_chain_filter_inet_fini(); + nft_chain_filter_arp_fini(); + nft_chain_filter_ipv6_fini(); + nft_chain_filter_ipv4_fini(); + nft_chain_filter_netdev_fini(); +} -- cgit From 43a605f2f722b6e08addedae8545b490fca252c4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 27 Mar 2018 11:53:08 +0200 Subject: netfilter: nf_tables: enable conntrack if NAT chain is registered Register conntrack hooks if the user adds NAT chains. Users get confused with the existing behaviour since they will see no packets hitting this chain until they add the first rule that refers to conntrack. This patch adds new ->init() and ->free() indirections to chain types that can be used by NAT chains to invoke the conntrack dependency. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 97ec1c388bfe..af8b6a7488bd 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1211,13 +1211,17 @@ static void nft_chain_stats_replace(struct nft_base_chain *chain, rcu_assign_pointer(chain->stats, newstats); } -static void nf_tables_chain_destroy(struct nft_chain *chain) +static void nf_tables_chain_destroy(struct nft_ctx *ctx) { + struct nft_chain *chain = ctx->chain; + BUG_ON(chain->use > 0); if (nft_is_base_chain(chain)) { struct nft_base_chain *basechain = nft_base_chain(chain); + if (basechain->type->free) + basechain->type->free(ctx); module_put(basechain->type->owner); free_percpu(basechain->stats); if (basechain->stats) @@ -1354,6 +1358,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, } basechain->type = hook.type; + if (basechain->type->init) + basechain->type->init(ctx); + chain = &basechain->chain; ops = &basechain->ops; @@ -1374,6 +1381,8 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, if (chain == NULL) return -ENOMEM; } + ctx->chain = chain; + INIT_LIST_HEAD(&chain->rules); chain->handle = nf_tables_alloc_handle(table); chain->table = table; @@ -1387,7 +1396,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, if (err < 0) goto err1; - ctx->chain = chain; err = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN); if (err < 0) goto err2; @@ -1399,7 +1407,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, err2: nf_tables_unregister_hook(net, table, chain); err1: - nf_tables_chain_destroy(chain); + nf_tables_chain_destroy(ctx); return err; } @@ -5678,7 +5686,7 @@ static void nf_tables_commit_release(struct nft_trans *trans) nf_tables_table_destroy(&trans->ctx); break; case NFT_MSG_DELCHAIN: - nf_tables_chain_destroy(trans->ctx.chain); + nf_tables_chain_destroy(&trans->ctx); break; case NFT_MSG_DELRULE: nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans)); @@ -5849,7 +5857,7 @@ static void nf_tables_abort_release(struct nft_trans *trans) nf_tables_table_destroy(&trans->ctx); break; case NFT_MSG_NEWCHAIN: - nf_tables_chain_destroy(trans->ctx.chain); + nf_tables_chain_destroy(&trans->ctx); break; case NFT_MSG_NEWRULE: nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans)); @@ -6499,7 +6507,7 @@ int __nft_release_basechain(struct nft_ctx *ctx) } list_del(&ctx->chain->list); ctx->table->use--; - nf_tables_chain_destroy(ctx->chain); + nf_tables_chain_destroy(ctx); return 0; } @@ -6515,6 +6523,7 @@ static void __nft_release_tables(struct net *net) struct nft_set *set, *ns; struct nft_ctx ctx = { .net = net, + .family = NFPROTO_NETDEV, }; list_for_each_entry_safe(table, nt, &net->nft.tables, list) { @@ -6551,9 +6560,10 @@ static void __nft_release_tables(struct net *net) nft_obj_destroy(obj); } list_for_each_entry_safe(chain, nc, &table->chains, list) { + ctx.chain = chain; list_del(&chain->list); table->use--; - nf_tables_chain_destroy(chain); + nf_tables_chain_destroy(&ctx); } list_del(&table->list); nf_tables_table_destroy(&ctx); -- cgit From 10659cbab72b7bfee1a886018d1915a9549b6378 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 28 Mar 2018 12:06:49 +0200 Subject: netfilter: nf_tables: rename to nft_set_lookup_global() To prepare shorter introduction of shorter function prefix. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 12 ++++++------ net/netfilter/nft_dynset.c | 5 +++-- net/netfilter/nft_lookup.c | 4 ++-- net/netfilter/nft_objref.c | 5 +++-- 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index af8b6a7488bd..769d84015073 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2633,11 +2633,11 @@ static struct nft_set *nf_tables_set_lookup_byid(const struct net *net, return ERR_PTR(-ENOENT); } -struct nft_set *nft_set_lookup(const struct net *net, - const struct nft_table *table, - const struct nlattr *nla_set_name, - const struct nlattr *nla_set_id, - u8 genmask) +struct nft_set *nft_set_lookup_global(const struct net *net, + const struct nft_table *table, + const struct nlattr *nla_set_name, + const struct nlattr *nla_set_id, + u8 genmask) { struct nft_set *set; @@ -2650,7 +2650,7 @@ struct nft_set *nft_set_lookup(const struct net *net, } return set; } -EXPORT_SYMBOL_GPL(nft_set_lookup); +EXPORT_SYMBOL_GPL(nft_set_lookup_global); static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set, const char *name) diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index fc83e29d6634..04863fad05dd 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c @@ -132,8 +132,9 @@ static int nft_dynset_init(const struct nft_ctx *ctx, priv->invert = true; } - set = nft_set_lookup(ctx->net, ctx->table, tb[NFTA_DYNSET_SET_NAME], - tb[NFTA_DYNSET_SET_ID], genmask); + set = nft_set_lookup_global(ctx->net, ctx->table, + tb[NFTA_DYNSET_SET_NAME], + tb[NFTA_DYNSET_SET_ID], genmask); if (IS_ERR(set)) return PTR_ERR(set); diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index 475570e89ede..f52da5e2199f 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -71,8 +71,8 @@ static int nft_lookup_init(const struct nft_ctx *ctx, tb[NFTA_LOOKUP_SREG] == NULL) return -EINVAL; - set = nft_set_lookup(ctx->net, ctx->table, tb[NFTA_LOOKUP_SET], - tb[NFTA_LOOKUP_SET_ID], genmask); + set = nft_set_lookup_global(ctx->net, ctx->table, tb[NFTA_LOOKUP_SET], + tb[NFTA_LOOKUP_SET_ID], genmask); if (IS_ERR(set)) return PTR_ERR(set); diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c index 7bcdc48f3d73..0b02407773ad 100644 --- a/net/netfilter/nft_objref.c +++ b/net/netfilter/nft_objref.c @@ -117,8 +117,9 @@ static int nft_objref_map_init(const struct nft_ctx *ctx, struct nft_set *set; int err; - set = nft_set_lookup(ctx->net, ctx->table, tb[NFTA_OBJREF_SET_NAME], - tb[NFTA_OBJREF_SET_ID], genmask); + set = nft_set_lookup_global(ctx->net, ctx->table, + tb[NFTA_OBJREF_SET_NAME], + tb[NFTA_OBJREF_SET_ID], genmask); if (IS_ERR(set)) return PTR_ERR(set); -- cgit From a3073c17dd8cd041d5cf68f28a80a54e310f2f45 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 28 Mar 2018 12:06:50 +0200 Subject: netfilter: nf_tables: use nft_set_lookup_global from nf_tables_newsetelem() Replace opencoded implementation of nft_set_lookup_global() by call to this function. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 769d84015073..2bd80fa9b070 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4032,17 +4032,10 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk, if (err < 0) return err; - set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], - genmask); - if (IS_ERR(set)) { - if (nla[NFTA_SET_ELEM_LIST_SET_ID]) { - set = nf_tables_set_lookup_byid(net, - nla[NFTA_SET_ELEM_LIST_SET_ID], - genmask); - } - if (IS_ERR(set)) - return PTR_ERR(set); - } + set = nft_set_lookup_global(net, ctx.table, nla[NFTA_SET_ELEM_LIST_SET], + nla[NFTA_SET_ELEM_LIST_SET_ID], genmask); + if (IS_ERR(set)) + return PTR_ERR(set); if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT) return -EBUSY; -- cgit From c47d36b3855d804b2e282f9b4eecbbd19b5453f9 Mon Sep 17 00:00:00 2001 From: Arushi Singhal Date: Thu, 29 Mar 2018 00:39:50 +0530 Subject: netfilter: Merge assignment with return Merge assignment with return statement to directly return the value. Signed-off-by: Arushi Singhal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 5 ++--- net/netfilter/xt_hashlimit.c | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 11ef85a57244..b00e84bf4107 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1527,9 +1527,8 @@ ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[]) if (ret < 0) return ret; - ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_SRC, - cda[CTA_NAT_SRC]); - return ret; + return ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_SRC, + cda[CTA_NAT_SRC]); #else if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC]) return 0; diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index db2fe0911740..64fc3721d74c 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -534,8 +534,7 @@ static u64 user2rate_bytes(u32 user) u64 r; r = user ? U32_MAX / user : U32_MAX; - r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT; - return r; + return (r - 1) << XT_HASHLIMIT_BYTE_SHIFT; } static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, -- cgit From 9ba5c404bf1d6284f0269411b33394362b7ff405 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 29 Mar 2018 15:12:41 +0100 Subject: netfilter: x_tables: Add note about how to free percpu counters Due to the way percpu counters are allocated and freed in blocks, it is not safe to free counters individually. Currently all callers do the right thing, but let's note this restriction. Fixes: ae0ac0ed6fcf ("netfilter: x_tables: pack percpu counter allocations") Signed-off-by: Ben Hutchings Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/netfilter') diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index bac932f1c582..75cd5196b29b 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1854,7 +1854,9 @@ EXPORT_SYMBOL_GPL(xt_proto_fini); * to fetch the real percpu counter. * * To speed up allocation and improve data locality, a 4kb block is - * allocated. + * allocated. Freeing any counter may free an entire block, so all + * counters allocated using the same state must be freed at the same + * time. * * xt_percpu_counter_alloc_state contains the base address of the * allocated page and the current sub-offset. -- cgit From 26c97c5d8dac6bc56d4360561a286f52543ac07e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 20 Mar 2018 10:35:47 -0700 Subject: netfilter: ipset: Use is_zero_ether_addr instead of static and memcmp To make the test a bit clearer and to reduce object size a little. Miscellanea: o remove now unnecessary static const array $ size ip_set_hash_mac.o* text data bss dec hex filename 22822 4619 64 27505 6b71 ip_set_hash_mac.o.allyesconfig.new 22932 4683 64 27679 6c1f ip_set_hash_mac.o.allyesconfig.old 10443 1040 0 11483 2cdb ip_set_hash_mac.o.defconfig.new 10507 1040 0 11547 2d1b ip_set_hash_mac.o.defconfig.old Signed-off-by: Joe Perches Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipset/ip_set_hash_mac.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'net/netfilter') diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c index 8f004edad396..f9d5a2a1e3d0 100644 --- a/net/netfilter/ipset/ip_set_hash_mac.c +++ b/net/netfilter/ipset/ip_set_hash_mac.c @@ -72,9 +72,6 @@ hash_mac4_data_next(struct hash_mac4_elem *next, #define IP_SET_PROTO_UNDEF #include "ip_set_hash_gen.h" -/* Zero valued element is not supported */ -static const unsigned char invalid_ether[ETH_ALEN] = { 0 }; - static int hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, @@ -93,7 +90,7 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, return -EINVAL; ether_addr_copy(e.ether, eth_hdr(skb)->h_source); - if (memcmp(e.ether, invalid_ether, ETH_ALEN) == 0) + if (is_zero_ether_addr(e.ether)) return -EINVAL; return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); } @@ -118,7 +115,7 @@ hash_mac4_uadt(struct ip_set *set, struct nlattr *tb[], if (ret) return ret; ether_addr_copy(e.ether, nla_data(tb[IPSET_ATTR_ETHER])); - if (memcmp(e.ether, invalid_ether, ETH_ALEN) == 0) + if (is_zero_ether_addr(e.ether)) return -IPSET_ERR_HASH_ELEM; return adtfn(set, &e, &ext, &ext, flags); -- cgit