diff options
-rw-r--r-- | include/linux/audit.h | 7 | ||||
-rw-r--r-- | include/linux/netfilter/ipset/ip_set_ahash.h | 108 | ||||
-rw-r--r-- | include/linux/netfilter/nfnetlink.h | 3 | ||||
-rw-r--r-- | include/linux/netfilter/nfnetlink_queue.h | 1 | ||||
-rw-r--r-- | kernel/audit.c | 29 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ip.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipport.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportip.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportnet.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_net.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netiface.c | 40 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netport.c | 6 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 40 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 170 | ||||
-rw-r--r-- | net/netfilter/xt_AUDIT.c | 5 |
15 files changed, 327 insertions, 112 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 9d339eb27881..0c8006129fb2 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -613,6 +613,12 @@ extern void audit_log_d_path(struct audit_buffer *ab, | |||
613 | extern void audit_log_key(struct audit_buffer *ab, | 613 | extern void audit_log_key(struct audit_buffer *ab, |
614 | char *key); | 614 | char *key); |
615 | extern void audit_log_lost(const char *message); | 615 | extern void audit_log_lost(const char *message); |
616 | #ifdef CONFIG_SECURITY | ||
617 | extern void audit_log_secctx(struct audit_buffer *ab, u32 secid); | ||
618 | #else | ||
619 | #define audit_log_secctx(b,s) do { ; } while (0) | ||
620 | #endif | ||
621 | |||
616 | extern int audit_update_lsm_rules(void); | 622 | extern int audit_update_lsm_rules(void); |
617 | 623 | ||
618 | /* Private API (for audit.c only) */ | 624 | /* Private API (for audit.c only) */ |
@@ -635,6 +641,7 @@ extern int audit_enabled; | |||
635 | #define audit_log_untrustedstring(a,s) do { ; } while (0) | 641 | #define audit_log_untrustedstring(a,s) do { ; } while (0) |
636 | #define audit_log_d_path(b, p, d) do { ; } while (0) | 642 | #define audit_log_d_path(b, p, d) do { ; } while (0) |
637 | #define audit_log_key(b, k) do { ; } while (0) | 643 | #define audit_log_key(b, k) do { ; } while (0) |
644 | #define audit_log_secctx(b,s) do { ; } while (0) | ||
638 | #define audit_enabled 0 | 645 | #define audit_enabled 0 |
639 | #endif | 646 | #endif |
640 | #endif | 647 | #endif |
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h index c5b06aaa205c..b89fb79cb44f 100644 --- a/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/include/linux/netfilter/ipset/ip_set_ahash.h | |||
@@ -28,7 +28,32 @@ | |||
28 | /* Number of elements to store in an initial array block */ | 28 | /* Number of elements to store in an initial array block */ |
29 | #define AHASH_INIT_SIZE 4 | 29 | #define AHASH_INIT_SIZE 4 |
30 | /* Max number of elements to store in an array block */ | 30 | /* Max number of elements to store in an array block */ |
31 | #define AHASH_MAX_SIZE (3*4) | 31 | #define AHASH_MAX_SIZE (3*AHASH_INIT_SIZE) |
32 | |||
33 | /* Max number of elements can be tuned */ | ||
34 | #ifdef IP_SET_HASH_WITH_MULTI | ||
35 | #define AHASH_MAX(h) ((h)->ahash_max) | ||
36 | |||
37 | static inline u8 | ||
38 | tune_ahash_max(u8 curr, u32 multi) | ||
39 | { | ||
40 | u32 n; | ||
41 | |||
42 | if (multi < curr) | ||
43 | return curr; | ||
44 | |||
45 | n = curr + AHASH_INIT_SIZE; | ||
46 | /* Currently, at listing one hash bucket must fit into a message. | ||
47 | * Therefore we have a hard limit here. | ||
48 | */ | ||
49 | return n > curr && n <= 64 ? n : curr; | ||
50 | } | ||
51 | #define TUNE_AHASH_MAX(h, multi) \ | ||
52 | ((h)->ahash_max = tune_ahash_max((h)->ahash_max, multi)) | ||
53 | #else | ||
54 | #define AHASH_MAX(h) AHASH_MAX_SIZE | ||
55 | #define TUNE_AHASH_MAX(h, multi) | ||
56 | #endif | ||
32 | 57 | ||
33 | /* A hash bucket */ | 58 | /* A hash bucket */ |
34 | struct hbucket { | 59 | struct hbucket { |
@@ -60,6 +85,9 @@ struct ip_set_hash { | |||
60 | u32 timeout; /* timeout value, if enabled */ | 85 | u32 timeout; /* timeout value, if enabled */ |
61 | struct timer_list gc; /* garbage collection when timeout enabled */ | 86 | struct timer_list gc; /* garbage collection when timeout enabled */ |
62 | struct type_pf_next next; /* temporary storage for uadd */ | 87 | struct type_pf_next next; /* temporary storage for uadd */ |
88 | #ifdef IP_SET_HASH_WITH_MULTI | ||
89 | u8 ahash_max; /* max elements in an array block */ | ||
90 | #endif | ||
63 | #ifdef IP_SET_HASH_WITH_NETMASK | 91 | #ifdef IP_SET_HASH_WITH_NETMASK |
64 | u8 netmask; /* netmask value for subnets to store */ | 92 | u8 netmask; /* netmask value for subnets to store */ |
65 | #endif | 93 | #endif |
@@ -211,12 +239,16 @@ ip_set_hash_destroy(struct ip_set *set) | |||
211 | set->data = NULL; | 239 | set->data = NULL; |
212 | } | 240 | } |
213 | 241 | ||
214 | #define HKEY(data, initval, htable_bits) \ | ||
215 | (jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \ | ||
216 | & jhash_mask(htable_bits)) | ||
217 | |||
218 | #endif /* _IP_SET_AHASH_H */ | 242 | #endif /* _IP_SET_AHASH_H */ |
219 | 243 | ||
244 | #ifndef HKEY_DATALEN | ||
245 | #define HKEY_DATALEN sizeof(struct type_pf_elem) | ||
246 | #endif | ||
247 | |||
248 | #define HKEY(data, initval, htable_bits) \ | ||
249 | (jhash2((u32 *)(data), HKEY_DATALEN/sizeof(u32), initval) \ | ||
250 | & jhash_mask(htable_bits)) | ||
251 | |||
220 | #define CONCAT(a, b, c) a##b##c | 252 | #define CONCAT(a, b, c) a##b##c |
221 | #define TOKEN(a, b, c) CONCAT(a, b, c) | 253 | #define TOKEN(a, b, c) CONCAT(a, b, c) |
222 | 254 | ||
@@ -275,12 +307,13 @@ ip_set_hash_destroy(struct ip_set *set) | |||
275 | /* Add an element to the hash table when resizing the set: | 307 | /* Add an element to the hash table when resizing the set: |
276 | * we spare the maintenance of the internal counters. */ | 308 | * we spare the maintenance of the internal counters. */ |
277 | static int | 309 | static int |
278 | type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value) | 310 | type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value, |
311 | u8 ahash_max) | ||
279 | { | 312 | { |
280 | if (n->pos >= n->size) { | 313 | if (n->pos >= n->size) { |
281 | void *tmp; | 314 | void *tmp; |
282 | 315 | ||
283 | if (n->size >= AHASH_MAX_SIZE) | 316 | if (n->size >= ahash_max) |
284 | /* Trigger rehashing */ | 317 | /* Trigger rehashing */ |
285 | return -EAGAIN; | 318 | return -EAGAIN; |
286 | 319 | ||
@@ -335,7 +368,7 @@ retry: | |||
335 | for (j = 0; j < n->pos; j++) { | 368 | for (j = 0; j < n->pos; j++) { |
336 | data = ahash_data(n, j); | 369 | data = ahash_data(n, j); |
337 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); | 370 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); |
338 | ret = type_pf_elem_add(m, data); | 371 | ret = type_pf_elem_add(m, data, AHASH_MAX(h)); |
339 | if (ret < 0) { | 372 | if (ret < 0) { |
340 | read_unlock_bh(&set->lock); | 373 | read_unlock_bh(&set->lock); |
341 | ahash_destroy(t); | 374 | ahash_destroy(t); |
@@ -359,7 +392,7 @@ retry: | |||
359 | return 0; | 392 | return 0; |
360 | } | 393 | } |
361 | 394 | ||
362 | static void | 395 | static inline void |
363 | type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d); | 396 | type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d); |
364 | 397 | ||
365 | /* Add an element to a hash and update the internal counters when succeeded, | 398 | /* Add an element to a hash and update the internal counters when succeeded, |
@@ -372,7 +405,7 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
372 | const struct type_pf_elem *d = value; | 405 | const struct type_pf_elem *d = value; |
373 | struct hbucket *n; | 406 | struct hbucket *n; |
374 | int i, ret = 0; | 407 | int i, ret = 0; |
375 | u32 key; | 408 | u32 key, multi = 0; |
376 | 409 | ||
377 | if (h->elements >= h->maxelem) | 410 | if (h->elements >= h->maxelem) |
378 | return -IPSET_ERR_HASH_FULL; | 411 | return -IPSET_ERR_HASH_FULL; |
@@ -382,12 +415,12 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
382 | key = HKEY(value, h->initval, t->htable_bits); | 415 | key = HKEY(value, h->initval, t->htable_bits); |
383 | n = hbucket(t, key); | 416 | n = hbucket(t, key); |
384 | for (i = 0; i < n->pos; i++) | 417 | for (i = 0; i < n->pos; i++) |
385 | if (type_pf_data_equal(ahash_data(n, i), d)) { | 418 | if (type_pf_data_equal(ahash_data(n, i), d, &multi)) { |
386 | ret = -IPSET_ERR_EXIST; | 419 | ret = -IPSET_ERR_EXIST; |
387 | goto out; | 420 | goto out; |
388 | } | 421 | } |
389 | 422 | TUNE_AHASH_MAX(h, multi); | |
390 | ret = type_pf_elem_add(n, value); | 423 | ret = type_pf_elem_add(n, value, AHASH_MAX(h)); |
391 | if (ret != 0) { | 424 | if (ret != 0) { |
392 | if (ret == -EAGAIN) | 425 | if (ret == -EAGAIN) |
393 | type_pf_data_next(h, d); | 426 | type_pf_data_next(h, d); |
@@ -415,13 +448,13 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
415 | struct hbucket *n; | 448 | struct hbucket *n; |
416 | int i; | 449 | int i; |
417 | struct type_pf_elem *data; | 450 | struct type_pf_elem *data; |
418 | u32 key; | 451 | u32 key, multi = 0; |
419 | 452 | ||
420 | key = HKEY(value, h->initval, t->htable_bits); | 453 | key = HKEY(value, h->initval, t->htable_bits); |
421 | n = hbucket(t, key); | 454 | n = hbucket(t, key); |
422 | for (i = 0; i < n->pos; i++) { | 455 | for (i = 0; i < n->pos; i++) { |
423 | data = ahash_data(n, i); | 456 | data = ahash_data(n, i); |
424 | if (!type_pf_data_equal(data, d)) | 457 | if (!type_pf_data_equal(data, d, &multi)) |
425 | continue; | 458 | continue; |
426 | if (i != n->pos - 1) | 459 | if (i != n->pos - 1) |
427 | /* Not last one */ | 460 | /* Not last one */ |
@@ -462,17 +495,17 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) | |||
462 | struct hbucket *n; | 495 | struct hbucket *n; |
463 | const struct type_pf_elem *data; | 496 | const struct type_pf_elem *data; |
464 | int i, j = 0; | 497 | int i, j = 0; |
465 | u32 key; | 498 | u32 key, multi = 0; |
466 | u8 host_mask = SET_HOST_MASK(set->family); | 499 | u8 host_mask = SET_HOST_MASK(set->family); |
467 | 500 | ||
468 | pr_debug("test by nets\n"); | 501 | pr_debug("test by nets\n"); |
469 | for (; j < host_mask && h->nets[j].cidr; j++) { | 502 | for (; j < host_mask && h->nets[j].cidr && !multi; j++) { |
470 | type_pf_data_netmask(d, h->nets[j].cidr); | 503 | type_pf_data_netmask(d, h->nets[j].cidr); |
471 | key = HKEY(d, h->initval, t->htable_bits); | 504 | key = HKEY(d, h->initval, t->htable_bits); |
472 | n = hbucket(t, key); | 505 | n = hbucket(t, key); |
473 | for (i = 0; i < n->pos; i++) { | 506 | for (i = 0; i < n->pos; i++) { |
474 | data = ahash_data(n, i); | 507 | data = ahash_data(n, i); |
475 | if (type_pf_data_equal(data, d)) | 508 | if (type_pf_data_equal(data, d, &multi)) |
476 | return 1; | 509 | return 1; |
477 | } | 510 | } |
478 | } | 511 | } |
@@ -490,7 +523,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
490 | struct hbucket *n; | 523 | struct hbucket *n; |
491 | const struct type_pf_elem *data; | 524 | const struct type_pf_elem *data; |
492 | int i; | 525 | int i; |
493 | u32 key; | 526 | u32 key, multi = 0; |
494 | 527 | ||
495 | #ifdef IP_SET_HASH_WITH_NETS | 528 | #ifdef IP_SET_HASH_WITH_NETS |
496 | /* If we test an IP address and not a network address, | 529 | /* If we test an IP address and not a network address, |
@@ -503,7 +536,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
503 | n = hbucket(t, key); | 536 | n = hbucket(t, key); |
504 | for (i = 0; i < n->pos; i++) { | 537 | for (i = 0; i < n->pos; i++) { |
505 | data = ahash_data(n, i); | 538 | data = ahash_data(n, i); |
506 | if (type_pf_data_equal(data, d)) | 539 | if (type_pf_data_equal(data, d, &multi)) |
507 | return 1; | 540 | return 1; |
508 | } | 541 | } |
509 | return 0; | 542 | return 0; |
@@ -660,14 +693,14 @@ type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout) | |||
660 | 693 | ||
661 | static int | 694 | static int |
662 | type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value, | 695 | type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value, |
663 | u32 timeout) | 696 | u8 ahash_max, u32 timeout) |
664 | { | 697 | { |
665 | struct type_pf_elem *data; | 698 | struct type_pf_elem *data; |
666 | 699 | ||
667 | if (n->pos >= n->size) { | 700 | if (n->pos >= n->size) { |
668 | void *tmp; | 701 | void *tmp; |
669 | 702 | ||
670 | if (n->size >= AHASH_MAX_SIZE) | 703 | if (n->size >= ahash_max) |
671 | /* Trigger rehashing */ | 704 | /* Trigger rehashing */ |
672 | return -EAGAIN; | 705 | return -EAGAIN; |
673 | 706 | ||
@@ -772,7 +805,7 @@ retry: | |||
772 | for (j = 0; j < n->pos; j++) { | 805 | for (j = 0; j < n->pos; j++) { |
773 | data = ahash_tdata(n, j); | 806 | data = ahash_tdata(n, j); |
774 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); | 807 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); |
775 | ret = type_pf_elem_tadd(m, data, | 808 | ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), |
776 | type_pf_data_timeout(data)); | 809 | type_pf_data_timeout(data)); |
777 | if (ret < 0) { | 810 | if (ret < 0) { |
778 | read_unlock_bh(&set->lock); | 811 | read_unlock_bh(&set->lock); |
@@ -803,9 +836,9 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
803 | const struct type_pf_elem *d = value; | 836 | const struct type_pf_elem *d = value; |
804 | struct hbucket *n; | 837 | struct hbucket *n; |
805 | struct type_pf_elem *data; | 838 | struct type_pf_elem *data; |
806 | int ret = 0, i, j = AHASH_MAX_SIZE + 1; | 839 | int ret = 0, i, j = AHASH_MAX(h) + 1; |
807 | bool flag_exist = flags & IPSET_FLAG_EXIST; | 840 | bool flag_exist = flags & IPSET_FLAG_EXIST; |
808 | u32 key; | 841 | u32 key, multi = 0; |
809 | 842 | ||
810 | if (h->elements >= h->maxelem) | 843 | if (h->elements >= h->maxelem) |
811 | /* FIXME: when set is full, we slow down here */ | 844 | /* FIXME: when set is full, we slow down here */ |
@@ -819,18 +852,18 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
819 | n = hbucket(t, key); | 852 | n = hbucket(t, key); |
820 | for (i = 0; i < n->pos; i++) { | 853 | for (i = 0; i < n->pos; i++) { |
821 | data = ahash_tdata(n, i); | 854 | data = ahash_tdata(n, i); |
822 | if (type_pf_data_equal(data, d)) { | 855 | if (type_pf_data_equal(data, d, &multi)) { |
823 | if (type_pf_data_expired(data) || flag_exist) | 856 | if (type_pf_data_expired(data) || flag_exist) |
824 | j = i; | 857 | j = i; |
825 | else { | 858 | else { |
826 | ret = -IPSET_ERR_EXIST; | 859 | ret = -IPSET_ERR_EXIST; |
827 | goto out; | 860 | goto out; |
828 | } | 861 | } |
829 | } else if (j == AHASH_MAX_SIZE + 1 && | 862 | } else if (j == AHASH_MAX(h) + 1 && |
830 | type_pf_data_expired(data)) | 863 | type_pf_data_expired(data)) |
831 | j = i; | 864 | j = i; |
832 | } | 865 | } |
833 | if (j != AHASH_MAX_SIZE + 1) { | 866 | if (j != AHASH_MAX(h) + 1) { |
834 | data = ahash_tdata(n, j); | 867 | data = ahash_tdata(n, j); |
835 | #ifdef IP_SET_HASH_WITH_NETS | 868 | #ifdef IP_SET_HASH_WITH_NETS |
836 | del_cidr(h, data->cidr, HOST_MASK); | 869 | del_cidr(h, data->cidr, HOST_MASK); |
@@ -840,7 +873,8 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
840 | type_pf_data_timeout_set(data, timeout); | 873 | type_pf_data_timeout_set(data, timeout); |
841 | goto out; | 874 | goto out; |
842 | } | 875 | } |
843 | ret = type_pf_elem_tadd(n, d, timeout); | 876 | TUNE_AHASH_MAX(h, multi); |
877 | ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), timeout); | ||
844 | if (ret != 0) { | 878 | if (ret != 0) { |
845 | if (ret == -EAGAIN) | 879 | if (ret == -EAGAIN) |
846 | type_pf_data_next(h, d); | 880 | type_pf_data_next(h, d); |
@@ -865,13 +899,13 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
865 | struct hbucket *n; | 899 | struct hbucket *n; |
866 | int i; | 900 | int i; |
867 | struct type_pf_elem *data; | 901 | struct type_pf_elem *data; |
868 | u32 key; | 902 | u32 key, multi = 0; |
869 | 903 | ||
870 | key = HKEY(value, h->initval, t->htable_bits); | 904 | key = HKEY(value, h->initval, t->htable_bits); |
871 | n = hbucket(t, key); | 905 | n = hbucket(t, key); |
872 | for (i = 0; i < n->pos; i++) { | 906 | for (i = 0; i < n->pos; i++) { |
873 | data = ahash_tdata(n, i); | 907 | data = ahash_tdata(n, i); |
874 | if (!type_pf_data_equal(data, d)) | 908 | if (!type_pf_data_equal(data, d, &multi)) |
875 | continue; | 909 | continue; |
876 | if (type_pf_data_expired(data)) | 910 | if (type_pf_data_expired(data)) |
877 | return -IPSET_ERR_EXIST; | 911 | return -IPSET_ERR_EXIST; |
@@ -911,16 +945,16 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) | |||
911 | struct type_pf_elem *data; | 945 | struct type_pf_elem *data; |
912 | struct hbucket *n; | 946 | struct hbucket *n; |
913 | int i, j = 0; | 947 | int i, j = 0; |
914 | u32 key; | 948 | u32 key, multi = 0; |
915 | u8 host_mask = SET_HOST_MASK(set->family); | 949 | u8 host_mask = SET_HOST_MASK(set->family); |
916 | 950 | ||
917 | for (; j < host_mask && h->nets[j].cidr; j++) { | 951 | for (; j < host_mask && h->nets[j].cidr && !multi; j++) { |
918 | type_pf_data_netmask(d, h->nets[j].cidr); | 952 | type_pf_data_netmask(d, h->nets[j].cidr); |
919 | key = HKEY(d, h->initval, t->htable_bits); | 953 | key = HKEY(d, h->initval, t->htable_bits); |
920 | n = hbucket(t, key); | 954 | n = hbucket(t, key); |
921 | for (i = 0; i < n->pos; i++) { | 955 | for (i = 0; i < n->pos; i++) { |
922 | data = ahash_tdata(n, i); | 956 | data = ahash_tdata(n, i); |
923 | if (type_pf_data_equal(data, d)) | 957 | if (type_pf_data_equal(data, d, &multi)) |
924 | return !type_pf_data_expired(data); | 958 | return !type_pf_data_expired(data); |
925 | } | 959 | } |
926 | } | 960 | } |
@@ -936,7 +970,7 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
936 | struct type_pf_elem *data, *d = value; | 970 | struct type_pf_elem *data, *d = value; |
937 | struct hbucket *n; | 971 | struct hbucket *n; |
938 | int i; | 972 | int i; |
939 | u32 key; | 973 | u32 key, multi = 0; |
940 | 974 | ||
941 | #ifdef IP_SET_HASH_WITH_NETS | 975 | #ifdef IP_SET_HASH_WITH_NETS |
942 | if (d->cidr == SET_HOST_MASK(set->family)) | 976 | if (d->cidr == SET_HOST_MASK(set->family)) |
@@ -946,7 +980,7 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags) | |||
946 | n = hbucket(t, key); | 980 | n = hbucket(t, key); |
947 | for (i = 0; i < n->pos; i++) { | 981 | for (i = 0; i < n->pos; i++) { |
948 | data = ahash_tdata(n, i); | 982 | data = ahash_tdata(n, i); |
949 | if (type_pf_data_equal(data, d)) | 983 | if (type_pf_data_equal(data, d, &multi)) |
950 | return !type_pf_data_expired(data); | 984 | return !type_pf_data_expired(data); |
951 | } | 985 | } |
952 | return 0; | 986 | return 0; |
@@ -1054,6 +1088,8 @@ type_pf_gc_init(struct ip_set *set) | |||
1054 | IPSET_GC_PERIOD(h->timeout)); | 1088 | IPSET_GC_PERIOD(h->timeout)); |
1055 | } | 1089 | } |
1056 | 1090 | ||
1091 | #undef HKEY_DATALEN | ||
1092 | #undef HKEY | ||
1057 | #undef type_pf_data_equal | 1093 | #undef type_pf_data_equal |
1058 | #undef type_pf_data_isnull | 1094 | #undef type_pf_data_isnull |
1059 | #undef type_pf_data_copy | 1095 | #undef type_pf_data_copy |
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 2b11fc1a86be..74d33861473c 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h | |||
@@ -60,6 +60,9 @@ struct nfnl_callback { | |||
60 | int (*call)(struct sock *nl, struct sk_buff *skb, | 60 | int (*call)(struct sock *nl, struct sk_buff *skb, |
61 | const struct nlmsghdr *nlh, | 61 | const struct nlmsghdr *nlh, |
62 | const struct nlattr * const cda[]); | 62 | const struct nlattr * const cda[]); |
63 | int (*call_rcu)(struct sock *nl, struct sk_buff *skb, | ||
64 | const struct nlmsghdr *nlh, | ||
65 | const struct nlattr * const cda[]); | ||
63 | const struct nla_policy *policy; /* netlink attribute policy */ | 66 | const struct nla_policy *policy; /* netlink attribute policy */ |
64 | const u_int16_t attr_count; /* number of nlattr's */ | 67 | const u_int16_t attr_count; /* number of nlattr's */ |
65 | }; | 68 | }; |
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h index af94e0014ebd..24b32e6c009e 100644 --- a/include/linux/netfilter/nfnetlink_queue.h +++ b/include/linux/netfilter/nfnetlink_queue.h | |||
@@ -8,6 +8,7 @@ enum nfqnl_msg_types { | |||
8 | NFQNL_MSG_PACKET, /* packet from kernel to userspace */ | 8 | NFQNL_MSG_PACKET, /* packet from kernel to userspace */ |
9 | NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */ | 9 | NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */ |
10 | NFQNL_MSG_CONFIG, /* connect to a particular queue */ | 10 | NFQNL_MSG_CONFIG, /* connect to a particular queue */ |
11 | NFQNL_MSG_VERDICT_BATCH, /* batchv from userspace to kernel */ | ||
11 | 12 | ||
12 | NFQNL_MSG_MAX | 13 | NFQNL_MSG_MAX |
13 | }; | 14 | }; |
diff --git a/kernel/audit.c b/kernel/audit.c index 939500317066..52501b5d4902 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -55,6 +55,9 @@ | |||
55 | #include <net/sock.h> | 55 | #include <net/sock.h> |
56 | #include <net/netlink.h> | 56 | #include <net/netlink.h> |
57 | #include <linux/skbuff.h> | 57 | #include <linux/skbuff.h> |
58 | #ifdef CONFIG_SECURITY | ||
59 | #include <linux/security.h> | ||
60 | #endif | ||
58 | #include <linux/netlink.h> | 61 | #include <linux/netlink.h> |
59 | #include <linux/freezer.h> | 62 | #include <linux/freezer.h> |
60 | #include <linux/tty.h> | 63 | #include <linux/tty.h> |
@@ -1502,6 +1505,32 @@ void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, | |||
1502 | } | 1505 | } |
1503 | } | 1506 | } |
1504 | 1507 | ||
1508 | #ifdef CONFIG_SECURITY | ||
1509 | /** | ||
1510 | * audit_log_secctx - Converts and logs SELinux context | ||
1511 | * @ab: audit_buffer | ||
1512 | * @secid: security number | ||
1513 | * | ||
1514 | * This is a helper function that calls security_secid_to_secctx to convert | ||
1515 | * secid to secctx and then adds the (converted) SELinux context to the audit | ||
1516 | * log by calling audit_log_format, thus also preventing leak of internal secid | ||
1517 | * to userspace. If secid cannot be converted audit_panic is called. | ||
1518 | */ | ||
1519 | void audit_log_secctx(struct audit_buffer *ab, u32 secid) | ||
1520 | { | ||
1521 | u32 len; | ||
1522 | char *secctx; | ||
1523 | |||
1524 | if (security_secid_to_secctx(secid, &secctx, &len)) { | ||
1525 | audit_panic("Cannot convert secid to context"); | ||
1526 | } else { | ||
1527 | audit_log_format(ab, " obj=%s", secctx); | ||
1528 | security_release_secctx(secctx, len); | ||
1529 | } | ||
1530 | } | ||
1531 | EXPORT_SYMBOL(audit_log_secctx); | ||
1532 | #endif | ||
1533 | |||
1505 | EXPORT_SYMBOL(audit_log_start); | 1534 | EXPORT_SYMBOL(audit_log_start); |
1506 | EXPORT_SYMBOL(audit_log_end); | 1535 | EXPORT_SYMBOL(audit_log_end); |
1507 | EXPORT_SYMBOL(audit_log_format); | 1536 | EXPORT_SYMBOL(audit_log_format); |
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index fa80bb9b9c81..f2d576e6b769 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c | |||
@@ -53,7 +53,8 @@ struct hash_ip4_telem { | |||
53 | 53 | ||
54 | static inline bool | 54 | static inline bool |
55 | hash_ip4_data_equal(const struct hash_ip4_elem *ip1, | 55 | hash_ip4_data_equal(const struct hash_ip4_elem *ip1, |
56 | const struct hash_ip4_elem *ip2) | 56 | const struct hash_ip4_elem *ip2, |
57 | u32 *multi) | ||
57 | { | 58 | { |
58 | return ip1->ip == ip2->ip; | 59 | return ip1->ip == ip2->ip; |
59 | } | 60 | } |
@@ -225,7 +226,8 @@ struct hash_ip6_telem { | |||
225 | 226 | ||
226 | static inline bool | 227 | static inline bool |
227 | hash_ip6_data_equal(const struct hash_ip6_elem *ip1, | 228 | hash_ip6_data_equal(const struct hash_ip6_elem *ip1, |
228 | const struct hash_ip6_elem *ip2) | 229 | const struct hash_ip6_elem *ip2, |
230 | u32 *multi) | ||
229 | { | 231 | { |
230 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0; | 232 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0; |
231 | } | 233 | } |
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index bbf51b67b170..6ee10f5d59bd 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c | |||
@@ -60,7 +60,8 @@ struct hash_ipport4_telem { | |||
60 | 60 | ||
61 | static inline bool | 61 | static inline bool |
62 | hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1, | 62 | hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1, |
63 | const struct hash_ipport4_elem *ip2) | 63 | const struct hash_ipport4_elem *ip2, |
64 | u32 *multi) | ||
64 | { | 65 | { |
65 | return ip1->ip == ip2->ip && | 66 | return ip1->ip == ip2->ip && |
66 | ip1->port == ip2->port && | 67 | ip1->port == ip2->port && |
@@ -276,7 +277,8 @@ struct hash_ipport6_telem { | |||
276 | 277 | ||
277 | static inline bool | 278 | static inline bool |
278 | hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1, | 279 | hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1, |
279 | const struct hash_ipport6_elem *ip2) | 280 | const struct hash_ipport6_elem *ip2, |
281 | u32 *multi) | ||
280 | { | 282 | { |
281 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 283 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
282 | ip1->port == ip2->port && | 284 | ip1->port == ip2->port && |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 96525f529a54..fb90e344e907 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c | |||
@@ -62,7 +62,8 @@ struct hash_ipportip4_telem { | |||
62 | 62 | ||
63 | static inline bool | 63 | static inline bool |
64 | hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, | 64 | hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, |
65 | const struct hash_ipportip4_elem *ip2) | 65 | const struct hash_ipportip4_elem *ip2, |
66 | u32 *multi) | ||
66 | { | 67 | { |
67 | return ip1->ip == ip2->ip && | 68 | return ip1->ip == ip2->ip && |
68 | ip1->ip2 == ip2->ip2 && | 69 | ip1->ip2 == ip2->ip2 && |
@@ -286,7 +287,8 @@ struct hash_ipportip6_telem { | |||
286 | 287 | ||
287 | static inline bool | 288 | static inline bool |
288 | hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, | 289 | hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, |
289 | const struct hash_ipportip6_elem *ip2) | 290 | const struct hash_ipportip6_elem *ip2, |
291 | u32 *multi) | ||
290 | { | 292 | { |
291 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 293 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
292 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && | 294 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index d2d6ab89f087..deb3e3dfa5fc 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
@@ -62,7 +62,8 @@ struct hash_ipportnet4_telem { | |||
62 | 62 | ||
63 | static inline bool | 63 | static inline bool |
64 | hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1, | 64 | hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1, |
65 | const struct hash_ipportnet4_elem *ip2) | 65 | const struct hash_ipportnet4_elem *ip2, |
66 | u32 *multi) | ||
66 | { | 67 | { |
67 | return ip1->ip == ip2->ip && | 68 | return ip1->ip == ip2->ip && |
68 | ip1->ip2 == ip2->ip2 && | 69 | ip1->ip2 == ip2->ip2 && |
@@ -335,7 +336,8 @@ struct hash_ipportnet6_telem { | |||
335 | 336 | ||
336 | static inline bool | 337 | static inline bool |
337 | hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1, | 338 | hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1, |
338 | const struct hash_ipportnet6_elem *ip2) | 339 | const struct hash_ipportnet6_elem *ip2, |
340 | u32 *multi) | ||
339 | { | 341 | { |
340 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 342 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
341 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && | 343 | ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && |
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 2d4b1f48e8c9..60d016541c58 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
@@ -58,7 +58,8 @@ struct hash_net4_telem { | |||
58 | 58 | ||
59 | static inline bool | 59 | static inline bool |
60 | hash_net4_data_equal(const struct hash_net4_elem *ip1, | 60 | hash_net4_data_equal(const struct hash_net4_elem *ip1, |
61 | const struct hash_net4_elem *ip2) | 61 | const struct hash_net4_elem *ip2, |
62 | u32 *multi) | ||
62 | { | 63 | { |
63 | return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; | 64 | return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; |
64 | } | 65 | } |
@@ -249,7 +250,8 @@ struct hash_net6_telem { | |||
249 | 250 | ||
250 | static inline bool | 251 | static inline bool |
251 | hash_net6_data_equal(const struct hash_net6_elem *ip1, | 252 | hash_net6_data_equal(const struct hash_net6_elem *ip1, |
252 | const struct hash_net6_elem *ip2) | 253 | const struct hash_net6_elem *ip2, |
254 | u32 *multi) | ||
253 | { | 255 | { |
254 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 256 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
255 | ip1->cidr == ip2->cidr; | 257 | ip1->cidr == ip2->cidr; |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index 3d6c53b6211a..e13095deb50d 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
@@ -99,7 +99,7 @@ iface_test(struct rb_root *root, const char **iface) | |||
99 | 99 | ||
100 | while (n) { | 100 | while (n) { |
101 | const char *d = iface_data(n); | 101 | const char *d = iface_data(n); |
102 | int res = ifname_compare(*iface, d); | 102 | long res = ifname_compare(*iface, d); |
103 | 103 | ||
104 | if (res < 0) | 104 | if (res < 0) |
105 | n = n->rb_left; | 105 | n = n->rb_left; |
@@ -121,7 +121,7 @@ iface_add(struct rb_root *root, const char **iface) | |||
121 | 121 | ||
122 | while (*n) { | 122 | while (*n) { |
123 | char *ifname = iface_data(*n); | 123 | char *ifname = iface_data(*n); |
124 | int res = ifname_compare(*iface, ifname); | 124 | long res = ifname_compare(*iface, ifname); |
125 | 125 | ||
126 | p = *n; | 126 | p = *n; |
127 | if (res < 0) | 127 | if (res < 0) |
@@ -159,31 +159,42 @@ hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b); | |||
159 | 159 | ||
160 | /* The type variant functions: IPv4 */ | 160 | /* The type variant functions: IPv4 */ |
161 | 161 | ||
162 | struct hash_netiface4_elem_hashed { | ||
163 | __be32 ip; | ||
164 | u8 physdev; | ||
165 | u8 cidr; | ||
166 | u16 padding; | ||
167 | }; | ||
168 | |||
169 | #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) | ||
170 | |||
162 | /* Member elements without timeout */ | 171 | /* Member elements without timeout */ |
163 | struct hash_netiface4_elem { | 172 | struct hash_netiface4_elem { |
164 | __be32 ip; | 173 | __be32 ip; |
165 | const char *iface; | ||
166 | u8 physdev; | 174 | u8 physdev; |
167 | u8 cidr; | 175 | u8 cidr; |
168 | u16 padding; | 176 | u16 padding; |
177 | const char *iface; | ||
169 | }; | 178 | }; |
170 | 179 | ||
171 | /* Member elements with timeout support */ | 180 | /* Member elements with timeout support */ |
172 | struct hash_netiface4_telem { | 181 | struct hash_netiface4_telem { |
173 | __be32 ip; | 182 | __be32 ip; |
174 | const char *iface; | ||
175 | u8 physdev; | 183 | u8 physdev; |
176 | u8 cidr; | 184 | u8 cidr; |
177 | u16 padding; | 185 | u16 padding; |
186 | const char *iface; | ||
178 | unsigned long timeout; | 187 | unsigned long timeout; |
179 | }; | 188 | }; |
180 | 189 | ||
181 | static inline bool | 190 | static inline bool |
182 | hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1, | 191 | hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1, |
183 | const struct hash_netiface4_elem *ip2) | 192 | const struct hash_netiface4_elem *ip2, |
193 | u32 *multi) | ||
184 | { | 194 | { |
185 | return ip1->ip == ip2->ip && | 195 | return ip1->ip == ip2->ip && |
186 | ip1->cidr == ip2->cidr && | 196 | ip1->cidr == ip2->cidr && |
197 | (++*multi) && | ||
187 | ip1->physdev == ip2->physdev && | 198 | ip1->physdev == ip2->physdev && |
188 | ip1->iface == ip2->iface; | 199 | ip1->iface == ip2->iface; |
189 | } | 200 | } |
@@ -257,6 +268,7 @@ nla_put_failure: | |||
257 | 268 | ||
258 | #define IP_SET_HASH_WITH_NETS | 269 | #define IP_SET_HASH_WITH_NETS |
259 | #define IP_SET_HASH_WITH_RBTREE | 270 | #define IP_SET_HASH_WITH_RBTREE |
271 | #define IP_SET_HASH_WITH_MULTI | ||
260 | 272 | ||
261 | #define PF 4 | 273 | #define PF 4 |
262 | #define HOST_MASK 32 | 274 | #define HOST_MASK 32 |
@@ -424,29 +436,40 @@ hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b) | |||
424 | 436 | ||
425 | /* The type variant functions: IPv6 */ | 437 | /* The type variant functions: IPv6 */ |
426 | 438 | ||
439 | struct hash_netiface6_elem_hashed { | ||
440 | union nf_inet_addr ip; | ||
441 | u8 physdev; | ||
442 | u8 cidr; | ||
443 | u16 padding; | ||
444 | }; | ||
445 | |||
446 | #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed) | ||
447 | |||
427 | struct hash_netiface6_elem { | 448 | struct hash_netiface6_elem { |
428 | union nf_inet_addr ip; | 449 | union nf_inet_addr ip; |
429 | const char *iface; | ||
430 | u8 physdev; | 450 | u8 physdev; |
431 | u8 cidr; | 451 | u8 cidr; |
432 | u16 padding; | 452 | u16 padding; |
453 | const char *iface; | ||
433 | }; | 454 | }; |
434 | 455 | ||
435 | struct hash_netiface6_telem { | 456 | struct hash_netiface6_telem { |
436 | union nf_inet_addr ip; | 457 | union nf_inet_addr ip; |
437 | const char *iface; | ||
438 | u8 physdev; | 458 | u8 physdev; |
439 | u8 cidr; | 459 | u8 cidr; |
440 | u16 padding; | 460 | u16 padding; |
461 | const char *iface; | ||
441 | unsigned long timeout; | 462 | unsigned long timeout; |
442 | }; | 463 | }; |
443 | 464 | ||
444 | static inline bool | 465 | static inline bool |
445 | hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1, | 466 | hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1, |
446 | const struct hash_netiface6_elem *ip2) | 467 | const struct hash_netiface6_elem *ip2, |
468 | u32 *multi) | ||
447 | { | 469 | { |
448 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 470 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
449 | ip1->cidr == ip2->cidr && | 471 | ip1->cidr == ip2->cidr && |
472 | (++*multi) && | ||
450 | ip1->physdev == ip2->physdev && | 473 | ip1->physdev == ip2->physdev && |
451 | ip1->iface == ip2->iface; | 474 | ip1->iface == ip2->iface; |
452 | } | 475 | } |
@@ -681,6 +704,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
681 | h->maxelem = maxelem; | 704 | h->maxelem = maxelem; |
682 | get_random_bytes(&h->initval, sizeof(h->initval)); | 705 | get_random_bytes(&h->initval, sizeof(h->initval)); |
683 | h->timeout = IPSET_NO_TIMEOUT; | 706 | h->timeout = IPSET_NO_TIMEOUT; |
707 | h->ahash_max = AHASH_MAX_SIZE; | ||
684 | 708 | ||
685 | hbits = htable_bits(hashsize); | 709 | hbits = htable_bits(hashsize); |
686 | h->table = ip_set_alloc( | 710 | h->table = ip_set_alloc( |
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index fe203d12f56b..8f9de7207ec9 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
@@ -59,7 +59,8 @@ struct hash_netport4_telem { | |||
59 | 59 | ||
60 | static inline bool | 60 | static inline bool |
61 | hash_netport4_data_equal(const struct hash_netport4_elem *ip1, | 61 | hash_netport4_data_equal(const struct hash_netport4_elem *ip1, |
62 | const struct hash_netport4_elem *ip2) | 62 | const struct hash_netport4_elem *ip2, |
63 | u32 *multi) | ||
63 | { | 64 | { |
64 | return ip1->ip == ip2->ip && | 65 | return ip1->ip == ip2->ip && |
65 | ip1->port == ip2->port && | 66 | ip1->port == ip2->port && |
@@ -300,7 +301,8 @@ struct hash_netport6_telem { | |||
300 | 301 | ||
301 | static inline bool | 302 | static inline bool |
302 | hash_netport6_data_equal(const struct hash_netport6_elem *ip1, | 303 | hash_netport6_data_equal(const struct hash_netport6_elem *ip1, |
303 | const struct hash_netport6_elem *ip2) | 304 | const struct hash_netport6_elem *ip2, |
305 | u32 *multi) | ||
304 | { | 306 | { |
305 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && | 307 | return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && |
306 | ip1->port == ip2->port && | 308 | ip1->port == ip2->port && |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b4a4532823e8..1905976b5135 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -37,7 +37,7 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); | |||
37 | 37 | ||
38 | static char __initdata nfversion[] = "0.30"; | 38 | static char __initdata nfversion[] = "0.30"; |
39 | 39 | ||
40 | static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; | 40 | static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT]; |
41 | static DEFINE_MUTEX(nfnl_mutex); | 41 | static DEFINE_MUTEX(nfnl_mutex); |
42 | 42 | ||
43 | void nfnl_lock(void) | 43 | void nfnl_lock(void) |
@@ -59,7 +59,7 @@ int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n) | |||
59 | nfnl_unlock(); | 59 | nfnl_unlock(); |
60 | return -EBUSY; | 60 | return -EBUSY; |
61 | } | 61 | } |
62 | subsys_table[n->subsys_id] = n; | 62 | rcu_assign_pointer(subsys_table[n->subsys_id], n); |
63 | nfnl_unlock(); | 63 | nfnl_unlock(); |
64 | 64 | ||
65 | return 0; | 65 | return 0; |
@@ -71,7 +71,7 @@ int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n) | |||
71 | nfnl_lock(); | 71 | nfnl_lock(); |
72 | subsys_table[n->subsys_id] = NULL; | 72 | subsys_table[n->subsys_id] = NULL; |
73 | nfnl_unlock(); | 73 | nfnl_unlock(); |
74 | 74 | synchronize_rcu(); | |
75 | return 0; | 75 | return 0; |
76 | } | 76 | } |
77 | EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); | 77 | EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); |
@@ -83,7 +83,7 @@ static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t t | |||
83 | if (subsys_id >= NFNL_SUBSYS_COUNT) | 83 | if (subsys_id >= NFNL_SUBSYS_COUNT) |
84 | return NULL; | 84 | return NULL; |
85 | 85 | ||
86 | return subsys_table[subsys_id]; | 86 | return rcu_dereference(subsys_table[subsys_id]); |
87 | } | 87 | } |
88 | 88 | ||
89 | static inline const struct nfnl_callback * | 89 | static inline const struct nfnl_callback * |
@@ -139,21 +139,27 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
139 | 139 | ||
140 | type = nlh->nlmsg_type; | 140 | type = nlh->nlmsg_type; |
141 | replay: | 141 | replay: |
142 | rcu_read_lock(); | ||
142 | ss = nfnetlink_get_subsys(type); | 143 | ss = nfnetlink_get_subsys(type); |
143 | if (!ss) { | 144 | if (!ss) { |
144 | #ifdef CONFIG_MODULES | 145 | #ifdef CONFIG_MODULES |
145 | nfnl_unlock(); | 146 | rcu_read_unlock(); |
146 | request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); | 147 | request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); |
147 | nfnl_lock(); | 148 | rcu_read_lock(); |
148 | ss = nfnetlink_get_subsys(type); | 149 | ss = nfnetlink_get_subsys(type); |
149 | if (!ss) | 150 | if (!ss) |
150 | #endif | 151 | #endif |
152 | { | ||
153 | rcu_read_unlock(); | ||
151 | return -EINVAL; | 154 | return -EINVAL; |
155 | } | ||
152 | } | 156 | } |
153 | 157 | ||
154 | nc = nfnetlink_find_client(type, ss); | 158 | nc = nfnetlink_find_client(type, ss); |
155 | if (!nc) | 159 | if (!nc) { |
160 | rcu_read_unlock(); | ||
156 | return -EINVAL; | 161 | return -EINVAL; |
162 | } | ||
157 | 163 | ||
158 | { | 164 | { |
159 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); | 165 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); |
@@ -167,7 +173,23 @@ replay: | |||
167 | if (err < 0) | 173 | if (err < 0) |
168 | return err; | 174 | return err; |
169 | 175 | ||
170 | err = nc->call(net->nfnl, skb, nlh, (const struct nlattr **)cda); | 176 | if (nc->call_rcu) { |
177 | err = nc->call_rcu(net->nfnl, skb, nlh, | ||
178 | (const struct nlattr **)cda); | ||
179 | rcu_read_unlock(); | ||
180 | } else { | ||
181 | rcu_read_unlock(); | ||
182 | nfnl_lock(); | ||
183 | if (rcu_dereference_protected( | ||
184 | subsys_table[NFNL_SUBSYS_ID(type)], | ||
185 | lockdep_is_held(&nfnl_mutex)) != ss || | ||
186 | nfnetlink_find_client(type, ss) != nc) | ||
187 | err = -EAGAIN; | ||
188 | else | ||
189 | err = nc->call(net->nfnl, skb, nlh, | ||
190 | (const struct nlattr **)cda); | ||
191 | nfnl_unlock(); | ||
192 | } | ||
171 | if (err == -EAGAIN) | 193 | if (err == -EAGAIN) |
172 | goto replay; | 194 | goto replay; |
173 | return err; | 195 | return err; |
@@ -176,9 +198,7 @@ replay: | |||
176 | 198 | ||
177 | static void nfnetlink_rcv(struct sk_buff *skb) | 199 | static void nfnetlink_rcv(struct sk_buff *skb) |
178 | { | 200 | { |
179 | nfnl_lock(); | ||
180 | netlink_rcv_skb(skb, &nfnetlink_rcv_msg); | 201 | netlink_rcv_skb(skb, &nfnetlink_rcv_msg); |
181 | nfnl_unlock(); | ||
182 | } | 202 | } |
183 | 203 | ||
184 | static int __net_init nfnetlink_net_init(struct net *net) | 204 | static int __net_init nfnetlink_net_init(struct net *net) |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index fdd2fafe0a14..49132bddd73e 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -58,7 +58,7 @@ struct nfqnl_instance { | |||
58 | */ | 58 | */ |
59 | spinlock_t lock; | 59 | spinlock_t lock; |
60 | unsigned int queue_total; | 60 | unsigned int queue_total; |
61 | atomic_t id_sequence; /* 'sequence' of pkt ids */ | 61 | unsigned int id_sequence; /* 'sequence' of pkt ids */ |
62 | struct list_head queue_list; /* packets in queue */ | 62 | struct list_head queue_list; /* packets in queue */ |
63 | }; | 63 | }; |
64 | 64 | ||
@@ -171,6 +171,13 @@ __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) | |||
171 | queue->queue_total++; | 171 | queue->queue_total++; |
172 | } | 172 | } |
173 | 173 | ||
174 | static void | ||
175 | __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) | ||
176 | { | ||
177 | list_del(&entry->list); | ||
178 | queue->queue_total--; | ||
179 | } | ||
180 | |||
174 | static struct nf_queue_entry * | 181 | static struct nf_queue_entry * |
175 | find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) | 182 | find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) |
176 | { | 183 | { |
@@ -185,10 +192,8 @@ find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) | |||
185 | } | 192 | } |
186 | } | 193 | } |
187 | 194 | ||
188 | if (entry) { | 195 | if (entry) |
189 | list_del(&entry->list); | 196 | __dequeue_entry(queue, entry); |
190 | queue->queue_total--; | ||
191 | } | ||
192 | 197 | ||
193 | spin_unlock_bh(&queue->lock); | 198 | spin_unlock_bh(&queue->lock); |
194 | 199 | ||
@@ -213,13 +218,15 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) | |||
213 | 218 | ||
214 | static struct sk_buff * | 219 | static struct sk_buff * |
215 | nfqnl_build_packet_message(struct nfqnl_instance *queue, | 220 | nfqnl_build_packet_message(struct nfqnl_instance *queue, |
216 | struct nf_queue_entry *entry) | 221 | struct nf_queue_entry *entry, |
222 | __be32 **packet_id_ptr) | ||
217 | { | 223 | { |
218 | sk_buff_data_t old_tail; | 224 | sk_buff_data_t old_tail; |
219 | size_t size; | 225 | size_t size; |
220 | size_t data_len = 0; | 226 | size_t data_len = 0; |
221 | struct sk_buff *skb; | 227 | struct sk_buff *skb; |
222 | struct nfqnl_msg_packet_hdr pmsg; | 228 | struct nlattr *nla; |
229 | struct nfqnl_msg_packet_hdr *pmsg; | ||
223 | struct nlmsghdr *nlh; | 230 | struct nlmsghdr *nlh; |
224 | struct nfgenmsg *nfmsg; | 231 | struct nfgenmsg *nfmsg; |
225 | struct sk_buff *entskb = entry->skb; | 232 | struct sk_buff *entskb = entry->skb; |
@@ -272,12 +279,11 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
272 | nfmsg->version = NFNETLINK_V0; | 279 | nfmsg->version = NFNETLINK_V0; |
273 | nfmsg->res_id = htons(queue->queue_num); | 280 | nfmsg->res_id = htons(queue->queue_num); |
274 | 281 | ||
275 | entry->id = atomic_inc_return(&queue->id_sequence); | 282 | nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg)); |
276 | pmsg.packet_id = htonl(entry->id); | 283 | pmsg = nla_data(nla); |
277 | pmsg.hw_protocol = entskb->protocol; | 284 | pmsg->hw_protocol = entskb->protocol; |
278 | pmsg.hook = entry->hook; | 285 | pmsg->hook = entry->hook; |
279 | 286 | *packet_id_ptr = &pmsg->packet_id; | |
280 | NLA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg); | ||
281 | 287 | ||
282 | indev = entry->indev; | 288 | indev = entry->indev; |
283 | if (indev) { | 289 | if (indev) { |
@@ -389,6 +395,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
389 | struct sk_buff *nskb; | 395 | struct sk_buff *nskb; |
390 | struct nfqnl_instance *queue; | 396 | struct nfqnl_instance *queue; |
391 | int err = -ENOBUFS; | 397 | int err = -ENOBUFS; |
398 | __be32 *packet_id_ptr; | ||
392 | 399 | ||
393 | /* rcu_read_lock()ed by nf_hook_slow() */ | 400 | /* rcu_read_lock()ed by nf_hook_slow() */ |
394 | queue = instance_lookup(queuenum); | 401 | queue = instance_lookup(queuenum); |
@@ -402,7 +409,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
402 | goto err_out; | 409 | goto err_out; |
403 | } | 410 | } |
404 | 411 | ||
405 | nskb = nfqnl_build_packet_message(queue, entry); | 412 | nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr); |
406 | if (nskb == NULL) { | 413 | if (nskb == NULL) { |
407 | err = -ENOMEM; | 414 | err = -ENOMEM; |
408 | goto err_out; | 415 | goto err_out; |
@@ -421,6 +428,8 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
421 | queue->queue_total); | 428 | queue->queue_total); |
422 | goto err_out_free_nskb; | 429 | goto err_out_free_nskb; |
423 | } | 430 | } |
431 | entry->id = ++queue->id_sequence; | ||
432 | *packet_id_ptr = htonl(entry->id); | ||
424 | 433 | ||
425 | /* nfnetlink_unicast will either free the nskb or add it to a socket */ | 434 | /* nfnetlink_unicast will either free the nskb or add it to a socket */ |
426 | err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); | 435 | err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); |
@@ -608,6 +617,92 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = { | |||
608 | [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, | 617 | [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, |
609 | }; | 618 | }; |
610 | 619 | ||
620 | static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = { | ||
621 | [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) }, | ||
622 | [NFQA_MARK] = { .type = NLA_U32 }, | ||
623 | }; | ||
624 | |||
625 | static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid) | ||
626 | { | ||
627 | struct nfqnl_instance *queue; | ||
628 | |||
629 | queue = instance_lookup(queue_num); | ||
630 | if (!queue) | ||
631 | return ERR_PTR(-ENODEV); | ||
632 | |||
633 | if (queue->peer_pid != nlpid) | ||
634 | return ERR_PTR(-EPERM); | ||
635 | |||
636 | return queue; | ||
637 | } | ||
638 | |||
639 | static struct nfqnl_msg_verdict_hdr* | ||
640 | verdicthdr_get(const struct nlattr * const nfqa[]) | ||
641 | { | ||
642 | struct nfqnl_msg_verdict_hdr *vhdr; | ||
643 | unsigned int verdict; | ||
644 | |||
645 | if (!nfqa[NFQA_VERDICT_HDR]) | ||
646 | return NULL; | ||
647 | |||
648 | vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); | ||
649 | verdict = ntohl(vhdr->verdict); | ||
650 | if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) | ||
651 | return NULL; | ||
652 | return vhdr; | ||
653 | } | ||
654 | |||
655 | static int nfq_id_after(unsigned int id, unsigned int max) | ||
656 | { | ||
657 | return (int)(id - max) > 0; | ||
658 | } | ||
659 | |||
660 | static int | ||
661 | nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb, | ||
662 | const struct nlmsghdr *nlh, | ||
663 | const struct nlattr * const nfqa[]) | ||
664 | { | ||
665 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
666 | struct nf_queue_entry *entry, *tmp; | ||
667 | unsigned int verdict, maxid; | ||
668 | struct nfqnl_msg_verdict_hdr *vhdr; | ||
669 | struct nfqnl_instance *queue; | ||
670 | LIST_HEAD(batch_list); | ||
671 | u16 queue_num = ntohs(nfmsg->res_id); | ||
672 | |||
673 | queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); | ||
674 | if (IS_ERR(queue)) | ||
675 | return PTR_ERR(queue); | ||
676 | |||
677 | vhdr = verdicthdr_get(nfqa); | ||
678 | if (!vhdr) | ||
679 | return -EINVAL; | ||
680 | |||
681 | verdict = ntohl(vhdr->verdict); | ||
682 | maxid = ntohl(vhdr->id); | ||
683 | |||
684 | spin_lock_bh(&queue->lock); | ||
685 | |||
686 | list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) { | ||
687 | if (nfq_id_after(entry->id, maxid)) | ||
688 | break; | ||
689 | __dequeue_entry(queue, entry); | ||
690 | list_add_tail(&entry->list, &batch_list); | ||
691 | } | ||
692 | |||
693 | spin_unlock_bh(&queue->lock); | ||
694 | |||
695 | if (list_empty(&batch_list)) | ||
696 | return -ENOENT; | ||
697 | |||
698 | list_for_each_entry_safe(entry, tmp, &batch_list, list) { | ||
699 | if (nfqa[NFQA_MARK]) | ||
700 | entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK])); | ||
701 | nf_reinject(entry, verdict); | ||
702 | } | ||
703 | return 0; | ||
704 | } | ||
705 | |||
611 | static int | 706 | static int |
612 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | 707 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, |
613 | const struct nlmsghdr *nlh, | 708 | const struct nlmsghdr *nlh, |
@@ -620,39 +715,23 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | |||
620 | struct nfqnl_instance *queue; | 715 | struct nfqnl_instance *queue; |
621 | unsigned int verdict; | 716 | unsigned int verdict; |
622 | struct nf_queue_entry *entry; | 717 | struct nf_queue_entry *entry; |
623 | int err; | ||
624 | 718 | ||
625 | rcu_read_lock(); | ||
626 | queue = instance_lookup(queue_num); | 719 | queue = instance_lookup(queue_num); |
627 | if (!queue) { | 720 | if (!queue) |
628 | err = -ENODEV; | ||
629 | goto err_out_unlock; | ||
630 | } | ||
631 | 721 | ||
632 | if (queue->peer_pid != NETLINK_CB(skb).pid) { | 722 | queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); |
633 | err = -EPERM; | 723 | if (IS_ERR(queue)) |
634 | goto err_out_unlock; | 724 | return PTR_ERR(queue); |
635 | } | ||
636 | 725 | ||
637 | if (!nfqa[NFQA_VERDICT_HDR]) { | 726 | vhdr = verdicthdr_get(nfqa); |
638 | err = -EINVAL; | 727 | if (!vhdr) |
639 | goto err_out_unlock; | 728 | return -EINVAL; |
640 | } | ||
641 | 729 | ||
642 | vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); | ||
643 | verdict = ntohl(vhdr->verdict); | 730 | verdict = ntohl(vhdr->verdict); |
644 | 731 | ||
645 | if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) { | ||
646 | err = -EINVAL; | ||
647 | goto err_out_unlock; | ||
648 | } | ||
649 | |||
650 | entry = find_dequeue_entry(queue, ntohl(vhdr->id)); | 732 | entry = find_dequeue_entry(queue, ntohl(vhdr->id)); |
651 | if (entry == NULL) { | 733 | if (entry == NULL) |
652 | err = -ENOENT; | 734 | return -ENOENT; |
653 | goto err_out_unlock; | ||
654 | } | ||
655 | rcu_read_unlock(); | ||
656 | 735 | ||
657 | if (nfqa[NFQA_PAYLOAD]) { | 736 | if (nfqa[NFQA_PAYLOAD]) { |
658 | if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), | 737 | if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), |
@@ -665,10 +744,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | |||
665 | 744 | ||
666 | nf_reinject(entry, verdict); | 745 | nf_reinject(entry, verdict); |
667 | return 0; | 746 | return 0; |
668 | |||
669 | err_out_unlock: | ||
670 | rcu_read_unlock(); | ||
671 | return err; | ||
672 | } | 747 | } |
673 | 748 | ||
674 | static int | 749 | static int |
@@ -781,14 +856,17 @@ err_out_unlock: | |||
781 | } | 856 | } |
782 | 857 | ||
783 | static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { | 858 | static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { |
784 | [NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp, | 859 | [NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp, |
785 | .attr_count = NFQA_MAX, }, | 860 | .attr_count = NFQA_MAX, }, |
786 | [NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict, | 861 | [NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict, |
787 | .attr_count = NFQA_MAX, | 862 | .attr_count = NFQA_MAX, |
788 | .policy = nfqa_verdict_policy }, | 863 | .policy = nfqa_verdict_policy }, |
789 | [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, | 864 | [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, |
790 | .attr_count = NFQA_CFG_MAX, | 865 | .attr_count = NFQA_CFG_MAX, |
791 | .policy = nfqa_cfg_policy }, | 866 | .policy = nfqa_cfg_policy }, |
867 | [NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch, | ||
868 | .attr_count = NFQA_MAX, | ||
869 | .policy = nfqa_verdict_batch_policy }, | ||
792 | }; | 870 | }; |
793 | 871 | ||
794 | static const struct nfnetlink_subsystem nfqnl_subsys = { | 872 | static const struct nfnetlink_subsystem nfqnl_subsys = { |
@@ -870,7 +948,7 @@ static int seq_show(struct seq_file *s, void *v) | |||
870 | inst->peer_pid, inst->queue_total, | 948 | inst->peer_pid, inst->queue_total, |
871 | inst->copy_mode, inst->copy_range, | 949 | inst->copy_mode, inst->copy_range, |
872 | inst->queue_dropped, inst->queue_user_dropped, | 950 | inst->queue_dropped, inst->queue_user_dropped, |
873 | atomic_read(&inst->id_sequence), 1); | 951 | inst->id_sequence, 1); |
874 | } | 952 | } |
875 | 953 | ||
876 | static const struct seq_operations nfqnl_seq_ops = { | 954 | static const struct seq_operations nfqnl_seq_ops = { |
diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c index 363a99ec0637..4bca15a0c385 100644 --- a/net/netfilter/xt_AUDIT.c +++ b/net/netfilter/xt_AUDIT.c | |||
@@ -163,6 +163,11 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
163 | break; | 163 | break; |
164 | } | 164 | } |
165 | 165 | ||
166 | #ifdef CONFIG_NETWORK_SECMARK | ||
167 | if (skb->secmark) | ||
168 | audit_log_secctx(ab, skb->secmark); | ||
169 | #endif | ||
170 | |||
166 | audit_log_end(ab); | 171 | audit_log_end(ab); |
167 | 172 | ||
168 | errout: | 173 | errout: |