aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2014-11-24 08:06:22 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2014-11-27 06:40:31 -0500
commitabc86d0f99242b7f142b7cb8f90e30081dd3c256 (patch)
tree9c5b2a99e19966c1a9c83653759e26969879b27f /net/netfilter
parent3a611e26e958b0372d2e7600b87bbb4a84c7704b (diff)
netfilter: xt_recent: relax ip_pkt_list_tot restrictions
The maximum value for the hitcount parameter is given by "ip_pkt_list_tot" parameter (default: 20). Exceeding this value on the command line will cause the rule to be rejected. The parameter is also readonly, i.e. it cannot be changed without module unload or reboot. Store size per table, then base nstamps[] size on the hitcount instead. The module parameter is retained for backwards compatibility. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/xt_recent.c64
1 files changed, 47 insertions, 17 deletions
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index a9faae89f955..30dbe34915ae 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -43,25 +43,29 @@ MODULE_LICENSE("GPL");
43MODULE_ALIAS("ipt_recent"); 43MODULE_ALIAS("ipt_recent");
44MODULE_ALIAS("ip6t_recent"); 44MODULE_ALIAS("ip6t_recent");
45 45
46static unsigned int ip_list_tot = 100; 46static unsigned int ip_list_tot __read_mostly = 100;
47static unsigned int ip_pkt_list_tot = 20; 47static unsigned int ip_list_hash_size __read_mostly;
48static unsigned int ip_list_hash_size = 0; 48static unsigned int ip_list_perms __read_mostly = 0644;
49static unsigned int ip_list_perms = 0644; 49static unsigned int ip_list_uid __read_mostly;
50static unsigned int ip_list_uid = 0; 50static unsigned int ip_list_gid __read_mostly;
51static unsigned int ip_list_gid = 0;
52module_param(ip_list_tot, uint, 0400); 51module_param(ip_list_tot, uint, 0400);
53module_param(ip_pkt_list_tot, uint, 0400);
54module_param(ip_list_hash_size, uint, 0400); 52module_param(ip_list_hash_size, uint, 0400);
55module_param(ip_list_perms, uint, 0400); 53module_param(ip_list_perms, uint, 0400);
56module_param(ip_list_uid, uint, S_IRUGO | S_IWUSR); 54module_param(ip_list_uid, uint, S_IRUGO | S_IWUSR);
57module_param(ip_list_gid, uint, S_IRUGO | S_IWUSR); 55module_param(ip_list_gid, uint, S_IRUGO | S_IWUSR);
58MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list"); 56MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
59MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)");
60MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs"); 57MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
61MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files"); 58MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files");
62MODULE_PARM_DESC(ip_list_uid, "default owner of /proc/net/xt_recent/* files"); 59MODULE_PARM_DESC(ip_list_uid, "default owner of /proc/net/xt_recent/* files");
63MODULE_PARM_DESC(ip_list_gid, "default owning group of /proc/net/xt_recent/* files"); 60MODULE_PARM_DESC(ip_list_gid, "default owning group of /proc/net/xt_recent/* files");
64 61
62/* retained for backwards compatibility */
63static unsigned int ip_pkt_list_tot __read_mostly;
64module_param(ip_pkt_list_tot, uint, 0400);
65MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)");
66
67#define XT_RECENT_MAX_NSTAMPS 256
68
65struct recent_entry { 69struct recent_entry {
66 struct list_head list; 70 struct list_head list;
67 struct list_head lru_list; 71 struct list_head lru_list;
@@ -79,6 +83,7 @@ struct recent_table {
79 union nf_inet_addr mask; 83 union nf_inet_addr mask;
80 unsigned int refcnt; 84 unsigned int refcnt;
81 unsigned int entries; 85 unsigned int entries;
86 u8 nstamps_max_mask;
82 struct list_head lru_list; 87 struct list_head lru_list;
83 struct list_head iphash[0]; 88 struct list_head iphash[0];
84}; 89};
@@ -90,7 +95,8 @@ struct recent_net {
90#endif 95#endif
91}; 96};
92 97
93static int recent_net_id; 98static int recent_net_id __read_mostly;
99
94static inline struct recent_net *recent_pernet(struct net *net) 100static inline struct recent_net *recent_pernet(struct net *net)
95{ 101{
96 return net_generic(net, recent_net_id); 102 return net_generic(net, recent_net_id);
@@ -171,12 +177,15 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr,
171 u_int16_t family, u_int8_t ttl) 177 u_int16_t family, u_int8_t ttl)
172{ 178{
173 struct recent_entry *e; 179 struct recent_entry *e;
180 unsigned int nstamps_max = t->nstamps_max_mask;
174 181
175 if (t->entries >= ip_list_tot) { 182 if (t->entries >= ip_list_tot) {
176 e = list_entry(t->lru_list.next, struct recent_entry, lru_list); 183 e = list_entry(t->lru_list.next, struct recent_entry, lru_list);
177 recent_entry_remove(t, e); 184 recent_entry_remove(t, e);
178 } 185 }
179 e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * ip_pkt_list_tot, 186
187 nstamps_max += 1;
188 e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * nstamps_max,
180 GFP_ATOMIC); 189 GFP_ATOMIC);
181 if (e == NULL) 190 if (e == NULL)
182 return NULL; 191 return NULL;
@@ -197,7 +206,7 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr,
197 206
198static void recent_entry_update(struct recent_table *t, struct recent_entry *e) 207static void recent_entry_update(struct recent_table *t, struct recent_entry *e)
199{ 208{
200 e->index %= ip_pkt_list_tot; 209 e->index &= t->nstamps_max_mask;
201 e->stamps[e->index++] = jiffies; 210 e->stamps[e->index++] = jiffies;
202 if (e->index > e->nstamps) 211 if (e->index > e->nstamps)
203 e->nstamps = e->index; 212 e->nstamps = e->index;
@@ -326,6 +335,7 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
326 kuid_t uid; 335 kuid_t uid;
327 kgid_t gid; 336 kgid_t gid;
328#endif 337#endif
338 unsigned int nstamp_mask;
329 unsigned int i; 339 unsigned int i;
330 int ret = -EINVAL; 340 int ret = -EINVAL;
331 size_t sz; 341 size_t sz;
@@ -349,19 +359,33 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
349 return -EINVAL; 359 return -EINVAL;
350 if ((info->check_set & XT_RECENT_REAP) && !info->seconds) 360 if ((info->check_set & XT_RECENT_REAP) && !info->seconds)
351 return -EINVAL; 361 return -EINVAL;
352 if (info->hit_count > ip_pkt_list_tot) { 362 if (info->hit_count >= XT_RECENT_MAX_NSTAMPS) {
353 pr_info("hitcount (%u) is larger than " 363 pr_info("hitcount (%u) is larger than allowed maximum (%u)\n",
354 "packets to be remembered (%u)\n", 364 info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
355 info->hit_count, ip_pkt_list_tot);
356 return -EINVAL; 365 return -EINVAL;
357 } 366 }
358 if (info->name[0] == '\0' || 367 if (info->name[0] == '\0' ||
359 strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) 368 strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
360 return -EINVAL; 369 return -EINVAL;
361 370
371 if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot)
372 nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1;
373 else if (info->hit_count)
374 nstamp_mask = roundup_pow_of_two(info->hit_count) - 1;
375 else
376 nstamp_mask = 32 - 1;
377
362 mutex_lock(&recent_mutex); 378 mutex_lock(&recent_mutex);
363 t = recent_table_lookup(recent_net, info->name); 379 t = recent_table_lookup(recent_net, info->name);
364 if (t != NULL) { 380 if (t != NULL) {
381 if (info->hit_count > t->nstamps_max_mask) {
382 pr_info("hitcount (%u) is larger than packets to be remembered (%u) for table %s\n",
383 info->hit_count, t->nstamps_max_mask + 1,
384 info->name);
385 ret = -EINVAL;
386 goto out;
387 }
388
365 t->refcnt++; 389 t->refcnt++;
366 ret = 0; 390 ret = 0;
367 goto out; 391 goto out;
@@ -377,6 +401,7 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
377 goto out; 401 goto out;
378 } 402 }
379 t->refcnt = 1; 403 t->refcnt = 1;
404 t->nstamps_max_mask = nstamp_mask;
380 405
381 memcpy(&t->mask, &info->mask, sizeof(t->mask)); 406 memcpy(&t->mask, &info->mask, sizeof(t->mask));
382 strcpy(t->name, info->name); 407 strcpy(t->name, info->name);
@@ -497,9 +522,12 @@ static void recent_seq_stop(struct seq_file *s, void *v)
497static int recent_seq_show(struct seq_file *seq, void *v) 522static int recent_seq_show(struct seq_file *seq, void *v)
498{ 523{
499 const struct recent_entry *e = v; 524 const struct recent_entry *e = v;
525 struct recent_iter_state *st = seq->private;
526 const struct recent_table *t = st->table;
500 unsigned int i; 527 unsigned int i;
501 528
502 i = (e->index - 1) % ip_pkt_list_tot; 529 i = (e->index - 1) & t->nstamps_max_mask;
530
503 if (e->family == NFPROTO_IPV4) 531 if (e->family == NFPROTO_IPV4)
504 seq_printf(seq, "src=%pI4 ttl: %u last_seen: %lu oldest_pkt: %u", 532 seq_printf(seq, "src=%pI4 ttl: %u last_seen: %lu oldest_pkt: %u",
505 &e->addr.ip, e->ttl, e->stamps[i], e->index); 533 &e->addr.ip, e->ttl, e->stamps[i], e->index);
@@ -717,7 +745,9 @@ static int __init recent_mt_init(void)
717{ 745{
718 int err; 746 int err;
719 747
720 if (!ip_list_tot || !ip_pkt_list_tot || ip_pkt_list_tot > 255) 748 BUILD_BUG_ON_NOT_POWER_OF_2(XT_RECENT_MAX_NSTAMPS);
749
750 if (!ip_list_tot || ip_pkt_list_tot >= XT_RECENT_MAX_NSTAMPS)
721 return -EINVAL; 751 return -EINVAL;
722 ip_list_hash_size = 1 << fls(ip_list_tot); 752 ip_list_hash_size = 1 << fls(ip_list_tot);
723 753