aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter/x_tables.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netfilter/x_tables.c')
-rw-r--r--net/netfilter/x_tables.c124
1 files changed, 81 insertions, 43 deletions
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index c9423763107..a9adf4c6b29 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -23,6 +23,7 @@
23#include <linux/mutex.h> 23#include <linux/mutex.h>
24#include <linux/mm.h> 24#include <linux/mm.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/audit.h>
26#include <net/net_namespace.h> 27#include <net/net_namespace.h>
27 28
28#include <linux/netfilter/x_tables.h> 29#include <linux/netfilter/x_tables.h>
@@ -38,9 +39,8 @@ MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
38#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) 39#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
39 40
40struct compat_delta { 41struct compat_delta {
41 struct compat_delta *next; 42 unsigned int offset; /* offset in kernel */
42 unsigned int offset; 43 int delta; /* delta in 32bit user land */
43 int delta;
44}; 44};
45 45
46struct xt_af { 46struct xt_af {
@@ -49,7 +49,9 @@ struct xt_af {
49 struct list_head target; 49 struct list_head target;
50#ifdef CONFIG_COMPAT 50#ifdef CONFIG_COMPAT
51 struct mutex compat_mutex; 51 struct mutex compat_mutex;
52 struct compat_delta *compat_offsets; 52 struct compat_delta *compat_tab;
53 unsigned int number; /* number of slots in compat_tab[] */
54 unsigned int cur; /* number of used slots in compat_tab[] */
53#endif 55#endif
54}; 56};
55 57
@@ -181,14 +183,14 @@ EXPORT_SYMBOL(xt_unregister_matches);
181/* 183/*
182 * These are weird, but module loading must not be done with mutex 184 * These are weird, but module loading must not be done with mutex
183 * held (since they will register), and we have to have a single 185 * held (since they will register), and we have to have a single
184 * function to use try_then_request_module(). 186 * function to use.
185 */ 187 */
186 188
187/* Find match, grabs ref. Returns ERR_PTR() on error. */ 189/* Find match, grabs ref. Returns ERR_PTR() on error. */
188struct xt_match *xt_find_match(u8 af, const char *name, u8 revision) 190struct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
189{ 191{
190 struct xt_match *m; 192 struct xt_match *m;
191 int err = 0; 193 int err = -ENOENT;
192 194
193 if (mutex_lock_interruptible(&xt[af].mutex) != 0) 195 if (mutex_lock_interruptible(&xt[af].mutex) != 0)
194 return ERR_PTR(-EINTR); 196 return ERR_PTR(-EINTR);
@@ -219,9 +221,13 @@ xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
219{ 221{
220 struct xt_match *match; 222 struct xt_match *match;
221 223
222 match = try_then_request_module(xt_find_match(nfproto, name, revision), 224 match = xt_find_match(nfproto, name, revision);
223 "%st_%s", xt_prefix[nfproto], name); 225 if (IS_ERR(match)) {
224 return (match != NULL) ? match : ERR_PTR(-ENOENT); 226 request_module("%st_%s", xt_prefix[nfproto], name);
227 match = xt_find_match(nfproto, name, revision);
228 }
229
230 return match;
225} 231}
226EXPORT_SYMBOL_GPL(xt_request_find_match); 232EXPORT_SYMBOL_GPL(xt_request_find_match);
227 233
@@ -229,7 +235,7 @@ EXPORT_SYMBOL_GPL(xt_request_find_match);
229struct xt_target *xt_find_target(u8 af, const char *name, u8 revision) 235struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
230{ 236{
231 struct xt_target *t; 237 struct xt_target *t;
232 int err = 0; 238 int err = -ENOENT;
233 239
234 if (mutex_lock_interruptible(&xt[af].mutex) != 0) 240 if (mutex_lock_interruptible(&xt[af].mutex) != 0)
235 return ERR_PTR(-EINTR); 241 return ERR_PTR(-EINTR);
@@ -259,9 +265,13 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
259{ 265{
260 struct xt_target *target; 266 struct xt_target *target;
261 267
262 target = try_then_request_module(xt_find_target(af, name, revision), 268 target = xt_find_target(af, name, revision);
263 "%st_%s", xt_prefix[af], name); 269 if (IS_ERR(target)) {
264 return (target != NULL) ? target : ERR_PTR(-ENOENT); 270 request_module("%st_%s", xt_prefix[af], name);
271 target = xt_find_target(af, name, revision);
272 }
273
274 return target;
265} 275}
266EXPORT_SYMBOL_GPL(xt_request_find_target); 276EXPORT_SYMBOL_GPL(xt_request_find_target);
267 277
@@ -414,54 +424,67 @@ int xt_check_match(struct xt_mtchk_param *par,
414EXPORT_SYMBOL_GPL(xt_check_match); 424EXPORT_SYMBOL_GPL(xt_check_match);
415 425
416#ifdef CONFIG_COMPAT 426#ifdef CONFIG_COMPAT
417int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta) 427int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
418{ 428{
419 struct compat_delta *tmp; 429 struct xt_af *xp = &xt[af];
420 430
421 tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); 431 if (!xp->compat_tab) {
422 if (!tmp) 432 if (!xp->number)
423 return -ENOMEM; 433 return -EINVAL;
434 xp->compat_tab = vmalloc(sizeof(struct compat_delta) * xp->number);
435 if (!xp->compat_tab)
436 return -ENOMEM;
437 xp->cur = 0;
438 }
424 439
425 tmp->offset = offset; 440 if (xp->cur >= xp->number)
426 tmp->delta = delta; 441 return -EINVAL;
427 442
428 if (xt[af].compat_offsets) { 443 if (xp->cur)
429 tmp->next = xt[af].compat_offsets->next; 444 delta += xp->compat_tab[xp->cur - 1].delta;
430 xt[af].compat_offsets->next = tmp; 445 xp->compat_tab[xp->cur].offset = offset;
431 } else { 446 xp->compat_tab[xp->cur].delta = delta;
432 xt[af].compat_offsets = tmp; 447 xp->cur++;
433 tmp->next = NULL;
434 }
435 return 0; 448 return 0;
436} 449}
437EXPORT_SYMBOL_GPL(xt_compat_add_offset); 450EXPORT_SYMBOL_GPL(xt_compat_add_offset);
438 451
439void xt_compat_flush_offsets(u_int8_t af) 452void xt_compat_flush_offsets(u_int8_t af)
440{ 453{
441 struct compat_delta *tmp, *next; 454 if (xt[af].compat_tab) {
442 455 vfree(xt[af].compat_tab);
443 if (xt[af].compat_offsets) { 456 xt[af].compat_tab = NULL;
444 for (tmp = xt[af].compat_offsets; tmp; tmp = next) { 457 xt[af].number = 0;
445 next = tmp->next;
446 kfree(tmp);
447 }
448 xt[af].compat_offsets = NULL;
449 } 458 }
450} 459}
451EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); 460EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
452 461
453int xt_compat_calc_jump(u_int8_t af, unsigned int offset) 462int xt_compat_calc_jump(u_int8_t af, unsigned int offset)
454{ 463{
455 struct compat_delta *tmp; 464 struct compat_delta *tmp = xt[af].compat_tab;
456 int delta; 465 int mid, left = 0, right = xt[af].cur - 1;
457 466
458 for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) 467 while (left <= right) {
459 if (tmp->offset < offset) 468 mid = (left + right) >> 1;
460 delta += tmp->delta; 469 if (offset > tmp[mid].offset)
461 return delta; 470 left = mid + 1;
471 else if (offset < tmp[mid].offset)
472 right = mid - 1;
473 else
474 return mid ? tmp[mid - 1].delta : 0;
475 }
476 WARN_ON_ONCE(1);
477 return 0;
462} 478}
463EXPORT_SYMBOL_GPL(xt_compat_calc_jump); 479EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
464 480
481void xt_compat_init_offsets(u_int8_t af, unsigned int number)
482{
483 xt[af].number = number;
484 xt[af].cur = 0;
485}
486EXPORT_SYMBOL(xt_compat_init_offsets);
487
465int xt_compat_match_offset(const struct xt_match *match) 488int xt_compat_match_offset(const struct xt_match *match)
466{ 489{
467 u_int16_t csize = match->compatsize ? : match->matchsize; 490 u_int16_t csize = match->compatsize ? : match->matchsize;
@@ -820,6 +843,21 @@ xt_replace_table(struct xt_table *table,
820 */ 843 */
821 local_bh_enable(); 844 local_bh_enable();
822 845
846#ifdef CONFIG_AUDIT
847 if (audit_enabled) {
848 struct audit_buffer *ab;
849
850 ab = audit_log_start(current->audit_context, GFP_KERNEL,
851 AUDIT_NETFILTER_CFG);
852 if (ab) {
853 audit_log_format(ab, "table=%s family=%u entries=%u",
854 table->name, table->af,
855 private->number);
856 audit_log_end(ab);
857 }
858 }
859#endif
860
823 return private; 861 return private;
824} 862}
825EXPORT_SYMBOL_GPL(xt_replace_table); 863EXPORT_SYMBOL_GPL(xt_replace_table);
@@ -1338,7 +1376,7 @@ static int __init xt_init(void)
1338 mutex_init(&xt[i].mutex); 1376 mutex_init(&xt[i].mutex);
1339#ifdef CONFIG_COMPAT 1377#ifdef CONFIG_COMPAT
1340 mutex_init(&xt[i].compat_mutex); 1378 mutex_init(&xt[i].compat_mutex);
1341 xt[i].compat_offsets = NULL; 1379 xt[i].compat_tab = NULL;
1342#endif 1380#endif
1343 INIT_LIST_HEAD(&xt[i].target); 1381 INIT_LIST_HEAD(&xt[i].target);
1344 INIT_LIST_HEAD(&xt[i].match); 1382 INIT_LIST_HEAD(&xt[i].match);