diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2010-04-14 08:44:44 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2010-04-14 12:22:02 +0000 |
commit | 1c6a075cc9e7b129c0d2259ee7514333acdf8246 (patch) | |
tree | 54255de442cecc3897a48369c24b429ded57d087 | |
parent | f4c1523e429f2a7e9d5c83c6d8a41b0a6fdbd2b0 (diff) | |
download | alpine_aports-1c6a075cc9e7b129c0d2259ee7514333acdf8246.tar.bz2 alpine_aports-1c6a075cc9e7b129c0d2259ee7514333acdf8246.tar.xz alpine_aports-1c6a075cc9e7b129c0d2259ee7514333acdf8246.zip |
main/linux-grsec: ipsec improvement patches
backport of net-next to improve ipsec send performance
(cherry picked from commit b1b9aa2787e3f40f38fbf6a258fcbd2b0a19478a)
22 files changed, 2985 insertions, 76 deletions
diff --git a/main/linux-grsec/0001-grsec-revert-conflicting-flow-cache-changes.patch b/main/linux-grsec/0001-grsec-revert-conflicting-flow-cache-changes.patch new file mode 100644 index 0000000000..99571657b1 --- /dev/null +++ b/main/linux-grsec/0001-grsec-revert-conflicting-flow-cache-changes.patch | |||
@@ -0,0 +1,43 @@ | |||
1 | From 5ea3677e1f26dd343ed139d2bdad23ae2f1393db Mon Sep 17 00:00:00 2001 | ||
2 | From: Timo Teras <timo.teras@iki.fi> | ||
3 | Date: Mon, 12 Apr 2010 13:43:01 +0000 | ||
4 | Subject: [PATCH 01/18] grsec: revert conflicting flow cache changes | ||
5 | |||
6 | --- | ||
7 | net/core/flow.c | 6 +++--- | ||
8 | 1 files changed, 3 insertions(+), 3 deletions(-) | ||
9 | |||
10 | diff --git a/net/core/flow.c b/net/core/flow.c | ||
11 | index 5b27992..9601587 100644 | ||
12 | --- a/net/core/flow.c | ||
13 | +++ b/net/core/flow.c | ||
14 | @@ -39,7 +39,7 @@ atomic_t flow_cache_genid = ATOMIC_INIT(0); | ||
15 | |||
16 | static u32 flow_hash_shift; | ||
17 | #define flow_hash_size (1 << flow_hash_shift) | ||
18 | -static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables); | ||
19 | +static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL }; | ||
20 | |||
21 | #define flow_table(cpu) (per_cpu(flow_tables, cpu)) | ||
22 | |||
23 | @@ -52,7 +52,7 @@ struct flow_percpu_info { | ||
24 | u32 hash_rnd; | ||
25 | int count; | ||
26 | }; | ||
27 | -static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info); | ||
28 | +static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info) = { 0 }; | ||
29 | |||
30 | #define flow_hash_rnd_recalc(cpu) \ | ||
31 | (per_cpu(flow_hash_info, cpu).hash_rnd_recalc) | ||
32 | @@ -69,7 +69,7 @@ struct flow_flush_info { | ||
33 | atomic_t cpuleft; | ||
34 | struct completion completion; | ||
35 | }; | ||
36 | -static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklets); | ||
37 | +static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklets) = { NULL }; | ||
38 | |||
39 | #define flow_flush_tasklet(cpu) (&per_cpu(flow_flush_tasklets, cpu)) | ||
40 | |||
41 | -- | ||
42 | 1.7.0.2 | ||
43 | |||
diff --git a/main/linux-grsec/0002-gre-fix-hard-header-destination-address-checking.patch b/main/linux-grsec/0002-gre-fix-hard-header-destination-address-checking.patch new file mode 100644 index 0000000000..36a0ae449a --- /dev/null +++ b/main/linux-grsec/0002-gre-fix-hard-header-destination-address-checking.patch | |||
@@ -0,0 +1,44 @@ | |||
1 | From 9082391046940c410eac3bad065c8701998b5cab Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 3 Mar 2010 04:01:13 +0000 | ||
4 | Subject: [PATCH 02/18] gre: fix hard header destination address checking | ||
5 | |||
6 | ipgre_header() can be called with zero daddr when the gre device is | ||
7 | configured as multipoint tunnel and still has the NOARP flag set (which is | ||
8 | typically cleared by the userspace arp daemon). If the NOARP packets are | ||
9 | not dropped, ipgre_tunnel_xmit() will take rt->rt_gateway (= NBMA IP) and | ||
10 | use that for route look up (and may lead to bogus xfrm acquires). | ||
11 | |||
12 | The multicast address check is removed as sending to multicast group should | ||
13 | be ok. In fact, if gre device has a multicast address as destination | ||
14 | ipgre_header is always called with multicast address. | ||
15 | |||
16 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
17 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
18 | (cherry picked from commit 6d55cb91a0020ac0d78edcad61efd6c8cf5785a3) | ||
19 | --- | ||
20 | net/ipv4/ip_gre.c | 7 ++----- | ||
21 | 1 files changed, 2 insertions(+), 5 deletions(-) | ||
22 | |||
23 | diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c | ||
24 | index 1433338..ac88ce5 100644 | ||
25 | --- a/net/ipv4/ip_gre.c | ||
26 | +++ b/net/ipv4/ip_gre.c | ||
27 | @@ -1137,12 +1137,9 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, | ||
28 | |||
29 | if (saddr) | ||
30 | memcpy(&iph->saddr, saddr, 4); | ||
31 | - | ||
32 | - if (daddr) { | ||
33 | + if (daddr) | ||
34 | memcpy(&iph->daddr, daddr, 4); | ||
35 | - return t->hlen; | ||
36 | - } | ||
37 | - if (iph->daddr && !ipv4_is_multicast(iph->daddr)) | ||
38 | + if (iph->daddr) | ||
39 | return t->hlen; | ||
40 | |||
41 | return -t->hlen; | ||
42 | -- | ||
43 | 1.7.0.2 | ||
44 | |||
diff --git a/main/linux-grsec/0003-ip_gre-include-route-header_len-in-max_headroom-calc.patch b/main/linux-grsec/0003-ip_gre-include-route-header_len-in-max_headroom-calc.patch new file mode 100644 index 0000000000..61d7c9a6c1 --- /dev/null +++ b/main/linux-grsec/0003-ip_gre-include-route-header_len-in-max_headroom-calc.patch | |||
@@ -0,0 +1,39 @@ | |||
1 | From cd0e9d08480e1e0648e17d099ecf50f6fd8714e5 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Sat, 20 Mar 2010 02:27:58 +0000 | ||
4 | Subject: [PATCH 03/18] ip_gre: include route header_len in max_headroom calculation | ||
5 | |||
6 | Taking route's header_len into account, and updating gre device | ||
7 | needed_headroom will give better hints on upper bound of required | ||
8 | headroom. This is useful if the gre traffic is xfrm'ed. | ||
9 | |||
10 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
11 | Acked-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
12 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
13 | (cherry picked from commit 243aad830e8a4cdda261626fbaeddde16b08d04a) | ||
14 | --- | ||
15 | net/ipv4/ip_gre.c | 4 +++- | ||
16 | 1 files changed, 3 insertions(+), 1 deletions(-) | ||
17 | |||
18 | diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c | ||
19 | index ac88ce5..7f1ff73 100644 | ||
20 | --- a/net/ipv4/ip_gre.c | ||
21 | +++ b/net/ipv4/ip_gre.c | ||
22 | @@ -803,11 +803,13 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev | ||
23 | tunnel->err_count = 0; | ||
24 | } | ||
25 | |||
26 | - max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen; | ||
27 | + max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->u.dst.header_len; | ||
28 | |||
29 | if (skb_headroom(skb) < max_headroom || skb_shared(skb)|| | ||
30 | (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { | ||
31 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); | ||
32 | + if (max_headroom > dev->needed_headroom) | ||
33 | + dev->needed_headroom = max_headroom; | ||
34 | if (!new_skb) { | ||
35 | ip_rt_put(rt); | ||
36 | stats->tx_dropped++; | ||
37 | -- | ||
38 | 1.7.0.2 | ||
39 | |||
diff --git a/main/linux-grsec/0004-arp-flush-arp-cache-on-device-change.patch b/main/linux-grsec/0004-arp-flush-arp-cache-on-device-change.patch new file mode 100644 index 0000000000..85161ea3a3 --- /dev/null +++ b/main/linux-grsec/0004-arp-flush-arp-cache-on-device-change.patch | |||
@@ -0,0 +1,29 @@ | |||
1 | From 8a0e3ea4924059a7268446177d6869e3399adbb2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Timo Teras <timo.teras@iki.fi> | ||
3 | Date: Mon, 12 Apr 2010 13:46:45 +0000 | ||
4 | Subject: [PATCH 04/18] arp: flush arp cache on device change | ||
5 | |||
6 | If IFF_NOARP is changed, we must flush the arp cache. | ||
7 | |||
8 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
9 | --- | ||
10 | net/ipv4/arp.c | 3 +++ | ||
11 | 1 files changed, 3 insertions(+), 0 deletions(-) | ||
12 | |||
13 | diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c | ||
14 | index 4e80f33..580bfc3 100644 | ||
15 | --- a/net/ipv4/arp.c | ||
16 | +++ b/net/ipv4/arp.c | ||
17 | @@ -1200,6 +1200,9 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo | ||
18 | neigh_changeaddr(&arp_tbl, dev); | ||
19 | rt_cache_flush(dev_net(dev), 0); | ||
20 | break; | ||
21 | + case NETDEV_CHANGE: | ||
22 | + neigh_changeaddr(&arp_tbl, dev); | ||
23 | + break; | ||
24 | default: | ||
25 | break; | ||
26 | } | ||
27 | -- | ||
28 | 1.7.0.2 | ||
29 | |||
diff --git a/main/linux-grsec/net-git-78f1cd-r8169-fix-broken-register-writes.patch b/main/linux-grsec/0005-r8169-fix-broken-register-writes.patch index f5f72acc4b..bfa8df2900 100644 --- a/main/linux-grsec/net-git-78f1cd-r8169-fix-broken-register-writes.patch +++ b/main/linux-grsec/0005-r8169-fix-broken-register-writes.patch | |||
@@ -1,9 +1,9 @@ | |||
1 | From 78f1cd02457252e1ffbc6caa44a17424a45286b8 Mon Sep 17 00:00:00 2001 | 1 | From 89f350c4ec426b4c1db6ef269546940365d918e1 Mon Sep 17 00:00:00 2001 |
2 | From: Francois Romieu <romieu@fr.zoreil.com> | 2 | From: Francois Romieu <romieu@fr.zoreil.com> |
3 | Date: Sat, 27 Mar 2010 19:35:46 -0700 | 3 | Date: Sat, 27 Mar 2010 19:35:46 -0700 |
4 | Subject: [PATCH] r8169: fix broken register writes | 4 | Subject: [PATCH 05/18] r8169: fix broken register writes |
5 | MIME-Version: 1.0 | 5 | MIME-Version: 1.0 |
6 | Content-Type: text/plain; charset=utf8 | 6 | Content-Type: text/plain; charset=UTF-8 |
7 | Content-Transfer-Encoding: 8bit | 7 | Content-Transfer-Encoding: 8bit |
8 | 8 | ||
9 | This is quite similar to b39fe41f481d20c201012e4483e76c203802dda7 | 9 | This is quite similar to b39fe41f481d20c201012e4483e76c203802dda7 |
@@ -14,19 +14,20 @@ level before being merged into a 64 bit logical entity. | |||
14 | 14 | ||
15 | Credits go to Ben Hutchings <ben@decadent.org.uk> for the MAR | 15 | Credits go to Ben Hutchings <ben@decadent.org.uk> for the MAR |
16 | registers (aka "multicast is broken for ages on ARM) and to | 16 | registers (aka "multicast is broken for ages on ARM) and to |
17 | Timo TerĂƒÂ¤s <timo.teras@iki.fi> for the MAC registers. | 17 | Timo Teräs <timo.teras@iki.fi> for the MAC registers. |
18 | 18 | ||
19 | Signed-off-by: Francois Romieu <romieu@fr.zoreil.com> | 19 | Signed-off-by: Francois Romieu <romieu@fr.zoreil.com> |
20 | Signed-off-by: David S. Miller <davem@davemloft.net> | 20 | Signed-off-by: David S. Miller <davem@davemloft.net> |
21 | (cherry picked from commit 78f1cd02457252e1ffbc6caa44a17424a45286b8) | ||
21 | --- | 22 | --- |
22 | drivers/net/r8169.c | 4 ++-- | 23 | drivers/net/r8169.c | 4 ++-- |
23 | 1 files changed, 2 insertions(+), 2 deletions(-) | 24 | 1 files changed, 2 insertions(+), 2 deletions(-) |
24 | 25 | ||
25 | diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c | 26 | diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c |
26 | index b93fd23..7193afc 100644 | 27 | index 0fe2fc9..24599b5 100644 |
27 | --- a/drivers/net/r8169.c | 28 | --- a/drivers/net/r8169.c |
28 | +++ b/drivers/net/r8169.c | 29 | +++ b/drivers/net/r8169.c |
29 | @@ -2820,8 +2820,8 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) | 30 | @@ -2827,8 +2827,8 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) |
30 | spin_lock_irq(&tp->lock); | 31 | spin_lock_irq(&tp->lock); |
31 | 32 | ||
32 | RTL_W8(Cfg9346, Cfg9346_Unlock); | 33 | RTL_W8(Cfg9346, Cfg9346_Unlock); |
@@ -36,7 +37,7 @@ index b93fd23..7193afc 100644 | |||
36 | RTL_W8(Cfg9346, Cfg9346_Lock); | 37 | RTL_W8(Cfg9346, Cfg9346_Lock); |
37 | 38 | ||
38 | spin_unlock_irq(&tp->lock); | 39 | spin_unlock_irq(&tp->lock); |
39 | @@ -4747,8 +4747,8 @@ static void rtl_set_rx_mode(struct net_device *dev) | 40 | @@ -4795,8 +4795,8 @@ static void rtl_set_rx_mode(struct net_device *dev) |
40 | mc_filter[1] = swab32(data); | 41 | mc_filter[1] = swab32(data); |
41 | } | 42 | } |
42 | 43 | ||
@@ -47,5 +48,5 @@ index b93fd23..7193afc 100644 | |||
47 | RTL_W32(RxConfig, tmp); | 48 | RTL_W32(RxConfig, tmp); |
48 | 49 | ||
49 | -- | 50 | -- |
50 | 1.7.0.3 | 51 | 1.7.0.2 |
51 | 52 | ||
diff --git a/main/linux-grsec/net-git-c0cd88-r8169-offical-fix-for-CVE-2009-4537-overlength-frame-DMAs.patch b/main/linux-grsec/0006-r8169-offical-fix-for-CVE-2009-4537-overlength-frame.patch index 250c85d678..03ea13fa1e 100644 --- a/main/linux-grsec/net-git-c0cd88-r8169-offical-fix-for-CVE-2009-4537-overlength-frame-DMAs.patch +++ b/main/linux-grsec/0006-r8169-offical-fix-for-CVE-2009-4537-overlength-frame.patch | |||
@@ -1,7 +1,7 @@ | |||
1 | From c0cd884af045338476b8e69a61fceb3f34ff22f1 Mon Sep 17 00:00:00 2001 | 1 | From a60cfaf3df9cd0cddbc24695434ed5bfa917d505 Mon Sep 17 00:00:00 2001 |
2 | From: Neil Horman <nhorman@redhat.com> | 2 | From: Neil Horman <nhorman@redhat.com> |
3 | Date: Mon, 29 Mar 2010 13:16:02 -0700 | 3 | Date: Mon, 29 Mar 2010 13:16:02 -0700 |
4 | Subject: [PATCH] r8169: offical fix for CVE-2009-4537 (overlength frame DMAs) | 4 | Subject: [PATCH 06/18] r8169: offical fix for CVE-2009-4537 (overlength frame DMAs) |
5 | 5 | ||
6 | Official patch to fix the r8169 frame length check error. | 6 | Official patch to fix the r8169 frame length check error. |
7 | 7 | ||
@@ -48,15 +48,16 @@ such that performance is restored easily. | |||
48 | 48 | ||
49 | Signed-off-by: Neil Horman <nhorman@redhat.com> | 49 | Signed-off-by: Neil Horman <nhorman@redhat.com> |
50 | Signed-off-by: David S. Miller <davem@davemloft.net> | 50 | Signed-off-by: David S. Miller <davem@davemloft.net> |
51 | (cherry picked from commit c0cd884af045338476b8e69a61fceb3f34ff22f1) | ||
51 | --- | 52 | --- |
52 | drivers/net/r8169.c | 29 ++++++++++++++++++++++++----- | 53 | drivers/net/r8169.c | 29 ++++++++++++++++++++++++----- |
53 | 1 files changed, 24 insertions(+), 5 deletions(-) | 54 | 1 files changed, 24 insertions(+), 5 deletions(-) |
54 | 55 | ||
55 | diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c | 56 | diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c |
56 | index 7193afc..9674005 100644 | 57 | index 24599b5..1484528 100644 |
57 | --- a/drivers/net/r8169.c | 58 | --- a/drivers/net/r8169.c |
58 | +++ b/drivers/net/r8169.c | 59 | +++ b/drivers/net/r8169.c |
59 | @@ -186,7 +186,12 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { | 60 | @@ -186,7 +186,12 @@ static struct pci_device_id rtl8169_pci_tbl[] = { |
60 | 61 | ||
61 | MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); | 62 | MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); |
62 | 63 | ||
@@ -70,7 +71,7 @@ index 7193afc..9674005 100644 | |||
70 | static int use_dac; | 71 | static int use_dac; |
71 | static struct { | 72 | static struct { |
72 | u32 msg_enable; | 73 | u32 msg_enable; |
73 | @@ -3217,9 +3222,13 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) | 74 | @@ -3245,9 +3250,13 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) |
74 | } | 75 | } |
75 | 76 | ||
76 | static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, | 77 | static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, |
@@ -86,7 +87,7 @@ index 7193afc..9674005 100644 | |||
86 | 87 | ||
87 | tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE; | 88 | tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE; |
88 | } | 89 | } |
89 | @@ -3231,7 +3240,17 @@ static int rtl8169_open(struct net_device *dev) | 90 | @@ -3259,7 +3268,17 @@ static int rtl8169_open(struct net_device *dev) |
90 | int retval = -ENOMEM; | 91 | int retval = -ENOMEM; |
91 | 92 | ||
92 | 93 | ||
@@ -105,7 +106,7 @@ index 7193afc..9674005 100644 | |||
105 | 106 | ||
106 | /* | 107 | /* |
107 | * Rx and Tx desscriptors needs 256 bytes alignment. | 108 | * Rx and Tx desscriptors needs 256 bytes alignment. |
108 | @@ -3884,7 +3903,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) | 109 | @@ -3912,7 +3931,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) |
109 | 110 | ||
110 | rtl8169_down(dev); | 111 | rtl8169_down(dev); |
111 | 112 | ||
@@ -115,5 +116,5 @@ index 7193afc..9674005 100644 | |||
115 | ret = rtl8169_init_ring(dev); | 116 | ret = rtl8169_init_ring(dev); |
116 | if (ret < 0) | 117 | if (ret < 0) |
117 | -- | 118 | -- |
118 | 1.7.0.3 | 119 | 1.7.0.2 |
119 | 120 | ||
diff --git a/main/linux-grsec/0007-r8169-Fix-rtl8169_rx_interrupt.patch b/main/linux-grsec/0007-r8169-Fix-rtl8169_rx_interrupt.patch new file mode 100644 index 0000000000..fad2723284 --- /dev/null +++ b/main/linux-grsec/0007-r8169-Fix-rtl8169_rx_interrupt.patch | |||
@@ -0,0 +1,89 @@ | |||
1 | From 26654a966adb674afc30d285f7e79535d03c2492 Mon Sep 17 00:00:00 2001 | ||
2 | From: Eric Dumazet <eric.dumazet@gmail.com> | ||
3 | Date: Wed, 31 Mar 2010 02:08:31 +0000 | ||
4 | Subject: [PATCH 07/18] r8169: Fix rtl8169_rx_interrupt() | ||
5 | |||
6 | In case a reset is performed, rtl8169_rx_interrupt() is called from | ||
7 | process context instead of softirq context. Special care must be taken | ||
8 | to call appropriate network core services (netif_rx() instead of | ||
9 | netif_receive_skb()). VLAN handling also corrected. | ||
10 | |||
11 | Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> | ||
12 | Tested-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> | ||
13 | Diagnosed-by: Oleg Nesterov <oleg@redhat.com> | ||
14 | Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> | ||
15 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
16 | (cherry picked from commit 630b943c182d1aed69f244405131902fbcba7ec6) | ||
17 | --- | ||
18 | drivers/net/r8169.c | 22 +++++++++++++++++----- | ||
19 | 1 files changed, 17 insertions(+), 5 deletions(-) | ||
20 | |||
21 | diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c | ||
22 | index 1484528..bed1d47 100644 | ||
23 | --- a/drivers/net/r8169.c | ||
24 | +++ b/drivers/net/r8169.c | ||
25 | @@ -1047,14 +1047,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev, | ||
26 | } | ||
27 | |||
28 | static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, | ||
29 | - struct sk_buff *skb) | ||
30 | + struct sk_buff *skb, int polling) | ||
31 | { | ||
32 | u32 opts2 = le32_to_cpu(desc->opts2); | ||
33 | struct vlan_group *vlgrp = tp->vlgrp; | ||
34 | int ret; | ||
35 | |||
36 | if (vlgrp && (opts2 & RxVlanTag)) { | ||
37 | - vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff)); | ||
38 | + __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling); | ||
39 | ret = 0; | ||
40 | } else | ||
41 | ret = -1; | ||
42 | @@ -1071,7 +1071,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, | ||
43 | } | ||
44 | |||
45 | static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, | ||
46 | - struct sk_buff *skb) | ||
47 | + struct sk_buff *skb, int polling) | ||
48 | { | ||
49 | return -1; | ||
50 | } | ||
51 | @@ -4480,12 +4480,20 @@ out: | ||
52 | return done; | ||
53 | } | ||
54 | |||
55 | +/* | ||
56 | + * Warning : rtl8169_rx_interrupt() might be called : | ||
57 | + * 1) from NAPI (softirq) context | ||
58 | + * (polling = 1 : we should call netif_receive_skb()) | ||
59 | + * 2) from process context (rtl8169_reset_task()) | ||
60 | + * (polling = 0 : we must call netif_rx() instead) | ||
61 | + */ | ||
62 | static int rtl8169_rx_interrupt(struct net_device *dev, | ||
63 | struct rtl8169_private *tp, | ||
64 | void __iomem *ioaddr, u32 budget) | ||
65 | { | ||
66 | unsigned int cur_rx, rx_left; | ||
67 | unsigned int delta, count; | ||
68 | + int polling = (budget != ~(u32)0) ? 1 : 0; | ||
69 | |||
70 | cur_rx = tp->cur_rx; | ||
71 | rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; | ||
72 | @@ -4550,8 +4558,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev, | ||
73 | skb_put(skb, pkt_size); | ||
74 | skb->protocol = eth_type_trans(skb, dev); | ||
75 | |||
76 | - if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) | ||
77 | - netif_receive_skb(skb); | ||
78 | + if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) { | ||
79 | + if (likely(polling)) | ||
80 | + netif_receive_skb(skb); | ||
81 | + else | ||
82 | + netif_rx(skb); | ||
83 | + } | ||
84 | |||
85 | dev->stats.rx_bytes += pkt_size; | ||
86 | dev->stats.rx_packets++; | ||
87 | -- | ||
88 | 1.7.0.2 | ||
89 | |||
diff --git a/main/linux-grsec/0008-r8169-clean-up-my-printk-uglyness.patch b/main/linux-grsec/0008-r8169-clean-up-my-printk-uglyness.patch new file mode 100644 index 0000000000..dff3fd2112 --- /dev/null +++ b/main/linux-grsec/0008-r8169-clean-up-my-printk-uglyness.patch | |||
@@ -0,0 +1,36 @@ | |||
1 | From d1c9ac562923fa0b1738fceb4c7bafac3ab936ba Mon Sep 17 00:00:00 2001 | ||
2 | From: Neil Horman <nhorman@tuxdriver.com> | ||
3 | Date: Thu, 1 Apr 2010 07:30:07 +0000 | ||
4 | Subject: [PATCH 08/18] r8169: clean up my printk uglyness | ||
5 | |||
6 | Fix formatting on r8169 printk | ||
7 | |||
8 | Brandon Philips noted that I had a spacing issue in my printk for the | ||
9 | last r8169 patch that made it quite ugly. Fix that up and add the PFX | ||
10 | macro to it as well so it looks like the other r8169 printks | ||
11 | |||
12 | Signed-off-by: Neil Horman <nhorman@tuxdriver.com> | ||
13 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
14 | (cherry picked from commit 93f4d91d879acfcb0ba9c2725e3133fcff2dfd1e) | ||
15 | --- | ||
16 | drivers/net/r8169.c | 4 ++-- | ||
17 | 1 files changed, 2 insertions(+), 2 deletions(-) | ||
18 | |||
19 | diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c | ||
20 | index bed1d47..790555e 100644 | ||
21 | --- a/drivers/net/r8169.c | ||
22 | +++ b/drivers/net/r8169.c | ||
23 | @@ -3255,8 +3255,8 @@ static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, | ||
24 | unsigned int max_frame = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; | ||
25 | |||
26 | if (max_frame != 16383) | ||
27 | - printk(KERN_WARNING "WARNING! Changing of MTU on this NIC" | ||
28 | - "May lead to frame reception errors!\n"); | ||
29 | + printk(KERN_WARNING PFX "WARNING! Changing of MTU on this " | ||
30 | + "NIC may lead to frame reception errors!\n"); | ||
31 | |||
32 | tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE; | ||
33 | } | ||
34 | -- | ||
35 | 1.7.0.2 | ||
36 | |||
diff --git a/main/linux-grsec/0009-ipsec-Fix-bogus-bundle-flowi.patch b/main/linux-grsec/0009-ipsec-Fix-bogus-bundle-flowi.patch new file mode 100644 index 0000000000..d4de0e1d58 --- /dev/null +++ b/main/linux-grsec/0009-ipsec-Fix-bogus-bundle-flowi.patch | |||
@@ -0,0 +1,110 @@ | |||
1 | From 21ee14f92ef1b6d4ca965c9b59135f3462919631 Mon Sep 17 00:00:00 2001 | ||
2 | From: Herbert Xu <herbert@gondor.apana.org.au> | ||
3 | Date: Tue, 2 Mar 2010 02:51:56 +0000 | ||
4 | Subject: [PATCH 09/18] ipsec: Fix bogus bundle flowi | ||
5 | |||
6 | When I merged the bundle creation code, I introduced a bogus | ||
7 | flowi value in the bundle. Instead of getting from the caller, | ||
8 | it was instead set to the flow in the route object, which is | ||
9 | totally different. | ||
10 | |||
11 | The end result is that the bundles we created never match, and | ||
12 | we instead end up with an ever growing bundle list. | ||
13 | |||
14 | Thanks to Jamal for find this problem. | ||
15 | |||
16 | Reported-by: Jamal Hadi Salim <hadi@cyberus.ca> | ||
17 | Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
18 | Acked-by: Steffen Klassert <steffen.klassert@secunet.com> | ||
19 | Acked-by: Jamal Hadi Salim <hadi@cyberus.ca> | ||
20 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
21 | (cherry picked from commit 87c1e12b5eeb7b30b4b41291bef8e0b41fc3dde9) | ||
22 | --- | ||
23 | include/net/xfrm.h | 3 ++- | ||
24 | net/ipv4/xfrm4_policy.c | 5 +++-- | ||
25 | net/ipv6/xfrm6_policy.c | 3 ++- | ||
26 | net/xfrm/xfrm_policy.c | 7 ++++--- | ||
27 | 4 files changed, 11 insertions(+), 7 deletions(-) | ||
28 | |||
29 | diff --git a/include/net/xfrm.h b/include/net/xfrm.h | ||
30 | index 223e90a..6960be2 100644 | ||
31 | --- a/include/net/xfrm.h | ||
32 | +++ b/include/net/xfrm.h | ||
33 | @@ -273,7 +273,8 @@ struct xfrm_policy_afinfo { | ||
34 | struct dst_entry *dst, | ||
35 | int nfheader_len); | ||
36 | int (*fill_dst)(struct xfrm_dst *xdst, | ||
37 | - struct net_device *dev); | ||
38 | + struct net_device *dev, | ||
39 | + struct flowi *fl); | ||
40 | }; | ||
41 | |||
42 | extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); | ||
43 | diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c | ||
44 | index 74fb2eb..7009886 100644 | ||
45 | --- a/net/ipv4/xfrm4_policy.c | ||
46 | +++ b/net/ipv4/xfrm4_policy.c | ||
47 | @@ -92,11 +92,12 @@ static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | -static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | ||
52 | +static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | ||
53 | + struct flowi *fl) | ||
54 | { | ||
55 | struct rtable *rt = (struct rtable *)xdst->route; | ||
56 | |||
57 | - xdst->u.rt.fl = rt->fl; | ||
58 | + xdst->u.rt.fl = *fl; | ||
59 | |||
60 | xdst->u.dst.dev = dev; | ||
61 | dev_hold(dev); | ||
62 | diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c | ||
63 | index 8ec3d45..3f89ab7 100644 | ||
64 | --- a/net/ipv6/xfrm6_policy.c | ||
65 | +++ b/net/ipv6/xfrm6_policy.c | ||
66 | @@ -117,7 +117,8 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | -static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | ||
71 | +static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | ||
72 | + struct flowi *fl) | ||
73 | { | ||
74 | struct rt6_info *rt = (struct rt6_info*)xdst->route; | ||
75 | |||
76 | diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c | ||
77 | index cb81ca3..d75047c 100644 | ||
78 | --- a/net/xfrm/xfrm_policy.c | ||
79 | +++ b/net/xfrm/xfrm_policy.c | ||
80 | @@ -1341,7 +1341,8 @@ static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
81 | return err; | ||
82 | } | ||
83 | |||
84 | -static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | ||
85 | +static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | ||
86 | + struct flowi *fl) | ||
87 | { | ||
88 | struct xfrm_policy_afinfo *afinfo = | ||
89 | xfrm_policy_get_afinfo(xdst->u.dst.ops->family); | ||
90 | @@ -1350,7 +1351,7 @@ static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | ||
91 | if (!afinfo) | ||
92 | return -EINVAL; | ||
93 | |||
94 | - err = afinfo->fill_dst(xdst, dev); | ||
95 | + err = afinfo->fill_dst(xdst, dev, fl); | ||
96 | |||
97 | xfrm_policy_put_afinfo(afinfo); | ||
98 | |||
99 | @@ -1454,7 +1455,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | ||
100 | for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { | ||
101 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev; | ||
102 | |||
103 | - err = xfrm_fill_dst(xdst, dev); | ||
104 | + err = xfrm_fill_dst(xdst, dev, fl); | ||
105 | if (err) | ||
106 | goto free_dst; | ||
107 | |||
108 | -- | ||
109 | 1.7.0.2 | ||
110 | |||
diff --git a/main/linux-grsec/0010-xfrm-Remove-xfrm_state_genid.patch b/main/linux-grsec/0010-xfrm-Remove-xfrm_state_genid.patch new file mode 100644 index 0000000000..8cfffd7398 --- /dev/null +++ b/main/linux-grsec/0010-xfrm-Remove-xfrm_state_genid.patch | |||
@@ -0,0 +1,54 @@ | |||
1 | From f2c59932757a06851bb740dc757ce2ba1961fc08 Mon Sep 17 00:00:00 2001 | ||
2 | From: Herbert Xu <herbert@gondor.apana.org.au> | ||
3 | Date: Wed, 31 Mar 2010 01:19:49 +0000 | ||
4 | Subject: [PATCH 10/18] xfrm: Remove xfrm_state_genid | ||
5 | MIME-Version: 1.0 | ||
6 | Content-Type: text/plain; charset=UTF-8 | ||
7 | Content-Transfer-Encoding: 8bit | ||
8 | |||
9 | The xfrm state genid only needs to be matched against the copy | ||
10 | saved in xfrm_dst. So we don't need a global genid at all. In | ||
11 | fact, we don't even need to initialise it. | ||
12 | |||
13 | Based on observation by Timo Teräs. | ||
14 | |||
15 | Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
16 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
17 | (cherry picked from commit 34996cb91dd72f0b0456d8fd3fef4aaee62232f2) | ||
18 | --- | ||
19 | net/xfrm/xfrm_state.c | 5 +---- | ||
20 | 1 files changed, 1 insertions(+), 4 deletions(-) | ||
21 | |||
22 | diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c | ||
23 | index f2f7c63..8ee733f 100644 | ||
24 | --- a/net/xfrm/xfrm_state.c | ||
25 | +++ b/net/xfrm/xfrm_state.c | ||
26 | @@ -34,7 +34,6 @@ | ||
27 | static DEFINE_SPINLOCK(xfrm_state_lock); | ||
28 | |||
29 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | ||
30 | -static unsigned int xfrm_state_genid; | ||
31 | |||
32 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | ||
33 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | ||
34 | @@ -903,8 +902,6 @@ static void __xfrm_state_insert(struct xfrm_state *x) | ||
35 | struct net *net = xs_net(x); | ||
36 | unsigned int h; | ||
37 | |||
38 | - x->genid = ++xfrm_state_genid; | ||
39 | - | ||
40 | list_add(&x->km.all, &net->xfrm.state_all); | ||
41 | |||
42 | h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, | ||
43 | @@ -948,7 +945,7 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | ||
44 | x->props.reqid == reqid && | ||
45 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | ||
46 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | ||
47 | - x->genid = xfrm_state_genid; | ||
48 | + x->genid++; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | -- | ||
53 | 1.7.0.2 | ||
54 | |||
diff --git a/main/linux-grsec/0011-xfrm_user-verify-policy-direction-at-XFRM_MSG_POLEXP.patch b/main/linux-grsec/0011-xfrm_user-verify-policy-direction-at-XFRM_MSG_POLEXP.patch new file mode 100644 index 0000000000..ae2a0f9100 --- /dev/null +++ b/main/linux-grsec/0011-xfrm_user-verify-policy-direction-at-XFRM_MSG_POLEXP.patch | |||
@@ -0,0 +1,35 @@ | |||
1 | From 5b3e87bccb0e48f2f8b78695e949c015a3695f8e Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 31 Mar 2010 00:17:04 +0000 | ||
4 | Subject: [PATCH 11/18] xfrm_user: verify policy direction at XFRM_MSG_POLEXPIRE handler | ||
5 | |||
6 | Add missing check for policy direction verification. This is | ||
7 | especially important since without this xfrm_user may end up | ||
8 | deleting per-socket policy which is not allowed. | ||
9 | |||
10 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
11 | Acked-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
12 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
13 | (cherry picked from commit c8bf4d04f970fafb3430d332533e1cf103f2a018) | ||
14 | --- | ||
15 | net/xfrm/xfrm_user.c | 4 ++++ | ||
16 | 1 files changed, 4 insertions(+), 0 deletions(-) | ||
17 | |||
18 | diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c | ||
19 | index b95a2d6..d1e9ee3 100644 | ||
20 | --- a/net/xfrm/xfrm_user.c | ||
21 | +++ b/net/xfrm/xfrm_user.c | ||
22 | @@ -1589,6 +1589,10 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
23 | if (err) | ||
24 | return err; | ||
25 | |||
26 | + err = verify_policy_dir(p->dir); | ||
27 | + if (err) | ||
28 | + return err; | ||
29 | + | ||
30 | if (p->index) | ||
31 | xp = xfrm_policy_byid(net, type, p->dir, p->index, 0, &err); | ||
32 | else { | ||
33 | -- | ||
34 | 1.7.0.2 | ||
35 | |||
diff --git a/main/linux-grsec/0012-xfrm-remove-policy-lock-when-accessing-policy-walk.d.patch b/main/linux-grsec/0012-xfrm-remove-policy-lock-when-accessing-policy-walk.d.patch new file mode 100644 index 0000000000..222caaddfd --- /dev/null +++ b/main/linux-grsec/0012-xfrm-remove-policy-lock-when-accessing-policy-walk.d.patch | |||
@@ -0,0 +1,105 @@ | |||
1 | From 7a400eb025dd53883c3560d0fdb069542f7ad3db Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 31 Mar 2010 00:17:05 +0000 | ||
4 | Subject: [PATCH 12/18] xfrm: remove policy lock when accessing policy->walk.dead | ||
5 | |||
6 | All of the code considers ->dead as a hint that the cached policy | ||
7 | needs to get refreshed. The read side can just drop the read lock | ||
8 | without any side effects. | ||
9 | |||
10 | The write side needs to make sure that it's written only exactly | ||
11 | once. Only possible race is at xfrm_policy_kill(). This is fixed | ||
12 | by checking result of __xfrm_policy_unlink() when needed. It will | ||
13 | always succeed if the policy object is looked up from the hash | ||
14 | list (so some checks are removed), but it needs to be checked if | ||
15 | we are trying to unlink policy via a reference (appropriate | ||
16 | checks added). | ||
17 | |||
18 | Since policy->walk.dead is written exactly once, it no longer | ||
19 | needs to be protected with a write lock. | ||
20 | |||
21 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
22 | Acked-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
23 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
24 | (backported from commit ea2dea9dacc256fe927857feb423872051642ae7) | ||
25 | --- | ||
26 | net/xfrm/xfrm_policy.c | 20 +++++--------------- | ||
27 | net/xfrm/xfrm_user.c | 6 +----- | ||
28 | 2 files changed, 6 insertions(+), 20 deletions(-) | ||
29 | |||
30 | diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c | ||
31 | index d75047c..110184f 100644 | ||
32 | --- a/net/xfrm/xfrm_policy.c | ||
33 | +++ b/net/xfrm/xfrm_policy.c | ||
34 | @@ -156,7 +156,7 @@ static void xfrm_policy_timer(unsigned long data) | ||
35 | |||
36 | read_lock(&xp->lock); | ||
37 | |||
38 | - if (xp->walk.dead) | ||
39 | + if (unlikely(xp->walk.dead)) | ||
40 | goto out; | ||
41 | |||
42 | dir = xfrm_policy_id2dir(xp->index); | ||
43 | @@ -297,17 +297,7 @@ static DECLARE_WORK(xfrm_policy_gc_work, xfrm_policy_gc_task); | ||
44 | |||
45 | static void xfrm_policy_kill(struct xfrm_policy *policy) | ||
46 | { | ||
47 | - int dead; | ||
48 | - | ||
49 | - write_lock_bh(&policy->lock); | ||
50 | - dead = policy->walk.dead; | ||
51 | policy->walk.dead = 1; | ||
52 | - write_unlock_bh(&policy->lock); | ||
53 | - | ||
54 | - if (unlikely(dead)) { | ||
55 | - WARN_ON(1); | ||
56 | - return; | ||
57 | - } | ||
58 | |||
59 | spin_lock_bh(&xfrm_policy_gc_lock); | ||
60 | hlist_add_head(&policy->bydst, &xfrm_policy_gc_list); | ||
61 | @@ -1115,6 +1105,9 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | ||
62 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | ||
63 | } | ||
64 | if (old_pol) | ||
65 | + /* Unlinking succeeds always. This is the only function | ||
66 | + * allowed to delete or replace socket policy. | ||
67 | + */ | ||
68 | __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); | ||
69 | write_unlock_bh(&xfrm_policy_lock); | ||
70 | |||
71 | @@ -1705,11 +1698,8 @@ restart: | ||
72 | goto error; | ||
73 | } | ||
74 | |||
75 | - for (pi = 0; pi < npols; pi++) { | ||
76 | - read_lock_bh(&pols[pi]->lock); | ||
77 | + for (pi = 0; pi < npols; pi++) | ||
78 | pol_dead |= pols[pi]->walk.dead; | ||
79 | - read_unlock_bh(&pols[pi]->lock); | ||
80 | - } | ||
81 | |||
82 | write_lock_bh(&policy->lock); | ||
83 | if (unlikely(pol_dead || stale_bundle(dst))) { | ||
84 | diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c | ||
85 | index d1e9ee3..f9c56e9 100644 | ||
86 | --- a/net/xfrm/xfrm_user.c | ||
87 | +++ b/net/xfrm/xfrm_user.c | ||
88 | @@ -1617,13 +1617,9 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
89 | if (xp == NULL) | ||
90 | return -ENOENT; | ||
91 | |||
92 | - read_lock(&xp->lock); | ||
93 | - if (xp->walk.dead) { | ||
94 | - read_unlock(&xp->lock); | ||
95 | + if (unlikely(xp->walk.dead)) | ||
96 | goto out; | ||
97 | - } | ||
98 | |||
99 | - read_unlock(&xp->lock); | ||
100 | err = 0; | ||
101 | if (up->hard) { | ||
102 | uid_t loginuid = NETLINK_CB(skb).loginuid; | ||
103 | -- | ||
104 | 1.7.0.2 | ||
105 | |||
diff --git a/main/linux-grsec/0013-flow-structurize-flow-cache.patch b/main/linux-grsec/0013-flow-structurize-flow-cache.patch new file mode 100644 index 0000000000..68fa753a2c --- /dev/null +++ b/main/linux-grsec/0013-flow-structurize-flow-cache.patch | |||
@@ -0,0 +1,395 @@ | |||
1 | From 884f6e44f0b405c06bd234b14cc228482291bb38 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 31 Mar 2010 00:17:06 +0000 | ||
4 | Subject: [PATCH 13/18] flow: structurize flow cache | ||
5 | |||
6 | Group all per-cpu data to one structure instead of having many | ||
7 | globals. Also prepare the internals so that we can have multiple | ||
8 | instances of the flow cache if needed. | ||
9 | |||
10 | Only the kmem_cache is left as a global as all flow caches share | ||
11 | the same element size, and benefit from using a common cache. | ||
12 | |||
13 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
14 | Acked-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
15 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
16 | (cherry picked from commit d7997fe1f4584da12e9c29fb682c18e9bdc13b73) | ||
17 | --- | ||
18 | net/core/flow.c | 223 +++++++++++++++++++++++++++++-------------------------- | ||
19 | 1 files changed, 119 insertions(+), 104 deletions(-) | ||
20 | |||
21 | diff --git a/net/core/flow.c b/net/core/flow.c | ||
22 | index 9601587..1d27ca6 100644 | ||
23 | --- a/net/core/flow.c | ||
24 | +++ b/net/core/flow.c | ||
25 | @@ -35,104 +35,105 @@ struct flow_cache_entry { | ||
26 | atomic_t *object_ref; | ||
27 | }; | ||
28 | |||
29 | -atomic_t flow_cache_genid = ATOMIC_INIT(0); | ||
30 | - | ||
31 | -static u32 flow_hash_shift; | ||
32 | -#define flow_hash_size (1 << flow_hash_shift) | ||
33 | -static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL }; | ||
34 | - | ||
35 | -#define flow_table(cpu) (per_cpu(flow_tables, cpu)) | ||
36 | - | ||
37 | -static struct kmem_cache *flow_cachep __read_mostly; | ||
38 | - | ||
39 | -static int flow_lwm, flow_hwm; | ||
40 | - | ||
41 | -struct flow_percpu_info { | ||
42 | - int hash_rnd_recalc; | ||
43 | - u32 hash_rnd; | ||
44 | - int count; | ||
45 | +struct flow_cache_percpu { | ||
46 | + struct flow_cache_entry ** hash_table; | ||
47 | + int hash_count; | ||
48 | + u32 hash_rnd; | ||
49 | + int hash_rnd_recalc; | ||
50 | + struct tasklet_struct flush_tasklet; | ||
51 | }; | ||
52 | -static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info) = { 0 }; | ||
53 | - | ||
54 | -#define flow_hash_rnd_recalc(cpu) \ | ||
55 | - (per_cpu(flow_hash_info, cpu).hash_rnd_recalc) | ||
56 | -#define flow_hash_rnd(cpu) \ | ||
57 | - (per_cpu(flow_hash_info, cpu).hash_rnd) | ||
58 | -#define flow_count(cpu) \ | ||
59 | - (per_cpu(flow_hash_info, cpu).count) | ||
60 | - | ||
61 | -static struct timer_list flow_hash_rnd_timer; | ||
62 | - | ||
63 | -#define FLOW_HASH_RND_PERIOD (10 * 60 * HZ) | ||
64 | |||
65 | struct flow_flush_info { | ||
66 | - atomic_t cpuleft; | ||
67 | - struct completion completion; | ||
68 | + struct flow_cache * cache; | ||
69 | + atomic_t cpuleft; | ||
70 | + struct completion completion; | ||
71 | }; | ||
72 | -static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklets) = { NULL }; | ||
73 | |||
74 | -#define flow_flush_tasklet(cpu) (&per_cpu(flow_flush_tasklets, cpu)) | ||
75 | +struct flow_cache { | ||
76 | + u32 hash_shift; | ||
77 | + unsigned long order; | ||
78 | + struct flow_cache_percpu * percpu; | ||
79 | + struct notifier_block hotcpu_notifier; | ||
80 | + int low_watermark; | ||
81 | + int high_watermark; | ||
82 | + struct timer_list rnd_timer; | ||
83 | +}; | ||
84 | + | ||
85 | +atomic_t flow_cache_genid = ATOMIC_INIT(0); | ||
86 | +static struct flow_cache flow_cache_global; | ||
87 | +static struct kmem_cache *flow_cachep; | ||
88 | + | ||
89 | +#define flow_cache_hash_size(cache) (1 << (cache)->hash_shift) | ||
90 | +#define FLOW_HASH_RND_PERIOD (10 * 60 * HZ) | ||
91 | |||
92 | static void flow_cache_new_hashrnd(unsigned long arg) | ||
93 | { | ||
94 | + struct flow_cache *fc = (void *) arg; | ||
95 | int i; | ||
96 | |||
97 | for_each_possible_cpu(i) | ||
98 | - flow_hash_rnd_recalc(i) = 1; | ||
99 | + per_cpu_ptr(fc->percpu, i)->hash_rnd_recalc = 1; | ||
100 | |||
101 | - flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; | ||
102 | - add_timer(&flow_hash_rnd_timer); | ||
103 | + fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; | ||
104 | + add_timer(&fc->rnd_timer); | ||
105 | } | ||
106 | |||
107 | -static void flow_entry_kill(int cpu, struct flow_cache_entry *fle) | ||
108 | +static void flow_entry_kill(struct flow_cache *fc, | ||
109 | + struct flow_cache_percpu *fcp, | ||
110 | + struct flow_cache_entry *fle) | ||
111 | { | ||
112 | if (fle->object) | ||
113 | atomic_dec(fle->object_ref); | ||
114 | kmem_cache_free(flow_cachep, fle); | ||
115 | - flow_count(cpu)--; | ||
116 | + fcp->hash_count--; | ||
117 | } | ||
118 | |||
119 | -static void __flow_cache_shrink(int cpu, int shrink_to) | ||
120 | +static void __flow_cache_shrink(struct flow_cache *fc, | ||
121 | + struct flow_cache_percpu *fcp, | ||
122 | + int shrink_to) | ||
123 | { | ||
124 | struct flow_cache_entry *fle, **flp; | ||
125 | int i; | ||
126 | |||
127 | - for (i = 0; i < flow_hash_size; i++) { | ||
128 | + for (i = 0; i < flow_cache_hash_size(fc); i++) { | ||
129 | int k = 0; | ||
130 | |||
131 | - flp = &flow_table(cpu)[i]; | ||
132 | + flp = &fcp->hash_table[i]; | ||
133 | while ((fle = *flp) != NULL && k < shrink_to) { | ||
134 | k++; | ||
135 | flp = &fle->next; | ||
136 | } | ||
137 | while ((fle = *flp) != NULL) { | ||
138 | *flp = fle->next; | ||
139 | - flow_entry_kill(cpu, fle); | ||
140 | + flow_entry_kill(fc, fcp, fle); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | -static void flow_cache_shrink(int cpu) | ||
146 | +static void flow_cache_shrink(struct flow_cache *fc, | ||
147 | + struct flow_cache_percpu *fcp) | ||
148 | { | ||
149 | - int shrink_to = flow_lwm / flow_hash_size; | ||
150 | + int shrink_to = fc->low_watermark / flow_cache_hash_size(fc); | ||
151 | |||
152 | - __flow_cache_shrink(cpu, shrink_to); | ||
153 | + __flow_cache_shrink(fc, fcp, shrink_to); | ||
154 | } | ||
155 | |||
156 | -static void flow_new_hash_rnd(int cpu) | ||
157 | +static void flow_new_hash_rnd(struct flow_cache *fc, | ||
158 | + struct flow_cache_percpu *fcp) | ||
159 | { | ||
160 | - get_random_bytes(&flow_hash_rnd(cpu), sizeof(u32)); | ||
161 | - flow_hash_rnd_recalc(cpu) = 0; | ||
162 | - | ||
163 | - __flow_cache_shrink(cpu, 0); | ||
164 | + get_random_bytes(&fcp->hash_rnd, sizeof(u32)); | ||
165 | + fcp->hash_rnd_recalc = 0; | ||
166 | + __flow_cache_shrink(fc, fcp, 0); | ||
167 | } | ||
168 | |||
169 | -static u32 flow_hash_code(struct flowi *key, int cpu) | ||
170 | +static u32 flow_hash_code(struct flow_cache *fc, | ||
171 | + struct flow_cache_percpu *fcp, | ||
172 | + struct flowi *key) | ||
173 | { | ||
174 | u32 *k = (u32 *) key; | ||
175 | |||
176 | - return (jhash2(k, (sizeof(*key) / sizeof(u32)), flow_hash_rnd(cpu)) & | ||
177 | - (flow_hash_size - 1)); | ||
178 | + return (jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd) | ||
179 | + & (flow_cache_hash_size(fc) - 1)); | ||
180 | } | ||
181 | |||
182 | #if (BITS_PER_LONG == 64) | ||
183 | @@ -168,24 +169,25 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2) | ||
184 | void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
185 | flow_resolve_t resolver) | ||
186 | { | ||
187 | + struct flow_cache *fc = &flow_cache_global; | ||
188 | + struct flow_cache_percpu *fcp; | ||
189 | struct flow_cache_entry *fle, **head; | ||
190 | unsigned int hash; | ||
191 | - int cpu; | ||
192 | |||
193 | local_bh_disable(); | ||
194 | - cpu = smp_processor_id(); | ||
195 | + fcp = per_cpu_ptr(fc->percpu, smp_processor_id()); | ||
196 | |||
197 | fle = NULL; | ||
198 | /* Packet really early in init? Making flow_cache_init a | ||
199 | * pre-smp initcall would solve this. --RR */ | ||
200 | - if (!flow_table(cpu)) | ||
201 | + if (!fcp->hash_table) | ||
202 | goto nocache; | ||
203 | |||
204 | - if (flow_hash_rnd_recalc(cpu)) | ||
205 | - flow_new_hash_rnd(cpu); | ||
206 | - hash = flow_hash_code(key, cpu); | ||
207 | + if (fcp->hash_rnd_recalc) | ||
208 | + flow_new_hash_rnd(fc, fcp); | ||
209 | + hash = flow_hash_code(fc, fcp, key); | ||
210 | |||
211 | - head = &flow_table(cpu)[hash]; | ||
212 | + head = &fcp->hash_table[hash]; | ||
213 | for (fle = *head; fle; fle = fle->next) { | ||
214 | if (fle->family == family && | ||
215 | fle->dir == dir && | ||
216 | @@ -204,8 +206,8 @@ void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
217 | } | ||
218 | |||
219 | if (!fle) { | ||
220 | - if (flow_count(cpu) > flow_hwm) | ||
221 | - flow_cache_shrink(cpu); | ||
222 | + if (fcp->hash_count > fc->high_watermark) | ||
223 | + flow_cache_shrink(fc, fcp); | ||
224 | |||
225 | fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); | ||
226 | if (fle) { | ||
227 | @@ -215,7 +217,7 @@ void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
228 | fle->dir = dir; | ||
229 | memcpy(&fle->key, key, sizeof(*key)); | ||
230 | fle->object = NULL; | ||
231 | - flow_count(cpu)++; | ||
232 | + fcp->hash_count++; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | @@ -249,14 +251,15 @@ nocache: | ||
237 | static void flow_cache_flush_tasklet(unsigned long data) | ||
238 | { | ||
239 | struct flow_flush_info *info = (void *)data; | ||
240 | + struct flow_cache *fc = info->cache; | ||
241 | + struct flow_cache_percpu *fcp; | ||
242 | int i; | ||
243 | - int cpu; | ||
244 | |||
245 | - cpu = smp_processor_id(); | ||
246 | - for (i = 0; i < flow_hash_size; i++) { | ||
247 | + fcp = per_cpu_ptr(fc->percpu, smp_processor_id()); | ||
248 | + for (i = 0; i < flow_cache_hash_size(fc); i++) { | ||
249 | struct flow_cache_entry *fle; | ||
250 | |||
251 | - fle = flow_table(cpu)[i]; | ||
252 | + fle = fcp->hash_table[i]; | ||
253 | for (; fle; fle = fle->next) { | ||
254 | unsigned genid = atomic_read(&flow_cache_genid); | ||
255 | |||
256 | @@ -272,7 +275,6 @@ static void flow_cache_flush_tasklet(unsigned long data) | ||
257 | complete(&info->completion); | ||
258 | } | ||
259 | |||
260 | -static void flow_cache_flush_per_cpu(void *) __attribute__((__unused__)); | ||
261 | static void flow_cache_flush_per_cpu(void *data) | ||
262 | { | ||
263 | struct flow_flush_info *info = data; | ||
264 | @@ -280,8 +282,7 @@ static void flow_cache_flush_per_cpu(void *data) | ||
265 | struct tasklet_struct *tasklet; | ||
266 | |||
267 | cpu = smp_processor_id(); | ||
268 | - | ||
269 | - tasklet = flow_flush_tasklet(cpu); | ||
270 | + tasklet = &per_cpu_ptr(info->cache->percpu, cpu)->flush_tasklet; | ||
271 | tasklet->data = (unsigned long)info; | ||
272 | tasklet_schedule(tasklet); | ||
273 | } | ||
274 | @@ -294,6 +295,7 @@ void flow_cache_flush(void) | ||
275 | /* Don't want cpus going down or up during this. */ | ||
276 | get_online_cpus(); | ||
277 | mutex_lock(&flow_flush_sem); | ||
278 | + info.cache = &flow_cache_global; | ||
279 | atomic_set(&info.cpuleft, num_online_cpus()); | ||
280 | init_completion(&info.completion); | ||
281 | |||
282 | @@ -307,62 +309,75 @@ void flow_cache_flush(void) | ||
283 | put_online_cpus(); | ||
284 | } | ||
285 | |||
286 | -static void __init flow_cache_cpu_prepare(int cpu) | ||
287 | +static void __init flow_cache_cpu_prepare(struct flow_cache *fc, | ||
288 | + struct flow_cache_percpu *fcp) | ||
289 | { | ||
290 | - struct tasklet_struct *tasklet; | ||
291 | - unsigned long order; | ||
292 | - | ||
293 | - for (order = 0; | ||
294 | - (PAGE_SIZE << order) < | ||
295 | - (sizeof(struct flow_cache_entry *)*flow_hash_size); | ||
296 | - order++) | ||
297 | - /* NOTHING */; | ||
298 | - | ||
299 | - flow_table(cpu) = (struct flow_cache_entry **) | ||
300 | - __get_free_pages(GFP_KERNEL|__GFP_ZERO, order); | ||
301 | - if (!flow_table(cpu)) | ||
302 | - panic("NET: failed to allocate flow cache order %lu\n", order); | ||
303 | - | ||
304 | - flow_hash_rnd_recalc(cpu) = 1; | ||
305 | - flow_count(cpu) = 0; | ||
306 | - | ||
307 | - tasklet = flow_flush_tasklet(cpu); | ||
308 | - tasklet_init(tasklet, flow_cache_flush_tasklet, 0); | ||
309 | + fcp->hash_table = (struct flow_cache_entry **) | ||
310 | + __get_free_pages(GFP_KERNEL|__GFP_ZERO, fc->order); | ||
311 | + if (!fcp->hash_table) | ||
312 | + panic("NET: failed to allocate flow cache order %lu\n", fc->order); | ||
313 | + | ||
314 | + fcp->hash_rnd_recalc = 1; | ||
315 | + fcp->hash_count = 0; | ||
316 | + tasklet_init(&fcp->flush_tasklet, flow_cache_flush_tasklet, 0); | ||
317 | } | ||
318 | |||
319 | static int flow_cache_cpu(struct notifier_block *nfb, | ||
320 | unsigned long action, | ||
321 | void *hcpu) | ||
322 | { | ||
323 | + struct flow_cache *fc = container_of(nfb, struct flow_cache, hotcpu_notifier); | ||
324 | + int cpu = (unsigned long) hcpu; | ||
325 | + struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu); | ||
326 | + | ||
327 | if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) | ||
328 | - __flow_cache_shrink((unsigned long)hcpu, 0); | ||
329 | + __flow_cache_shrink(fc, fcp, 0); | ||
330 | return NOTIFY_OK; | ||
331 | } | ||
332 | |||
333 | -static int __init flow_cache_init(void) | ||
334 | +static int flow_cache_init(struct flow_cache *fc) | ||
335 | { | ||
336 | + unsigned long order; | ||
337 | int i; | ||
338 | |||
339 | - flow_cachep = kmem_cache_create("flow_cache", | ||
340 | - sizeof(struct flow_cache_entry), | ||
341 | - 0, SLAB_PANIC, | ||
342 | - NULL); | ||
343 | - flow_hash_shift = 10; | ||
344 | - flow_lwm = 2 * flow_hash_size; | ||
345 | - flow_hwm = 4 * flow_hash_size; | ||
346 | + fc->hash_shift = 10; | ||
347 | + fc->low_watermark = 2 * flow_cache_hash_size(fc); | ||
348 | + fc->high_watermark = 4 * flow_cache_hash_size(fc); | ||
349 | + | ||
350 | + for (order = 0; | ||
351 | + (PAGE_SIZE << order) < | ||
352 | + (sizeof(struct flow_cache_entry *)*flow_cache_hash_size(fc)); | ||
353 | + order++) | ||
354 | + /* NOTHING */; | ||
355 | + fc->order = order; | ||
356 | + fc->percpu = alloc_percpu(struct flow_cache_percpu); | ||
357 | |||
358 | - setup_timer(&flow_hash_rnd_timer, flow_cache_new_hashrnd, 0); | ||
359 | - flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; | ||
360 | - add_timer(&flow_hash_rnd_timer); | ||
361 | + setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd, | ||
362 | + (unsigned long) fc); | ||
363 | + fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; | ||
364 | + add_timer(&fc->rnd_timer); | ||
365 | |||
366 | for_each_possible_cpu(i) | ||
367 | - flow_cache_cpu_prepare(i); | ||
368 | + flow_cache_cpu_prepare(fc, per_cpu_ptr(fc->percpu, i)); | ||
369 | + | ||
370 | + fc->hotcpu_notifier = (struct notifier_block){ | ||
371 | + .notifier_call = flow_cache_cpu, | ||
372 | + }; | ||
373 | + register_hotcpu_notifier(&fc->hotcpu_notifier); | ||
374 | |||
375 | - hotcpu_notifier(flow_cache_cpu, 0); | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | -module_init(flow_cache_init); | ||
380 | +static int __init flow_cache_init_global(void) | ||
381 | +{ | ||
382 | + flow_cachep = kmem_cache_create("flow_cache", | ||
383 | + sizeof(struct flow_cache_entry), | ||
384 | + 0, SLAB_PANIC, NULL); | ||
385 | + | ||
386 | + return flow_cache_init(&flow_cache_global); | ||
387 | +} | ||
388 | + | ||
389 | +module_init(flow_cache_init_global); | ||
390 | |||
391 | EXPORT_SYMBOL(flow_cache_genid); | ||
392 | EXPORT_SYMBOL(flow_cache_lookup); | ||
393 | -- | ||
394 | 1.7.0.2 | ||
395 | |||
diff --git a/main/linux-grsec/0014-flow-virtualize-flow-cache-entry-methods.patch b/main/linux-grsec/0014-flow-virtualize-flow-cache-entry-methods.patch new file mode 100644 index 0000000000..5c4a9ea594 --- /dev/null +++ b/main/linux-grsec/0014-flow-virtualize-flow-cache-entry-methods.patch | |||
@@ -0,0 +1,513 @@ | |||
1 | From d56cd1c538e5448fe43acc69991aa842f382a622 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 7 Apr 2010 00:30:04 +0000 | ||
4 | Subject: [PATCH 14/18] flow: virtualize flow cache entry methods | ||
5 | |||
6 | This allows to validate the cached object before returning it. | ||
7 | It also allows to destruct object properly, if the last reference | ||
8 | was held in flow cache. This is also a prepartion for caching | ||
9 | bundles in the flow cache. | ||
10 | |||
11 | In return for virtualizing the methods, we save on: | ||
12 | - not having to regenerate the whole flow cache on policy removal: | ||
13 | each flow matching a killed policy gets refreshed as the getter | ||
14 | function notices it smartly. | ||
15 | - we do not have to call flow_cache_flush from policy gc, since the | ||
16 | flow cache now properly deletes the object if it had any references | ||
17 | |||
18 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
19 | Acked-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
20 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
21 | (backported from commit fe1a5f031e76bd8761a7803d75b95ee96e84a574) | ||
22 | --- | ||
23 | include/net/flow.h | 23 +++++++-- | ||
24 | include/net/xfrm.h | 3 + | ||
25 | net/core/flow.c | 128 +++++++++++++++++++++++++---------------------- | ||
26 | net/xfrm/xfrm_policy.c | 111 ++++++++++++++++++++++++++++-------------- | ||
27 | 4 files changed, 164 insertions(+), 101 deletions(-) | ||
28 | |||
29 | diff --git a/include/net/flow.h b/include/net/flow.h | ||
30 | index 809970b..bb08692 100644 | ||
31 | --- a/include/net/flow.h | ||
32 | +++ b/include/net/flow.h | ||
33 | @@ -86,11 +86,26 @@ struct flowi { | ||
34 | |||
35 | struct net; | ||
36 | struct sock; | ||
37 | -typedef int (*flow_resolve_t)(struct net *net, struct flowi *key, u16 family, | ||
38 | - u8 dir, void **objp, atomic_t **obj_refp); | ||
39 | +struct flow_cache_ops; | ||
40 | + | ||
41 | +struct flow_cache_object { | ||
42 | + const struct flow_cache_ops *ops; | ||
43 | +}; | ||
44 | + | ||
45 | +struct flow_cache_ops { | ||
46 | + struct flow_cache_object *(*get)(struct flow_cache_object *); | ||
47 | + int (*check)(struct flow_cache_object *); | ||
48 | + void (*delete)(struct flow_cache_object *); | ||
49 | +}; | ||
50 | + | ||
51 | +typedef struct flow_cache_object *(*flow_resolve_t)( | ||
52 | + struct net *net, struct flowi *key, u16 family, | ||
53 | + u8 dir, struct flow_cache_object *oldobj, void *ctx); | ||
54 | + | ||
55 | +extern struct flow_cache_object *flow_cache_lookup( | ||
56 | + struct net *net, struct flowi *key, u16 family, | ||
57 | + u8 dir, flow_resolve_t resolver, void *ctx); | ||
58 | |||
59 | -extern void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, | ||
60 | - u8 dir, flow_resolve_t resolver); | ||
61 | extern void flow_cache_flush(void); | ||
62 | extern atomic_t flow_cache_genid; | ||
63 | |||
64 | diff --git a/include/net/xfrm.h b/include/net/xfrm.h | ||
65 | index 6960be2..6023a48 100644 | ||
66 | --- a/include/net/xfrm.h | ||
67 | +++ b/include/net/xfrm.h | ||
68 | @@ -19,6 +19,8 @@ | ||
69 | #include <net/route.h> | ||
70 | #include <net/ipv6.h> | ||
71 | #include <net/ip6_fib.h> | ||
72 | +#include <net/flow.h> | ||
73 | + | ||
74 | #ifdef CONFIG_XFRM_STATISTICS | ||
75 | #include <net/snmp.h> | ||
76 | #endif | ||
77 | @@ -482,6 +484,7 @@ struct xfrm_policy | ||
78 | atomic_t refcnt; | ||
79 | struct timer_list timer; | ||
80 | |||
81 | + struct flow_cache_object flo; | ||
82 | u32 priority; | ||
83 | u32 index; | ||
84 | struct xfrm_selector selector; | ||
85 | diff --git a/net/core/flow.c b/net/core/flow.c | ||
86 | index 1d27ca6..521df52 100644 | ||
87 | --- a/net/core/flow.c | ||
88 | +++ b/net/core/flow.c | ||
89 | @@ -26,17 +26,16 @@ | ||
90 | #include <linux/security.h> | ||
91 | |||
92 | struct flow_cache_entry { | ||
93 | - struct flow_cache_entry *next; | ||
94 | - u16 family; | ||
95 | - u8 dir; | ||
96 | - u32 genid; | ||
97 | - struct flowi key; | ||
98 | - void *object; | ||
99 | - atomic_t *object_ref; | ||
100 | + struct flow_cache_entry *next; | ||
101 | + u16 family; | ||
102 | + u8 dir; | ||
103 | + u32 genid; | ||
104 | + struct flowi key; | ||
105 | + struct flow_cache_object *object; | ||
106 | }; | ||
107 | |||
108 | struct flow_cache_percpu { | ||
109 | - struct flow_cache_entry ** hash_table; | ||
110 | + struct flow_cache_entry **hash_table; | ||
111 | int hash_count; | ||
112 | u32 hash_rnd; | ||
113 | int hash_rnd_recalc; | ||
114 | @@ -44,7 +43,7 @@ struct flow_cache_percpu { | ||
115 | }; | ||
116 | |||
117 | struct flow_flush_info { | ||
118 | - struct flow_cache * cache; | ||
119 | + struct flow_cache *cache; | ||
120 | atomic_t cpuleft; | ||
121 | struct completion completion; | ||
122 | }; | ||
123 | @@ -52,7 +51,7 @@ struct flow_flush_info { | ||
124 | struct flow_cache { | ||
125 | u32 hash_shift; | ||
126 | unsigned long order; | ||
127 | - struct flow_cache_percpu * percpu; | ||
128 | + struct flow_cache_percpu *percpu; | ||
129 | struct notifier_block hotcpu_notifier; | ||
130 | int low_watermark; | ||
131 | int high_watermark; | ||
132 | @@ -78,12 +77,21 @@ static void flow_cache_new_hashrnd(unsigned long arg) | ||
133 | add_timer(&fc->rnd_timer); | ||
134 | } | ||
135 | |||
136 | +static int flow_entry_valid(struct flow_cache_entry *fle) | ||
137 | +{ | ||
138 | + if (atomic_read(&flow_cache_genid) != fle->genid) | ||
139 | + return 0; | ||
140 | + if (fle->object && !fle->object->ops->check(fle->object)) | ||
141 | + return 0; | ||
142 | + return 1; | ||
143 | +} | ||
144 | + | ||
145 | static void flow_entry_kill(struct flow_cache *fc, | ||
146 | struct flow_cache_percpu *fcp, | ||
147 | struct flow_cache_entry *fle) | ||
148 | { | ||
149 | if (fle->object) | ||
150 | - atomic_dec(fle->object_ref); | ||
151 | + fle->object->ops->delete(fle->object); | ||
152 | kmem_cache_free(flow_cachep, fle); | ||
153 | fcp->hash_count--; | ||
154 | } | ||
155 | @@ -96,16 +104,18 @@ static void __flow_cache_shrink(struct flow_cache *fc, | ||
156 | int i; | ||
157 | |||
158 | for (i = 0; i < flow_cache_hash_size(fc); i++) { | ||
159 | - int k = 0; | ||
160 | + int saved = 0; | ||
161 | |||
162 | flp = &fcp->hash_table[i]; | ||
163 | - while ((fle = *flp) != NULL && k < shrink_to) { | ||
164 | - k++; | ||
165 | - flp = &fle->next; | ||
166 | - } | ||
167 | while ((fle = *flp) != NULL) { | ||
168 | - *flp = fle->next; | ||
169 | - flow_entry_kill(fc, fcp, fle); | ||
170 | + if (saved < shrink_to && | ||
171 | + flow_entry_valid(fle)) { | ||
172 | + saved++; | ||
173 | + flp = &fle->next; | ||
174 | + } else { | ||
175 | + *flp = fle->next; | ||
176 | + flow_entry_kill(fc, fcp, fle); | ||
177 | + } | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | @@ -166,18 +176,21 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2) | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | -void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
186 | - flow_resolve_t resolver) | ||
187 | +struct flow_cache_object * | ||
188 | +flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
189 | + flow_resolve_t resolver, void *ctx) | ||
190 | { | ||
191 | struct flow_cache *fc = &flow_cache_global; | ||
192 | struct flow_cache_percpu *fcp; | ||
193 | struct flow_cache_entry *fle, **head; | ||
194 | + struct flow_cache_object *flo; | ||
195 | unsigned int hash; | ||
196 | |||
197 | local_bh_disable(); | ||
198 | fcp = per_cpu_ptr(fc->percpu, smp_processor_id()); | ||
199 | |||
200 | fle = NULL; | ||
201 | + flo = NULL; | ||
202 | /* Packet really early in init? Making flow_cache_init a | ||
203 | * pre-smp initcall would solve this. --RR */ | ||
204 | if (!fcp->hash_table) | ||
205 | @@ -185,27 +198,17 @@ void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
206 | |||
207 | if (fcp->hash_rnd_recalc) | ||
208 | flow_new_hash_rnd(fc, fcp); | ||
209 | - hash = flow_hash_code(fc, fcp, key); | ||
210 | |||
211 | + hash = flow_hash_code(fc, fcp, key); | ||
212 | head = &fcp->hash_table[hash]; | ||
213 | for (fle = *head; fle; fle = fle->next) { | ||
214 | if (fle->family == family && | ||
215 | fle->dir == dir && | ||
216 | - flow_key_compare(key, &fle->key) == 0) { | ||
217 | - if (fle->genid == atomic_read(&flow_cache_genid)) { | ||
218 | - void *ret = fle->object; | ||
219 | - | ||
220 | - if (ret) | ||
221 | - atomic_inc(fle->object_ref); | ||
222 | - local_bh_enable(); | ||
223 | - | ||
224 | - return ret; | ||
225 | - } | ||
226 | + flow_key_compare(key, &fle->key) == 0) | ||
227 | break; | ||
228 | - } | ||
229 | } | ||
230 | |||
231 | - if (!fle) { | ||
232 | + if (unlikely(!fle)) { | ||
233 | if (fcp->hash_count > fc->high_watermark) | ||
234 | flow_cache_shrink(fc, fcp); | ||
235 | |||
236 | @@ -219,33 +222,39 @@ void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
237 | fle->object = NULL; | ||
238 | fcp->hash_count++; | ||
239 | } | ||
240 | + } else if (likely(fle->genid == atomic_read(&flow_cache_genid))) { | ||
241 | + flo = fle->object; | ||
242 | + if (!flo) | ||
243 | + goto ret_object; | ||
244 | + flo = flo->ops->get(flo); | ||
245 | + if (flo) | ||
246 | + goto ret_object; | ||
247 | + } else if (fle->object) { | ||
248 | + flo = fle->object; | ||
249 | + flo->ops->delete(flo); | ||
250 | + fle->object = NULL; | ||
251 | } | ||
252 | |||
253 | nocache: | ||
254 | - { | ||
255 | - int err; | ||
256 | - void *obj; | ||
257 | - atomic_t *obj_ref; | ||
258 | - | ||
259 | - err = resolver(net, key, family, dir, &obj, &obj_ref); | ||
260 | - | ||
261 | - if (fle && !err) { | ||
262 | - fle->genid = atomic_read(&flow_cache_genid); | ||
263 | - | ||
264 | - if (fle->object) | ||
265 | - atomic_dec(fle->object_ref); | ||
266 | - | ||
267 | - fle->object = obj; | ||
268 | - fle->object_ref = obj_ref; | ||
269 | - if (obj) | ||
270 | - atomic_inc(fle->object_ref); | ||
271 | - } | ||
272 | - local_bh_enable(); | ||
273 | - | ||
274 | - if (err) | ||
275 | - obj = ERR_PTR(err); | ||
276 | - return obj; | ||
277 | + flo = NULL; | ||
278 | + if (fle) { | ||
279 | + flo = fle->object; | ||
280 | + fle->object = NULL; | ||
281 | + } | ||
282 | + flo = resolver(net, key, family, dir, flo, ctx); | ||
283 | + if (fle) { | ||
284 | + fle->genid = atomic_read(&flow_cache_genid); | ||
285 | + if (!IS_ERR(flo)) | ||
286 | + fle->object = flo; | ||
287 | + else | ||
288 | + fle->genid--; | ||
289 | + } else { | ||
290 | + if (flo && !IS_ERR(flo)) | ||
291 | + flo->ops->delete(flo); | ||
292 | } | ||
293 | +ret_object: | ||
294 | + local_bh_enable(); | ||
295 | + return flo; | ||
296 | } | ||
297 | |||
298 | static void flow_cache_flush_tasklet(unsigned long data) | ||
299 | @@ -261,13 +270,12 @@ static void flow_cache_flush_tasklet(unsigned long data) | ||
300 | |||
301 | fle = fcp->hash_table[i]; | ||
302 | for (; fle; fle = fle->next) { | ||
303 | - unsigned genid = atomic_read(&flow_cache_genid); | ||
304 | - | ||
305 | - if (!fle->object || fle->genid == genid) | ||
306 | + if (flow_entry_valid(fle)) | ||
307 | continue; | ||
308 | |||
309 | + if (fle->object) | ||
310 | + fle->object->ops->delete(fle->object); | ||
311 | fle->object = NULL; | ||
312 | - atomic_dec(fle->object_ref); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c | ||
317 | index 110184f..d1eb2b5 100644 | ||
318 | --- a/net/xfrm/xfrm_policy.c | ||
319 | +++ b/net/xfrm/xfrm_policy.c | ||
320 | @@ -216,6 +216,35 @@ expired: | ||
321 | xfrm_pol_put(xp); | ||
322 | } | ||
323 | |||
324 | +static struct flow_cache_object *xfrm_policy_flo_get(struct flow_cache_object *flo) | ||
325 | +{ | ||
326 | + struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo); | ||
327 | + | ||
328 | + if (unlikely(pol->walk.dead)) | ||
329 | + flo = NULL; | ||
330 | + else | ||
331 | + xfrm_pol_hold(pol); | ||
332 | + | ||
333 | + return flo; | ||
334 | +} | ||
335 | + | ||
336 | +static int xfrm_policy_flo_check(struct flow_cache_object *flo) | ||
337 | +{ | ||
338 | + struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo); | ||
339 | + | ||
340 | + return !pol->walk.dead; | ||
341 | +} | ||
342 | + | ||
343 | +static void xfrm_policy_flo_delete(struct flow_cache_object *flo) | ||
344 | +{ | ||
345 | + xfrm_pol_put(container_of(flo, struct xfrm_policy, flo)); | ||
346 | +} | ||
347 | + | ||
348 | +static const struct flow_cache_ops xfrm_policy_fc_ops = { | ||
349 | + .get = xfrm_policy_flo_get, | ||
350 | + .check = xfrm_policy_flo_check, | ||
351 | + .delete = xfrm_policy_flo_delete, | ||
352 | +}; | ||
353 | |||
354 | /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2 | ||
355 | * SPD calls. | ||
356 | @@ -236,6 +265,7 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp) | ||
357 | atomic_set(&policy->refcnt, 1); | ||
358 | setup_timer(&policy->timer, xfrm_policy_timer, | ||
359 | (unsigned long)policy); | ||
360 | + policy->flo.ops = &xfrm_policy_fc_ops; | ||
361 | } | ||
362 | return policy; | ||
363 | } | ||
364 | @@ -269,9 +299,6 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy) | ||
365 | if (del_timer(&policy->timer)) | ||
366 | atomic_dec(&policy->refcnt); | ||
367 | |||
368 | - if (atomic_read(&policy->refcnt) > 1) | ||
369 | - flow_cache_flush(); | ||
370 | - | ||
371 | xfrm_pol_put(policy); | ||
372 | } | ||
373 | |||
374 | @@ -658,10 +685,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, | ||
375 | } | ||
376 | write_unlock_bh(&xfrm_policy_lock); | ||
377 | |||
378 | - if (ret && delete) { | ||
379 | - atomic_inc(&flow_cache_genid); | ||
380 | + if (ret && delete) | ||
381 | xfrm_policy_kill(ret); | ||
382 | - } | ||
383 | return ret; | ||
384 | } | ||
385 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | ||
386 | @@ -699,10 +724,8 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id, | ||
387 | } | ||
388 | write_unlock_bh(&xfrm_policy_lock); | ||
389 | |||
390 | - if (ret && delete) { | ||
391 | - atomic_inc(&flow_cache_genid); | ||
392 | + if (ret && delete) | ||
393 | xfrm_policy_kill(ret); | ||
394 | - } | ||
395 | return ret; | ||
396 | } | ||
397 | EXPORT_SYMBOL(xfrm_policy_byid); | ||
398 | @@ -967,32 +990,35 @@ fail: | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | -static int xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, | ||
403 | - u8 dir, void **objp, atomic_t **obj_refp) | ||
404 | +static struct flow_cache_object * | ||
405 | +xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, | ||
406 | + u8 dir, struct flow_cache_object *old_obj, void *ctx) | ||
407 | { | ||
408 | struct xfrm_policy *pol; | ||
409 | - int err = 0; | ||
410 | + | ||
411 | + if (old_obj) | ||
412 | + xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo)); | ||
413 | |||
414 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
415 | pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
416 | - if (IS_ERR(pol)) { | ||
417 | - err = PTR_ERR(pol); | ||
418 | - pol = NULL; | ||
419 | - } | ||
420 | - if (pol || err) | ||
421 | - goto end; | ||
422 | + if (IS_ERR(pol)) | ||
423 | + return ERR_CAST(pol); | ||
424 | + if (pol) | ||
425 | + goto found; | ||
426 | #endif | ||
427 | pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
428 | - if (IS_ERR(pol)) { | ||
429 | - err = PTR_ERR(pol); | ||
430 | - pol = NULL; | ||
431 | - } | ||
432 | -#ifdef CONFIG_XFRM_SUB_POLICY | ||
433 | -end: | ||
434 | -#endif | ||
435 | - if ((*objp = (void *) pol) != NULL) | ||
436 | - *obj_refp = &pol->refcnt; | ||
437 | - return err; | ||
438 | + if (IS_ERR(pol)) | ||
439 | + return ERR_CAST(pol); | ||
440 | + if (pol) | ||
441 | + goto found; | ||
442 | + return NULL; | ||
443 | + | ||
444 | +found: | ||
445 | + /* Resolver returns two references: | ||
446 | + * one for cache and one for caller of flow_cache_lookup() */ | ||
447 | + xfrm_pol_hold(pol); | ||
448 | + | ||
449 | + return &pol->flo; | ||
450 | } | ||
451 | |||
452 | static inline int policy_to_flow_dir(int dir) | ||
453 | @@ -1077,8 +1103,6 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | ||
454 | pol = __xfrm_policy_unlink(pol, dir); | ||
455 | write_unlock_bh(&xfrm_policy_lock); | ||
456 | if (pol) { | ||
457 | - if (dir < XFRM_POLICY_MAX) | ||
458 | - atomic_inc(&flow_cache_genid); | ||
459 | xfrm_policy_kill(pol); | ||
460 | return 0; | ||
461 | } | ||
462 | @@ -1549,18 +1573,24 @@ restart: | ||
463 | } | ||
464 | |||
465 | if (!policy) { | ||
466 | + struct flow_cache_object *flo; | ||
467 | + | ||
468 | /* To accelerate a bit... */ | ||
469 | if ((dst_orig->flags & DST_NOXFRM) || | ||
470 | !net->xfrm.policy_count[XFRM_POLICY_OUT]) | ||
471 | goto nopol; | ||
472 | |||
473 | - policy = flow_cache_lookup(net, fl, dst_orig->ops->family, | ||
474 | - dir, xfrm_policy_lookup); | ||
475 | - err = PTR_ERR(policy); | ||
476 | - if (IS_ERR(policy)) { | ||
477 | + flo = flow_cache_lookup(net, fl, dst_orig->ops->family, | ||
478 | + dir, xfrm_policy_lookup, NULL); | ||
479 | + err = PTR_ERR(flo); | ||
480 | + if (IS_ERR(flo)) { | ||
481 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
482 | goto dropdst; | ||
483 | } | ||
484 | + if (flo) | ||
485 | + policy = container_of(flo, struct xfrm_policy, flo); | ||
486 | + else | ||
487 | + policy = NULL; | ||
488 | } | ||
489 | |||
490 | if (!policy) | ||
491 | @@ -1910,9 +1940,16 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | ||
492 | } | ||
493 | } | ||
494 | |||
495 | - if (!pol) | ||
496 | - pol = flow_cache_lookup(net, &fl, family, fl_dir, | ||
497 | - xfrm_policy_lookup); | ||
498 | + if (!pol) { | ||
499 | + struct flow_cache_object *flo; | ||
500 | + | ||
501 | + flo = flow_cache_lookup(net, &fl, family, fl_dir, | ||
502 | + xfrm_policy_lookup, NULL); | ||
503 | + if (flo == NULL || IS_ERR(flo)) | ||
504 | + pol = ERR_CAST(flo); | ||
505 | + else | ||
506 | + pol = container_of(flo, struct xfrm_policy, flo); | ||
507 | + } | ||
508 | |||
509 | if (IS_ERR(pol)) { | ||
510 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); | ||
511 | -- | ||
512 | 1.7.0.2 | ||
513 | |||
diff --git a/main/linux-grsec/0015-xfrm-cache-bundles-instead-of-policies-for-outgoing-.patch b/main/linux-grsec/0015-xfrm-cache-bundles-instead-of-policies-for-outgoing-.patch new file mode 100644 index 0000000000..0d066c84d9 --- /dev/null +++ b/main/linux-grsec/0015-xfrm-cache-bundles-instead-of-policies-for-outgoing-.patch | |||
@@ -0,0 +1,1068 @@ | |||
1 | From f89d21648e6dc06db2aeabc8926c270894c41446 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 7 Apr 2010 00:30:05 +0000 | ||
4 | Subject: [PATCH 15/18] xfrm: cache bundles instead of policies for outgoing flows | ||
5 | |||
6 | __xfrm_lookup() is called for each packet transmitted out of | ||
7 | system. The xfrm_find_bundle() does a linear search which can | ||
8 | kill system performance depending on how many bundles are | ||
9 | required per policy. | ||
10 | |||
11 | This modifies __xfrm_lookup() to store bundles directly in | ||
12 | the flow cache. If we did not get a hit, we just create a new | ||
13 | bundle instead of doing slow search. This means that we can now | ||
14 | get multiple xfrm_dst's for same flow (on per-cpu basis). | ||
15 | |||
16 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
17 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
18 | (backported from commit 80c802f3073e84c956846e921e8a0b02dfa3755f) | ||
19 | --- | ||
20 | include/net/xfrm.h | 10 +- | ||
21 | net/ipv4/xfrm4_policy.c | 22 -- | ||
22 | net/ipv6/xfrm6_policy.c | 31 -- | ||
23 | net/xfrm/xfrm_policy.c | 710 +++++++++++++++++++++++++---------------------- | ||
24 | 4 files changed, 383 insertions(+), 390 deletions(-) | ||
25 | |||
26 | diff --git a/include/net/xfrm.h b/include/net/xfrm.h | ||
27 | index 6023a48..d51ef61 100644 | ||
28 | --- a/include/net/xfrm.h | ||
29 | +++ b/include/net/xfrm.h | ||
30 | @@ -266,7 +266,6 @@ struct xfrm_policy_afinfo { | ||
31 | xfrm_address_t *saddr, | ||
32 | xfrm_address_t *daddr); | ||
33 | int (*get_saddr)(struct net *net, xfrm_address_t *saddr, xfrm_address_t *daddr); | ||
34 | - struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy); | ||
35 | void (*decode_session)(struct sk_buff *skb, | ||
36 | struct flowi *fl, | ||
37 | int reverse); | ||
38 | @@ -485,12 +484,12 @@ struct xfrm_policy | ||
39 | struct timer_list timer; | ||
40 | |||
41 | struct flow_cache_object flo; | ||
42 | + atomic_t genid; | ||
43 | u32 priority; | ||
44 | u32 index; | ||
45 | struct xfrm_selector selector; | ||
46 | struct xfrm_lifetime_cfg lft; | ||
47 | struct xfrm_lifetime_cur curlft; | ||
48 | - struct dst_entry *bundles; | ||
49 | struct xfrm_policy_walk_entry walk; | ||
50 | u8 type; | ||
51 | u8 action; | ||
52 | @@ -883,11 +882,15 @@ struct xfrm_dst | ||
53 | struct rt6_info rt6; | ||
54 | } u; | ||
55 | struct dst_entry *route; | ||
56 | + struct flow_cache_object flo; | ||
57 | + struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
58 | + int num_pols, num_xfrms; | ||
59 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
60 | struct flowi *origin; | ||
61 | struct xfrm_selector *partner; | ||
62 | #endif | ||
63 | - u32 genid; | ||
64 | + u32 xfrm_genid; | ||
65 | + u32 policy_genid; | ||
66 | u32 route_mtu_cached; | ||
67 | u32 child_mtu_cached; | ||
68 | u32 route_cookie; | ||
69 | @@ -897,6 +900,7 @@ struct xfrm_dst | ||
70 | #ifdef CONFIG_XFRM | ||
71 | static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) | ||
72 | { | ||
73 | + xfrm_pols_put(xdst->pols, xdst->num_pols); | ||
74 | dst_release(xdst->route); | ||
75 | if (likely(xdst->u.dst.xfrm)) | ||
76 | xfrm_state_put(xdst->u.dst.xfrm); | ||
77 | diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c | ||
78 | index 7009886..651a3e7 100644 | ||
79 | --- a/net/ipv4/xfrm4_policy.c | ||
80 | +++ b/net/ipv4/xfrm4_policy.c | ||
81 | @@ -60,27 +60,6 @@ static int xfrm4_get_saddr(struct net *net, | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | -static struct dst_entry * | ||
86 | -__xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | ||
87 | -{ | ||
88 | - struct dst_entry *dst; | ||
89 | - | ||
90 | - read_lock_bh(&policy->lock); | ||
91 | - for (dst = policy->bundles; dst; dst = dst->next) { | ||
92 | - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | ||
93 | - if (xdst->u.rt.fl.oif == fl->oif && /*XXX*/ | ||
94 | - xdst->u.rt.fl.fl4_dst == fl->fl4_dst && | ||
95 | - xdst->u.rt.fl.fl4_src == fl->fl4_src && | ||
96 | - xdst->u.rt.fl.fl4_tos == fl->fl4_tos && | ||
97 | - xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) { | ||
98 | - dst_clone(dst); | ||
99 | - break; | ||
100 | - } | ||
101 | - } | ||
102 | - read_unlock_bh(&policy->lock); | ||
103 | - return dst; | ||
104 | -} | ||
105 | - | ||
106 | static int xfrm4_get_tos(struct flowi *fl) | ||
107 | { | ||
108 | return fl->fl4_tos; | ||
109 | @@ -258,7 +237,6 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | ||
110 | .dst_ops = &xfrm4_dst_ops, | ||
111 | .dst_lookup = xfrm4_dst_lookup, | ||
112 | .get_saddr = xfrm4_get_saddr, | ||
113 | - .find_bundle = __xfrm4_find_bundle, | ||
114 | .decode_session = _decode_session4, | ||
115 | .get_tos = xfrm4_get_tos, | ||
116 | .init_path = xfrm4_init_path, | ||
117 | diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c | ||
118 | index 3f89ab7..fb2a5b7 100644 | ||
119 | --- a/net/ipv6/xfrm6_policy.c | ||
120 | +++ b/net/ipv6/xfrm6_policy.c | ||
121 | @@ -68,36 +68,6 @@ static int xfrm6_get_saddr(struct net *net, | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | -static struct dst_entry * | ||
126 | -__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | ||
127 | -{ | ||
128 | - struct dst_entry *dst; | ||
129 | - | ||
130 | - /* Still not clear if we should set fl->fl6_{src,dst}... */ | ||
131 | - read_lock_bh(&policy->lock); | ||
132 | - for (dst = policy->bundles; dst; dst = dst->next) { | ||
133 | - struct xfrm_dst *xdst = (struct xfrm_dst*)dst; | ||
134 | - struct in6_addr fl_dst_prefix, fl_src_prefix; | ||
135 | - | ||
136 | - ipv6_addr_prefix(&fl_dst_prefix, | ||
137 | - &fl->fl6_dst, | ||
138 | - xdst->u.rt6.rt6i_dst.plen); | ||
139 | - ipv6_addr_prefix(&fl_src_prefix, | ||
140 | - &fl->fl6_src, | ||
141 | - xdst->u.rt6.rt6i_src.plen); | ||
142 | - if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && | ||
143 | - ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && | ||
144 | - xfrm_bundle_ok(policy, xdst, fl, AF_INET6, | ||
145 | - (xdst->u.rt6.rt6i_dst.plen != 128 || | ||
146 | - xdst->u.rt6.rt6i_src.plen != 128))) { | ||
147 | - dst_clone(dst); | ||
148 | - break; | ||
149 | - } | ||
150 | - } | ||
151 | - read_unlock_bh(&policy->lock); | ||
152 | - return dst; | ||
153 | -} | ||
154 | - | ||
155 | static int xfrm6_get_tos(struct flowi *fl) | ||
156 | { | ||
157 | return 0; | ||
158 | @@ -290,7 +260,6 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | ||
159 | .dst_ops = &xfrm6_dst_ops, | ||
160 | .dst_lookup = xfrm6_dst_lookup, | ||
161 | .get_saddr = xfrm6_get_saddr, | ||
162 | - .find_bundle = __xfrm6_find_bundle, | ||
163 | .decode_session = _decode_session6, | ||
164 | .get_tos = xfrm6_get_tos, | ||
165 | .init_path = xfrm6_init_path, | ||
166 | diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c | ||
167 | index d1eb2b5..0379d82 100644 | ||
168 | --- a/net/xfrm/xfrm_policy.c | ||
169 | +++ b/net/xfrm/xfrm_policy.c | ||
170 | @@ -37,6 +37,8 @@ | ||
171 | DEFINE_MUTEX(xfrm_cfg_mutex); | ||
172 | EXPORT_SYMBOL(xfrm_cfg_mutex); | ||
173 | |||
174 | +static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock); | ||
175 | +static struct dst_entry *xfrm_policy_sk_bundles; | ||
176 | static DEFINE_RWLOCK(xfrm_policy_lock); | ||
177 | |||
178 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); | ||
179 | @@ -50,6 +52,7 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock); | ||
180 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); | ||
181 | static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); | ||
182 | static void xfrm_init_pmtu(struct dst_entry *dst); | ||
183 | +static int stale_bundle(struct dst_entry *dst); | ||
184 | |||
185 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | ||
186 | int dir); | ||
187 | @@ -277,8 +280,6 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) | ||
188 | { | ||
189 | BUG_ON(!policy->walk.dead); | ||
190 | |||
191 | - BUG_ON(policy->bundles); | ||
192 | - | ||
193 | if (del_timer(&policy->timer)) | ||
194 | BUG(); | ||
195 | |||
196 | @@ -289,12 +290,7 @@ EXPORT_SYMBOL(xfrm_policy_destroy); | ||
197 | |||
198 | static void xfrm_policy_gc_kill(struct xfrm_policy *policy) | ||
199 | { | ||
200 | - struct dst_entry *dst; | ||
201 | - | ||
202 | - while ((dst = policy->bundles) != NULL) { | ||
203 | - policy->bundles = dst->next; | ||
204 | - dst_free(dst); | ||
205 | - } | ||
206 | + atomic_inc(&policy->genid); | ||
207 | |||
208 | if (del_timer(&policy->timer)) | ||
209 | atomic_dec(&policy->refcnt); | ||
210 | @@ -572,7 +568,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | ||
211 | struct xfrm_policy *delpol; | ||
212 | struct hlist_head *chain; | ||
213 | struct hlist_node *entry, *newpos; | ||
214 | - struct dst_entry *gc_list; | ||
215 | |||
216 | write_lock_bh(&xfrm_policy_lock); | ||
217 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); | ||
218 | @@ -620,34 +615,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | ||
219 | else if (xfrm_bydst_should_resize(net, dir, NULL)) | ||
220 | schedule_work(&net->xfrm.policy_hash_work); | ||
221 | |||
222 | - read_lock_bh(&xfrm_policy_lock); | ||
223 | - gc_list = NULL; | ||
224 | - entry = &policy->bydst; | ||
225 | - hlist_for_each_entry_continue(policy, entry, bydst) { | ||
226 | - struct dst_entry *dst; | ||
227 | - | ||
228 | - write_lock(&policy->lock); | ||
229 | - dst = policy->bundles; | ||
230 | - if (dst) { | ||
231 | - struct dst_entry *tail = dst; | ||
232 | - while (tail->next) | ||
233 | - tail = tail->next; | ||
234 | - tail->next = gc_list; | ||
235 | - gc_list = dst; | ||
236 | - | ||
237 | - policy->bundles = NULL; | ||
238 | - } | ||
239 | - write_unlock(&policy->lock); | ||
240 | - } | ||
241 | - read_unlock_bh(&xfrm_policy_lock); | ||
242 | - | ||
243 | - while (gc_list) { | ||
244 | - struct dst_entry *dst = gc_list; | ||
245 | - | ||
246 | - gc_list = dst->next; | ||
247 | - dst_free(dst); | ||
248 | - } | ||
249 | - | ||
250 | return 0; | ||
251 | } | ||
252 | EXPORT_SYMBOL(xfrm_policy_insert); | ||
253 | @@ -990,6 +957,19 @@ fail: | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | +static struct xfrm_policy * | ||
258 | +__xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, u8 dir) | ||
259 | +{ | ||
260 | +#ifdef CONFIG_XFRM_SUB_POLICY | ||
261 | + struct xfrm_policy *pol; | ||
262 | + | ||
263 | + pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
264 | + if (pol != NULL) | ||
265 | + return pol; | ||
266 | +#endif | ||
267 | + return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
268 | +} | ||
269 | + | ||
270 | static struct flow_cache_object * | ||
271 | xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, | ||
272 | u8 dir, struct flow_cache_object *old_obj, void *ctx) | ||
273 | @@ -999,21 +979,10 @@ xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, | ||
274 | if (old_obj) | ||
275 | xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo)); | ||
276 | |||
277 | -#ifdef CONFIG_XFRM_SUB_POLICY | ||
278 | - pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
279 | - if (IS_ERR(pol)) | ||
280 | + pol = __xfrm_policy_lookup(net, fl, family, dir); | ||
281 | + if (pol == NULL || IS_ERR(pol)) | ||
282 | return ERR_CAST(pol); | ||
283 | - if (pol) | ||
284 | - goto found; | ||
285 | -#endif | ||
286 | - pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
287 | - if (IS_ERR(pol)) | ||
288 | - return ERR_CAST(pol); | ||
289 | - if (pol) | ||
290 | - goto found; | ||
291 | - return NULL; | ||
292 | |||
293 | -found: | ||
294 | /* Resolver returns two references: | ||
295 | * one for cache and one for caller of flow_cache_lookup() */ | ||
296 | xfrm_pol_hold(pol); | ||
297 | @@ -1299,18 +1268,6 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | ||
298 | * still valid. | ||
299 | */ | ||
300 | |||
301 | -static struct dst_entry * | ||
302 | -xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short family) | ||
303 | -{ | ||
304 | - struct dst_entry *x; | ||
305 | - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | ||
306 | - if (unlikely(afinfo == NULL)) | ||
307 | - return ERR_PTR(-EINVAL); | ||
308 | - x = afinfo->find_bundle(fl, policy); | ||
309 | - xfrm_policy_put_afinfo(afinfo); | ||
310 | - return x; | ||
311 | -} | ||
312 | - | ||
313 | static inline int xfrm_get_tos(struct flowi *fl, int family) | ||
314 | { | ||
315 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | ||
316 | @@ -1326,6 +1283,54 @@ static inline int xfrm_get_tos(struct flowi *fl, int family) | ||
317 | return tos; | ||
318 | } | ||
319 | |||
320 | +static struct flow_cache_object *xfrm_bundle_flo_get(struct flow_cache_object *flo) | ||
321 | +{ | ||
322 | + struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo); | ||
323 | + struct dst_entry *dst = &xdst->u.dst; | ||
324 | + | ||
325 | + if (xdst->route == NULL) { | ||
326 | + /* Dummy bundle - if it has xfrms we were not | ||
327 | + * able to build bundle as template resolution failed. | ||
328 | + * It means we need to try again resolving. */ | ||
329 | + if (xdst->num_xfrms > 0) | ||
330 | + return NULL; | ||
331 | + } else { | ||
332 | + /* Real bundle */ | ||
333 | + if (stale_bundle(dst)) | ||
334 | + return NULL; | ||
335 | + } | ||
336 | + | ||
337 | + dst_hold(dst); | ||
338 | + return flo; | ||
339 | +} | ||
340 | + | ||
341 | +static int xfrm_bundle_flo_check(struct flow_cache_object *flo) | ||
342 | +{ | ||
343 | + struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo); | ||
344 | + struct dst_entry *dst = &xdst->u.dst; | ||
345 | + | ||
346 | + if (!xdst->route) | ||
347 | + return 0; | ||
348 | + if (stale_bundle(dst)) | ||
349 | + return 0; | ||
350 | + | ||
351 | + return 1; | ||
352 | +} | ||
353 | + | ||
354 | +static void xfrm_bundle_flo_delete(struct flow_cache_object *flo) | ||
355 | +{ | ||
356 | + struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo); | ||
357 | + struct dst_entry *dst = &xdst->u.dst; | ||
358 | + | ||
359 | + dst_free(dst); | ||
360 | +} | ||
361 | + | ||
362 | +static const struct flow_cache_ops xfrm_bundle_fc_ops = { | ||
363 | + .get = xfrm_bundle_flo_get, | ||
364 | + .check = xfrm_bundle_flo_check, | ||
365 | + .delete = xfrm_bundle_flo_delete, | ||
366 | +}; | ||
367 | + | ||
368 | static inline struct xfrm_dst *xfrm_alloc_dst(int family) | ||
369 | { | ||
370 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | ||
371 | @@ -1338,6 +1343,8 @@ static inline struct xfrm_dst *xfrm_alloc_dst(int family) | ||
372 | |||
373 | xfrm_policy_put_afinfo(afinfo); | ||
374 | |||
375 | + xdst->flo.ops = &xfrm_bundle_fc_ops; | ||
376 | + | ||
377 | return xdst; | ||
378 | } | ||
379 | |||
380 | @@ -1375,6 +1382,7 @@ static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | ||
381 | return err; | ||
382 | } | ||
383 | |||
384 | + | ||
385 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate | ||
386 | * all the metrics... Shortly, bundle a bundle. | ||
387 | */ | ||
388 | @@ -1437,7 +1445,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | ||
389 | dst_hold(dst); | ||
390 | |||
391 | dst1->xfrm = xfrm[i]; | ||
392 | - xdst->genid = xfrm[i]->genid; | ||
393 | + xdst->xfrm_genid = xfrm[i]->genid; | ||
394 | |||
395 | dst1->obsolete = -1; | ||
396 | dst1->flags |= DST_HOST; | ||
397 | @@ -1530,7 +1538,186 @@ xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl) | ||
398 | #endif | ||
399 | } | ||
400 | |||
401 | -static int stale_bundle(struct dst_entry *dst); | ||
402 | +static int xfrm_expand_policies(struct flowi *fl, u16 family, | ||
403 | + struct xfrm_policy **pols, | ||
404 | + int *num_pols, int *num_xfrms) | ||
405 | +{ | ||
406 | + int i; | ||
407 | + | ||
408 | + if (*num_pols == 0 || !pols[0]) { | ||
409 | + *num_pols = 0; | ||
410 | + *num_xfrms = 0; | ||
411 | + return 0; | ||
412 | + } | ||
413 | + if (IS_ERR(pols[0])) | ||
414 | + return PTR_ERR(pols[0]); | ||
415 | + | ||
416 | + *num_xfrms = pols[0]->xfrm_nr; | ||
417 | + | ||
418 | +#ifdef CONFIG_XFRM_SUB_POLICY | ||
419 | + if (pols[0] && pols[0]->action == XFRM_POLICY_ALLOW && | ||
420 | + pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
421 | + pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]), | ||
422 | + XFRM_POLICY_TYPE_MAIN, | ||
423 | + fl, family, | ||
424 | + XFRM_POLICY_OUT); | ||
425 | + if (pols[1]) { | ||
426 | + if (IS_ERR(pols[1])) { | ||
427 | + xfrm_pols_put(pols, *num_pols); | ||
428 | + return PTR_ERR(pols[1]); | ||
429 | + } | ||
430 | + (*num_pols) ++; | ||
431 | + (*num_xfrms) += pols[1]->xfrm_nr; | ||
432 | + } | ||
433 | + } | ||
434 | +#endif | ||
435 | + for (i = 0; i < *num_pols; i++) { | ||
436 | + if (pols[i]->action != XFRM_POLICY_ALLOW) { | ||
437 | + *num_xfrms = -1; | ||
438 | + break; | ||
439 | + } | ||
440 | + } | ||
441 | + | ||
442 | + return 0; | ||
443 | + | ||
444 | +} | ||
445 | + | ||
446 | +static struct xfrm_dst * | ||
447 | +xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, | ||
448 | + struct flowi *fl, u16 family, | ||
449 | + struct dst_entry *dst_orig) | ||
450 | +{ | ||
451 | + struct net *net = xp_net(pols[0]); | ||
452 | + struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | ||
453 | + struct dst_entry *dst; | ||
454 | + struct xfrm_dst *xdst; | ||
455 | + int err; | ||
456 | + | ||
457 | + /* Try to instantiate a bundle */ | ||
458 | + err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family); | ||
459 | + if (err < 0) { | ||
460 | + if (err != -EAGAIN) | ||
461 | + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
462 | + return ERR_PTR(err); | ||
463 | + } | ||
464 | + | ||
465 | + dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig); | ||
466 | + if (IS_ERR(dst)) { | ||
467 | + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR); | ||
468 | + return ERR_CAST(dst); | ||
469 | + } | ||
470 | + | ||
471 | + xdst = (struct xfrm_dst *)dst; | ||
472 | + xdst->num_xfrms = err; | ||
473 | + if (num_pols > 1) | ||
474 | + err = xfrm_dst_update_parent(dst, &pols[1]->selector); | ||
475 | + else | ||
476 | + err = xfrm_dst_update_origin(dst, fl); | ||
477 | + if (unlikely(err)) { | ||
478 | + dst_free(dst); | ||
479 | + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | ||
480 | + return ERR_PTR(err); | ||
481 | + } | ||
482 | + | ||
483 | + xdst->num_pols = num_pols; | ||
484 | + memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols); | ||
485 | + xdst->policy_genid = atomic_read(&pols[0]->genid); | ||
486 | + | ||
487 | + return xdst; | ||
488 | +} | ||
489 | + | ||
490 | +static struct flow_cache_object * | ||
491 | +xfrm_bundle_lookup(struct net *net, struct flowi *fl, u16 family, u8 dir, | ||
492 | + struct flow_cache_object *oldflo, void *ctx) | ||
493 | +{ | ||
494 | + struct dst_entry *dst_orig = (struct dst_entry *)ctx; | ||
495 | + struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
496 | + struct xfrm_dst *xdst, *new_xdst; | ||
497 | + int num_pols = 0, num_xfrms = 0, i, err, pol_dead; | ||
498 | + | ||
499 | + /* Check if the policies from old bundle are usable */ | ||
500 | + xdst = NULL; | ||
501 | + if (oldflo) { | ||
502 | + xdst = container_of(oldflo, struct xfrm_dst, flo); | ||
503 | + num_pols = xdst->num_pols; | ||
504 | + num_xfrms = xdst->num_xfrms; | ||
505 | + pol_dead = 0; | ||
506 | + for (i = 0; i < num_pols; i++) { | ||
507 | + pols[i] = xdst->pols[i]; | ||
508 | + pol_dead |= pols[i]->walk.dead; | ||
509 | + } | ||
510 | + if (pol_dead) { | ||
511 | + dst_free(&xdst->u.dst); | ||
512 | + xdst = NULL; | ||
513 | + num_pols = 0; | ||
514 | + num_xfrms = 0; | ||
515 | + oldflo = NULL; | ||
516 | + } | ||
517 | + } | ||
518 | + | ||
519 | + /* Resolve policies to use if we couldn't get them from | ||
520 | + * previous cache entry */ | ||
521 | + if (xdst == NULL) { | ||
522 | + num_pols = 1; | ||
523 | + pols[0] = __xfrm_policy_lookup(net, fl, family, dir); | ||
524 | + err = xfrm_expand_policies(fl, family, pols, | ||
525 | + &num_pols, &num_xfrms); | ||
526 | + if (err < 0) | ||
527 | + goto inc_error; | ||
528 | + if (num_pols == 0) | ||
529 | + return NULL; | ||
530 | + if (num_xfrms <= 0) | ||
531 | + goto make_dummy_bundle; | ||
532 | + } | ||
533 | + | ||
534 | + new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, dst_orig); | ||
535 | + if (IS_ERR(new_xdst)) { | ||
536 | + err = PTR_ERR(new_xdst); | ||
537 | + if (err != -EAGAIN) | ||
538 | + goto error; | ||
539 | + if (oldflo == NULL) | ||
540 | + goto make_dummy_bundle; | ||
541 | + dst_hold(&xdst->u.dst); | ||
542 | + return oldflo; | ||
543 | + } | ||
544 | + | ||
545 | + /* Kill the previous bundle */ | ||
546 | + if (xdst) { | ||
547 | + /* The policies were stolen for newly generated bundle */ | ||
548 | + xdst->num_pols = 0; | ||
549 | + dst_free(&xdst->u.dst); | ||
550 | + } | ||
551 | + | ||
552 | + /* Flow cache does not have reference, it dst_free()'s, | ||
553 | + * but we do need to return one reference for original caller */ | ||
554 | + dst_hold(&new_xdst->u.dst); | ||
555 | + return &new_xdst->flo; | ||
556 | + | ||
557 | +make_dummy_bundle: | ||
558 | + /* We found policies, but there's no bundles to instantiate: | ||
559 | + * either because the policy blocks, has no transformations or | ||
560 | + * we could not build template (no xfrm_states).*/ | ||
561 | + xdst = xfrm_alloc_dst(family); | ||
562 | + if (IS_ERR(xdst)) { | ||
563 | + xfrm_pols_put(pols, num_pols); | ||
564 | + return ERR_CAST(xdst); | ||
565 | + } | ||
566 | + xdst->num_pols = num_pols; | ||
567 | + xdst->num_xfrms = num_xfrms; | ||
568 | + memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols); | ||
569 | + | ||
570 | + dst_hold(&xdst->u.dst); | ||
571 | + return &xdst->flo; | ||
572 | + | ||
573 | +inc_error: | ||
574 | + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
575 | +error: | ||
576 | + if (xdst != NULL) | ||
577 | + dst_free(&xdst->u.dst); | ||
578 | + else | ||
579 | + xfrm_pols_put(pols, num_pols); | ||
580 | + return ERR_PTR(err); | ||
581 | +} | ||
582 | |||
583 | /* Main function: finds/creates a bundle for given flow. | ||
584 | * | ||
585 | @@ -1540,248 +1727,152 @@ static int stale_bundle(struct dst_entry *dst); | ||
586 | int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl, | ||
587 | struct sock *sk, int flags) | ||
588 | { | ||
589 | - struct xfrm_policy *policy; | ||
590 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
591 | - int npols; | ||
592 | - int pol_dead; | ||
593 | - int xfrm_nr; | ||
594 | - int pi; | ||
595 | - struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | ||
596 | - struct dst_entry *dst, *dst_orig = *dst_p; | ||
597 | - int nx = 0; | ||
598 | - int err; | ||
599 | - u32 genid; | ||
600 | - u16 family; | ||
601 | + struct flow_cache_object *flo; | ||
602 | + struct xfrm_dst *xdst; | ||
603 | + struct dst_entry *dst, *dst_orig = *dst_p, *route; | ||
604 | + u16 family = dst_orig->ops->family; | ||
605 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | ||
606 | + int i, err, num_pols, num_xfrms, drop_pols = 0; | ||
607 | |||
608 | restart: | ||
609 | - genid = atomic_read(&flow_cache_genid); | ||
610 | - policy = NULL; | ||
611 | - for (pi = 0; pi < ARRAY_SIZE(pols); pi++) | ||
612 | - pols[pi] = NULL; | ||
613 | - npols = 0; | ||
614 | - pol_dead = 0; | ||
615 | - xfrm_nr = 0; | ||
616 | + dst = NULL; | ||
617 | + xdst = NULL; | ||
618 | + route = NULL; | ||
619 | |||
620 | if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { | ||
621 | - policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | ||
622 | - err = PTR_ERR(policy); | ||
623 | - if (IS_ERR(policy)) { | ||
624 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
625 | + num_pols = 1; | ||
626 | + pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | ||
627 | + err = xfrm_expand_policies(fl, family, pols, | ||
628 | + &num_pols, &num_xfrms); | ||
629 | + if (err < 0) | ||
630 | goto dropdst; | ||
631 | + | ||
632 | + if (num_pols) { | ||
633 | + if (num_xfrms <= 0) { | ||
634 | + drop_pols = num_pols; | ||
635 | + goto no_transform; | ||
636 | + } | ||
637 | + | ||
638 | + xdst = xfrm_resolve_and_create_bundle( | ||
639 | + pols, num_pols, fl, | ||
640 | + family, dst_orig); | ||
641 | + if (IS_ERR(xdst)) { | ||
642 | + xfrm_pols_put(pols, num_pols); | ||
643 | + err = PTR_ERR(xdst); | ||
644 | + goto dropdst; | ||
645 | + } | ||
646 | + | ||
647 | + spin_lock_bh(&xfrm_policy_sk_bundle_lock); | ||
648 | + xdst->u.dst.next = xfrm_policy_sk_bundles; | ||
649 | + xfrm_policy_sk_bundles = &xdst->u.dst; | ||
650 | + spin_unlock_bh(&xfrm_policy_sk_bundle_lock); | ||
651 | + | ||
652 | + route = xdst->route; | ||
653 | } | ||
654 | } | ||
655 | |||
656 | - if (!policy) { | ||
657 | - struct flow_cache_object *flo; | ||
658 | - | ||
659 | + if (xdst == NULL) { | ||
660 | /* To accelerate a bit... */ | ||
661 | if ((dst_orig->flags & DST_NOXFRM) || | ||
662 | !net->xfrm.policy_count[XFRM_POLICY_OUT]) | ||
663 | goto nopol; | ||
664 | |||
665 | - flo = flow_cache_lookup(net, fl, dst_orig->ops->family, | ||
666 | - dir, xfrm_policy_lookup, NULL); | ||
667 | - err = PTR_ERR(flo); | ||
668 | + flo = flow_cache_lookup(net, fl, family, dir, | ||
669 | + xfrm_bundle_lookup, dst_orig); | ||
670 | + if (flo == NULL) | ||
671 | + goto nopol; | ||
672 | if (IS_ERR(flo)) { | ||
673 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
674 | + err = PTR_ERR(flo); | ||
675 | goto dropdst; | ||
676 | } | ||
677 | - if (flo) | ||
678 | - policy = container_of(flo, struct xfrm_policy, flo); | ||
679 | - else | ||
680 | - policy = NULL; | ||
681 | + xdst = container_of(flo, struct xfrm_dst, flo); | ||
682 | + | ||
683 | + num_pols = xdst->num_pols; | ||
684 | + num_xfrms = xdst->num_xfrms; | ||
685 | + memcpy(pols, xdst->pols, sizeof(struct xfrm_policy*) * num_pols); | ||
686 | + route = xdst->route; | ||
687 | + } | ||
688 | + | ||
689 | + dst = &xdst->u.dst; | ||
690 | + if (route == NULL && num_xfrms > 0) { | ||
691 | + /* The only case when xfrm_bundle_lookup() returns a | ||
692 | + * bundle with null route, is when the template could | ||
693 | + * not be resolved. It means policies are there, but | ||
694 | + * bundle could not be created, since we don't yet | ||
695 | + * have the xfrm_state's. We need to wait for KM to | ||
696 | + * negotiate new SA's or bail out with error.*/ | ||
697 | + if (net->xfrm.sysctl_larval_drop) { | ||
698 | + /* EREMOTE tells the caller to generate | ||
699 | + * a one-shot blackhole route. */ | ||
700 | + dst_release(dst); | ||
701 | + xfrm_pols_put(pols, num_pols); | ||
702 | + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | ||
703 | + return -EREMOTE; | ||
704 | + } | ||
705 | + if (flags & XFRM_LOOKUP_WAIT) { | ||
706 | + DECLARE_WAITQUEUE(wait, current); | ||
707 | + | ||
708 | + add_wait_queue(&net->xfrm.km_waitq, &wait); | ||
709 | + set_current_state(TASK_INTERRUPTIBLE); | ||
710 | + schedule(); | ||
711 | + set_current_state(TASK_RUNNING); | ||
712 | + remove_wait_queue(&net->xfrm.km_waitq, &wait); | ||
713 | + | ||
714 | + if (!signal_pending(current)) { | ||
715 | + dst_release(dst); | ||
716 | + goto restart; | ||
717 | + } | ||
718 | + | ||
719 | + err = -ERESTART; | ||
720 | + } else | ||
721 | + err = -EAGAIN; | ||
722 | + | ||
723 | + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | ||
724 | + goto error; | ||
725 | } | ||
726 | |||
727 | - if (!policy) | ||
728 | +no_transform: | ||
729 | + if (num_pols == 0) | ||
730 | goto nopol; | ||
731 | |||
732 | - family = dst_orig->ops->family; | ||
733 | - pols[0] = policy; | ||
734 | - npols ++; | ||
735 | - xfrm_nr += pols[0]->xfrm_nr; | ||
736 | - | ||
737 | - err = -ENOENT; | ||
738 | - if ((flags & XFRM_LOOKUP_ICMP) && !(policy->flags & XFRM_POLICY_ICMP)) | ||
739 | + if ((flags & XFRM_LOOKUP_ICMP) && | ||
740 | + !(pols[0]->flags & XFRM_POLICY_ICMP)) { | ||
741 | + err = -ENOENT; | ||
742 | goto error; | ||
743 | + } | ||
744 | |||
745 | - policy->curlft.use_time = get_seconds(); | ||
746 | + for (i = 0; i < num_pols; i++) | ||
747 | + pols[i]->curlft.use_time = get_seconds(); | ||
748 | |||
749 | - switch (policy->action) { | ||
750 | - default: | ||
751 | - case XFRM_POLICY_BLOCK: | ||
752 | + if (num_xfrms < 0) { | ||
753 | /* Prohibit the flow */ | ||
754 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK); | ||
755 | err = -EPERM; | ||
756 | goto error; | ||
757 | - | ||
758 | - case XFRM_POLICY_ALLOW: | ||
759 | -#ifndef CONFIG_XFRM_SUB_POLICY | ||
760 | - if (policy->xfrm_nr == 0) { | ||
761 | - /* Flow passes not transformed. */ | ||
762 | - xfrm_pol_put(policy); | ||
763 | - return 0; | ||
764 | - } | ||
765 | -#endif | ||
766 | - | ||
767 | - /* Try to find matching bundle. | ||
768 | - * | ||
769 | - * LATER: help from flow cache. It is optional, this | ||
770 | - * is required only for output policy. | ||
771 | - */ | ||
772 | - dst = xfrm_find_bundle(fl, policy, family); | ||
773 | - if (IS_ERR(dst)) { | ||
774 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | ||
775 | - err = PTR_ERR(dst); | ||
776 | - goto error; | ||
777 | - } | ||
778 | - | ||
779 | - if (dst) | ||
780 | - break; | ||
781 | - | ||
782 | -#ifdef CONFIG_XFRM_SUB_POLICY | ||
783 | - if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
784 | - pols[1] = xfrm_policy_lookup_bytype(net, | ||
785 | - XFRM_POLICY_TYPE_MAIN, | ||
786 | - fl, family, | ||
787 | - XFRM_POLICY_OUT); | ||
788 | - if (pols[1]) { | ||
789 | - if (IS_ERR(pols[1])) { | ||
790 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
791 | - err = PTR_ERR(pols[1]); | ||
792 | - goto error; | ||
793 | - } | ||
794 | - if (pols[1]->action == XFRM_POLICY_BLOCK) { | ||
795 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK); | ||
796 | - err = -EPERM; | ||
797 | - goto error; | ||
798 | - } | ||
799 | - npols ++; | ||
800 | - xfrm_nr += pols[1]->xfrm_nr; | ||
801 | - } | ||
802 | - } | ||
803 | - | ||
804 | - /* | ||
805 | - * Because neither flowi nor bundle information knows about | ||
806 | - * transformation template size. On more than one policy usage | ||
807 | - * we can realize whether all of them is bypass or not after | ||
808 | - * they are searched. See above not-transformed bypass | ||
809 | - * is surrounded by non-sub policy configuration, too. | ||
810 | - */ | ||
811 | - if (xfrm_nr == 0) { | ||
812 | - /* Flow passes not transformed. */ | ||
813 | - xfrm_pols_put(pols, npols); | ||
814 | - return 0; | ||
815 | - } | ||
816 | - | ||
817 | -#endif | ||
818 | - nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | ||
819 | - | ||
820 | - if (unlikely(nx<0)) { | ||
821 | - err = nx; | ||
822 | - if (err == -EAGAIN && net->xfrm.sysctl_larval_drop) { | ||
823 | - /* EREMOTE tells the caller to generate | ||
824 | - * a one-shot blackhole route. | ||
825 | - */ | ||
826 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | ||
827 | - xfrm_pol_put(policy); | ||
828 | - return -EREMOTE; | ||
829 | - } | ||
830 | - if (err == -EAGAIN && (flags & XFRM_LOOKUP_WAIT)) { | ||
831 | - DECLARE_WAITQUEUE(wait, current); | ||
832 | - | ||
833 | - add_wait_queue(&net->xfrm.km_waitq, &wait); | ||
834 | - set_current_state(TASK_INTERRUPTIBLE); | ||
835 | - schedule(); | ||
836 | - set_current_state(TASK_RUNNING); | ||
837 | - remove_wait_queue(&net->xfrm.km_waitq, &wait); | ||
838 | - | ||
839 | - nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | ||
840 | - | ||
841 | - if (nx == -EAGAIN && signal_pending(current)) { | ||
842 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | ||
843 | - err = -ERESTART; | ||
844 | - goto error; | ||
845 | - } | ||
846 | - if (nx == -EAGAIN || | ||
847 | - genid != atomic_read(&flow_cache_genid)) { | ||
848 | - xfrm_pols_put(pols, npols); | ||
849 | - goto restart; | ||
850 | - } | ||
851 | - err = nx; | ||
852 | - } | ||
853 | - if (err < 0) { | ||
854 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | ||
855 | - goto error; | ||
856 | - } | ||
857 | - } | ||
858 | - if (nx == 0) { | ||
859 | - /* Flow passes not transformed. */ | ||
860 | - xfrm_pols_put(pols, npols); | ||
861 | - return 0; | ||
862 | - } | ||
863 | - | ||
864 | - dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig); | ||
865 | - err = PTR_ERR(dst); | ||
866 | - if (IS_ERR(dst)) { | ||
867 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR); | ||
868 | - goto error; | ||
869 | - } | ||
870 | - | ||
871 | - for (pi = 0; pi < npols; pi++) | ||
872 | - pol_dead |= pols[pi]->walk.dead; | ||
873 | - | ||
874 | - write_lock_bh(&policy->lock); | ||
875 | - if (unlikely(pol_dead || stale_bundle(dst))) { | ||
876 | - /* Wow! While we worked on resolving, this | ||
877 | - * policy has gone. Retry. It is not paranoia, | ||
878 | - * we just cannot enlist new bundle to dead object. | ||
879 | - * We can't enlist stable bundles either. | ||
880 | - */ | ||
881 | - write_unlock_bh(&policy->lock); | ||
882 | - dst_free(dst); | ||
883 | - | ||
884 | - if (pol_dead) | ||
885 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLDEAD); | ||
886 | - else | ||
887 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | ||
888 | - err = -EHOSTUNREACH; | ||
889 | - goto error; | ||
890 | - } | ||
891 | - | ||
892 | - if (npols > 1) | ||
893 | - err = xfrm_dst_update_parent(dst, &pols[1]->selector); | ||
894 | - else | ||
895 | - err = xfrm_dst_update_origin(dst, fl); | ||
896 | - if (unlikely(err)) { | ||
897 | - write_unlock_bh(&policy->lock); | ||
898 | - dst_free(dst); | ||
899 | - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | ||
900 | - goto error; | ||
901 | - } | ||
902 | - | ||
903 | - dst->next = policy->bundles; | ||
904 | - policy->bundles = dst; | ||
905 | - dst_hold(dst); | ||
906 | - write_unlock_bh(&policy->lock); | ||
907 | + } else if (num_xfrms > 0) { | ||
908 | + /* Flow transformed */ | ||
909 | + *dst_p = dst; | ||
910 | + dst_release(dst_orig); | ||
911 | + } else { | ||
912 | + /* Flow passes untransformed */ | ||
913 | + dst_release(dst); | ||
914 | } | ||
915 | - *dst_p = dst; | ||
916 | - dst_release(dst_orig); | ||
917 | - xfrm_pols_put(pols, npols); | ||
918 | +ok: | ||
919 | + xfrm_pols_put(pols, drop_pols); | ||
920 | return 0; | ||
921 | |||
922 | +nopol: | ||
923 | + if (!(flags & XFRM_LOOKUP_ICMP)) | ||
924 | + goto ok; | ||
925 | + err = -ENOENT; | ||
926 | error: | ||
927 | - xfrm_pols_put(pols, npols); | ||
928 | + dst_release(dst); | ||
929 | dropdst: | ||
930 | dst_release(dst_orig); | ||
931 | *dst_p = NULL; | ||
932 | + xfrm_pols_put(pols, drop_pols); | ||
933 | return err; | ||
934 | - | ||
935 | -nopol: | ||
936 | - err = -ENOENT; | ||
937 | - if (flags & XFRM_LOOKUP_ICMP) | ||
938 | - goto dropdst; | ||
939 | - return 0; | ||
940 | } | ||
941 | EXPORT_SYMBOL(__xfrm_lookup); | ||
942 | |||
943 | @@ -2134,71 +2225,24 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) | ||
944 | return dst; | ||
945 | } | ||
946 | |||
947 | -static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p) | ||
948 | -{ | ||
949 | - struct dst_entry *dst, **dstp; | ||
950 | - | ||
951 | - write_lock(&pol->lock); | ||
952 | - dstp = &pol->bundles; | ||
953 | - while ((dst=*dstp) != NULL) { | ||
954 | - if (func(dst)) { | ||
955 | - *dstp = dst->next; | ||
956 | - dst->next = *gc_list_p; | ||
957 | - *gc_list_p = dst; | ||
958 | - } else { | ||
959 | - dstp = &dst->next; | ||
960 | - } | ||
961 | - } | ||
962 | - write_unlock(&pol->lock); | ||
963 | -} | ||
964 | - | ||
965 | -static void xfrm_prune_bundles(struct net *net, int (*func)(struct dst_entry *)) | ||
966 | +static void __xfrm_garbage_collect(struct net *net) | ||
967 | { | ||
968 | - struct dst_entry *gc_list = NULL; | ||
969 | - int dir; | ||
970 | + struct dst_entry *head, *next; | ||
971 | |||
972 | - read_lock_bh(&xfrm_policy_lock); | ||
973 | - for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
974 | - struct xfrm_policy *pol; | ||
975 | - struct hlist_node *entry; | ||
976 | - struct hlist_head *table; | ||
977 | - int i; | ||
978 | + flow_cache_flush(); | ||
979 | |||
980 | - hlist_for_each_entry(pol, entry, | ||
981 | - &net->xfrm.policy_inexact[dir], bydst) | ||
982 | - prune_one_bundle(pol, func, &gc_list); | ||
983 | + spin_lock_bh(&xfrm_policy_sk_bundle_lock); | ||
984 | + head = xfrm_policy_sk_bundles; | ||
985 | + xfrm_policy_sk_bundles = NULL; | ||
986 | + spin_unlock_bh(&xfrm_policy_sk_bundle_lock); | ||
987 | |||
988 | - table = net->xfrm.policy_bydst[dir].table; | ||
989 | - for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) { | ||
990 | - hlist_for_each_entry(pol, entry, table + i, bydst) | ||
991 | - prune_one_bundle(pol, func, &gc_list); | ||
992 | - } | ||
993 | - } | ||
994 | - read_unlock_bh(&xfrm_policy_lock); | ||
995 | - | ||
996 | - while (gc_list) { | ||
997 | - struct dst_entry *dst = gc_list; | ||
998 | - gc_list = dst->next; | ||
999 | - dst_free(dst); | ||
1000 | + while (head) { | ||
1001 | + next = head->next; | ||
1002 | + dst_free(head); | ||
1003 | + head = next; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | -static int unused_bundle(struct dst_entry *dst) | ||
1008 | -{ | ||
1009 | - return !atomic_read(&dst->__refcnt); | ||
1010 | -} | ||
1011 | - | ||
1012 | -static void __xfrm_garbage_collect(struct net *net) | ||
1013 | -{ | ||
1014 | - xfrm_prune_bundles(net, unused_bundle); | ||
1015 | -} | ||
1016 | - | ||
1017 | -static int xfrm_flush_bundles(struct net *net) | ||
1018 | -{ | ||
1019 | - xfrm_prune_bundles(net, stale_bundle); | ||
1020 | - return 0; | ||
1021 | -} | ||
1022 | - | ||
1023 | static void xfrm_init_pmtu(struct dst_entry *dst) | ||
1024 | { | ||
1025 | do { | ||
1026 | @@ -2256,7 +2300,9 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, | ||
1027 | return 0; | ||
1028 | if (dst->xfrm->km.state != XFRM_STATE_VALID) | ||
1029 | return 0; | ||
1030 | - if (xdst->genid != dst->xfrm->genid) | ||
1031 | + if (xdst->xfrm_genid != dst->xfrm->genid) | ||
1032 | + return 0; | ||
1033 | + if (xdst->policy_genid != atomic_read(&xdst->pols[0]->genid)) | ||
1034 | return 0; | ||
1035 | |||
1036 | if (strict && fl && | ||
1037 | @@ -2383,7 +2429,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void | ||
1038 | |||
1039 | switch (event) { | ||
1040 | case NETDEV_DOWN: | ||
1041 | - xfrm_flush_bundles(dev_net(dev)); | ||
1042 | + __xfrm_garbage_collect(dev_net(dev)); | ||
1043 | } | ||
1044 | return NOTIFY_DONE; | ||
1045 | } | ||
1046 | @@ -2714,7 +2760,6 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol, | ||
1047 | struct xfrm_migrate *m, int num_migrate) | ||
1048 | { | ||
1049 | struct xfrm_migrate *mp; | ||
1050 | - struct dst_entry *dst; | ||
1051 | int i, j, n = 0; | ||
1052 | |||
1053 | write_lock_bh(&pol->lock); | ||
1054 | @@ -2739,10 +2784,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol, | ||
1055 | sizeof(pol->xfrm_vec[i].saddr)); | ||
1056 | pol->xfrm_vec[i].encap_family = mp->new_family; | ||
1057 | /* flush bundles */ | ||
1058 | - while ((dst = pol->bundles) != NULL) { | ||
1059 | - pol->bundles = dst->next; | ||
1060 | - dst_free(dst); | ||
1061 | - } | ||
1062 | + atomic_inc(&pol->genid); | ||
1063 | } | ||
1064 | } | ||
1065 | |||
1066 | -- | ||
1067 | 1.7.0.2 | ||
1068 | |||
diff --git a/main/linux-grsec/0016-xfrm-remove-policy-garbage-collection.patch b/main/linux-grsec/0016-xfrm-remove-policy-garbage-collection.patch new file mode 100644 index 0000000000..4a45c7f40d --- /dev/null +++ b/main/linux-grsec/0016-xfrm-remove-policy-garbage-collection.patch | |||
@@ -0,0 +1,91 @@ | |||
1 | From 4c53c9239069f48ec9a86f8e596c163b72e8bc4d Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 7 Apr 2010 00:30:06 +0000 | ||
4 | Subject: [PATCH 16/18] xfrm: remove policy garbage collection | ||
5 | |||
6 | Policies are now properly reference counted and destroyed from | ||
7 | all code paths. The delayed gc is just an overhead now and can | ||
8 | be removed. | ||
9 | |||
10 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
11 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
12 | (cherry picked from commit 285ead175c5dd5075cab5b6c94f35a3e6c0a3ae6) | ||
13 | --- | ||
14 | net/xfrm/xfrm_policy.c | 39 +++++---------------------------------- | ||
15 | 1 files changed, 5 insertions(+), 34 deletions(-) | ||
16 | |||
17 | diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c | ||
18 | index 0379d82..5606841 100644 | ||
19 | --- a/net/xfrm/xfrm_policy.c | ||
20 | +++ b/net/xfrm/xfrm_policy.c | ||
21 | @@ -46,9 +46,6 @@ static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | ||
22 | |||
23 | static struct kmem_cache *xfrm_dst_cache __read_mostly; | ||
24 | |||
25 | -static HLIST_HEAD(xfrm_policy_gc_list); | ||
26 | -static DEFINE_SPINLOCK(xfrm_policy_gc_lock); | ||
27 | - | ||
28 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); | ||
29 | static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); | ||
30 | static void xfrm_init_pmtu(struct dst_entry *dst); | ||
31 | @@ -288,32 +285,6 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) | ||
32 | } | ||
33 | EXPORT_SYMBOL(xfrm_policy_destroy); | ||
34 | |||
35 | -static void xfrm_policy_gc_kill(struct xfrm_policy *policy) | ||
36 | -{ | ||
37 | - atomic_inc(&policy->genid); | ||
38 | - | ||
39 | - if (del_timer(&policy->timer)) | ||
40 | - atomic_dec(&policy->refcnt); | ||
41 | - | ||
42 | - xfrm_pol_put(policy); | ||
43 | -} | ||
44 | - | ||
45 | -static void xfrm_policy_gc_task(struct work_struct *work) | ||
46 | -{ | ||
47 | - struct xfrm_policy *policy; | ||
48 | - struct hlist_node *entry, *tmp; | ||
49 | - struct hlist_head gc_list; | ||
50 | - | ||
51 | - spin_lock_bh(&xfrm_policy_gc_lock); | ||
52 | - gc_list.first = xfrm_policy_gc_list.first; | ||
53 | - INIT_HLIST_HEAD(&xfrm_policy_gc_list); | ||
54 | - spin_unlock_bh(&xfrm_policy_gc_lock); | ||
55 | - | ||
56 | - hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst) | ||
57 | - xfrm_policy_gc_kill(policy); | ||
58 | -} | ||
59 | -static DECLARE_WORK(xfrm_policy_gc_work, xfrm_policy_gc_task); | ||
60 | - | ||
61 | /* Rule must be locked. Release descentant resources, announce | ||
62 | * entry dead. The rule must be unlinked from lists to the moment. | ||
63 | */ | ||
64 | @@ -322,11 +293,12 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | ||
65 | { | ||
66 | policy->walk.dead = 1; | ||
67 | |||
68 | - spin_lock_bh(&xfrm_policy_gc_lock); | ||
69 | - hlist_add_head(&policy->bydst, &xfrm_policy_gc_list); | ||
70 | - spin_unlock_bh(&xfrm_policy_gc_lock); | ||
71 | + atomic_inc(&policy->genid); | ||
72 | |||
73 | - schedule_work(&xfrm_policy_gc_work); | ||
74 | + if (del_timer(&policy->timer)) | ||
75 | + xfrm_pol_put(policy); | ||
76 | + | ||
77 | + xfrm_pol_put(policy); | ||
78 | } | ||
79 | |||
80 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; | ||
81 | @@ -2535,7 +2507,6 @@ static void xfrm_policy_fini(struct net *net) | ||
82 | audit_info.sessionid = -1; | ||
83 | audit_info.secid = 0; | ||
84 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); | ||
85 | - flush_work(&xfrm_policy_gc_work); | ||
86 | |||
87 | WARN_ON(!list_empty(&net->xfrm.policy_all)); | ||
88 | |||
89 | -- | ||
90 | 1.7.0.2 | ||
91 | |||
diff --git a/main/linux-grsec/0017-flow-delayed-deletion-of-flow-cache-entries.patch b/main/linux-grsec/0017-flow-delayed-deletion-of-flow-cache-entries.patch new file mode 100644 index 0000000000..7d17d41aed --- /dev/null +++ b/main/linux-grsec/0017-flow-delayed-deletion-of-flow-cache-entries.patch | |||
@@ -0,0 +1,231 @@ | |||
1 | From fede05e99e2d860e97bc877b8b77fb9e63f55cc8 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Wed, 7 Apr 2010 00:30:07 +0000 | ||
4 | Subject: [PATCH 17/18] flow: delayed deletion of flow cache entries | ||
5 | |||
6 | Speed up lookups by freeing flow cache entries later. After | ||
7 | virtualizing flow cache entry operations, the flow cache may now | ||
8 | end up calling policy or bundle destructor which can be slowish. | ||
9 | |||
10 | As gc_list is more effective with double linked list, the flow cache | ||
11 | is converted to use common hlist and list macroes where appropriate. | ||
12 | |||
13 | Signed-off-by: Timo Teras <timo.teras@iki.fi> | ||
14 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
15 | (cherry picked from commit 8e4795605d1e1b39113818ad7c147b8a867a1f6a) | ||
16 | --- | ||
17 | net/core/flow.c | 100 ++++++++++++++++++++++++++++++++++++++----------------- | ||
18 | 1 files changed, 69 insertions(+), 31 deletions(-) | ||
19 | |||
20 | diff --git a/net/core/flow.c b/net/core/flow.c | ||
21 | index 521df52..1619006 100644 | ||
22 | --- a/net/core/flow.c | ||
23 | +++ b/net/core/flow.c | ||
24 | @@ -26,7 +26,10 @@ | ||
25 | #include <linux/security.h> | ||
26 | |||
27 | struct flow_cache_entry { | ||
28 | - struct flow_cache_entry *next; | ||
29 | + union { | ||
30 | + struct hlist_node hlist; | ||
31 | + struct list_head gc_list; | ||
32 | + } u; | ||
33 | u16 family; | ||
34 | u8 dir; | ||
35 | u32 genid; | ||
36 | @@ -35,7 +38,7 @@ struct flow_cache_entry { | ||
37 | }; | ||
38 | |||
39 | struct flow_cache_percpu { | ||
40 | - struct flow_cache_entry **hash_table; | ||
41 | + struct hlist_head *hash_table; | ||
42 | int hash_count; | ||
43 | u32 hash_rnd; | ||
44 | int hash_rnd_recalc; | ||
45 | @@ -62,6 +65,9 @@ atomic_t flow_cache_genid = ATOMIC_INIT(0); | ||
46 | static struct flow_cache flow_cache_global; | ||
47 | static struct kmem_cache *flow_cachep; | ||
48 | |||
49 | +static DEFINE_SPINLOCK(flow_cache_gc_lock); | ||
50 | +static LIST_HEAD(flow_cache_gc_list); | ||
51 | + | ||
52 | #define flow_cache_hash_size(cache) (1 << (cache)->hash_shift) | ||
53 | #define FLOW_HASH_RND_PERIOD (10 * 60 * HZ) | ||
54 | |||
55 | @@ -86,38 +92,66 @@ static int flow_entry_valid(struct flow_cache_entry *fle) | ||
56 | return 1; | ||
57 | } | ||
58 | |||
59 | -static void flow_entry_kill(struct flow_cache *fc, | ||
60 | - struct flow_cache_percpu *fcp, | ||
61 | - struct flow_cache_entry *fle) | ||
62 | +static void flow_entry_kill(struct flow_cache_entry *fle) | ||
63 | { | ||
64 | if (fle->object) | ||
65 | fle->object->ops->delete(fle->object); | ||
66 | kmem_cache_free(flow_cachep, fle); | ||
67 | - fcp->hash_count--; | ||
68 | +} | ||
69 | + | ||
70 | +static void flow_cache_gc_task(struct work_struct *work) | ||
71 | +{ | ||
72 | + struct list_head gc_list; | ||
73 | + struct flow_cache_entry *fce, *n; | ||
74 | + | ||
75 | + INIT_LIST_HEAD(&gc_list); | ||
76 | + spin_lock_bh(&flow_cache_gc_lock); | ||
77 | + list_splice_tail_init(&flow_cache_gc_list, &gc_list); | ||
78 | + spin_unlock_bh(&flow_cache_gc_lock); | ||
79 | + | ||
80 | + list_for_each_entry_safe(fce, n, &gc_list, u.gc_list) | ||
81 | + flow_entry_kill(fce); | ||
82 | +} | ||
83 | +static DECLARE_WORK(flow_cache_gc_work, flow_cache_gc_task); | ||
84 | + | ||
85 | +static void flow_cache_queue_garbage(struct flow_cache_percpu *fcp, | ||
86 | + int deleted, struct list_head *gc_list) | ||
87 | +{ | ||
88 | + if (deleted) { | ||
89 | + fcp->hash_count -= deleted; | ||
90 | + spin_lock_bh(&flow_cache_gc_lock); | ||
91 | + list_splice_tail(gc_list, &flow_cache_gc_list); | ||
92 | + spin_unlock_bh(&flow_cache_gc_lock); | ||
93 | + schedule_work(&flow_cache_gc_work); | ||
94 | + } | ||
95 | } | ||
96 | |||
97 | static void __flow_cache_shrink(struct flow_cache *fc, | ||
98 | struct flow_cache_percpu *fcp, | ||
99 | int shrink_to) | ||
100 | { | ||
101 | - struct flow_cache_entry *fle, **flp; | ||
102 | - int i; | ||
103 | + struct flow_cache_entry *fle; | ||
104 | + struct hlist_node *entry, *tmp; | ||
105 | + LIST_HEAD(gc_list); | ||
106 | + int i, deleted = 0; | ||
107 | |||
108 | for (i = 0; i < flow_cache_hash_size(fc); i++) { | ||
109 | int saved = 0; | ||
110 | |||
111 | - flp = &fcp->hash_table[i]; | ||
112 | - while ((fle = *flp) != NULL) { | ||
113 | + hlist_for_each_entry_safe(fle, entry, tmp, | ||
114 | + &fcp->hash_table[i], u.hlist) { | ||
115 | if (saved < shrink_to && | ||
116 | flow_entry_valid(fle)) { | ||
117 | saved++; | ||
118 | - flp = &fle->next; | ||
119 | } else { | ||
120 | - *flp = fle->next; | ||
121 | - flow_entry_kill(fc, fcp, fle); | ||
122 | + deleted++; | ||
123 | + hlist_del(&fle->u.hlist); | ||
124 | + list_add_tail(&fle->u.gc_list, &gc_list); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | + | ||
129 | + flow_cache_queue_garbage(fcp, deleted, &gc_list); | ||
130 | } | ||
131 | |||
132 | static void flow_cache_shrink(struct flow_cache *fc, | ||
133 | @@ -182,7 +216,8 @@ flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
134 | { | ||
135 | struct flow_cache *fc = &flow_cache_global; | ||
136 | struct flow_cache_percpu *fcp; | ||
137 | - struct flow_cache_entry *fle, **head; | ||
138 | + struct flow_cache_entry *fle, *tfle; | ||
139 | + struct hlist_node *entry; | ||
140 | struct flow_cache_object *flo; | ||
141 | unsigned int hash; | ||
142 | |||
143 | @@ -200,12 +235,13 @@ flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
144 | flow_new_hash_rnd(fc, fcp); | ||
145 | |||
146 | hash = flow_hash_code(fc, fcp, key); | ||
147 | - head = &fcp->hash_table[hash]; | ||
148 | - for (fle = *head; fle; fle = fle->next) { | ||
149 | - if (fle->family == family && | ||
150 | - fle->dir == dir && | ||
151 | - flow_key_compare(key, &fle->key) == 0) | ||
152 | + hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { | ||
153 | + if (tfle->family == family && | ||
154 | + tfle->dir == dir && | ||
155 | + flow_key_compare(key, &tfle->key) == 0) { | ||
156 | + fle = tfle; | ||
157 | break; | ||
158 | + } | ||
159 | } | ||
160 | |||
161 | if (unlikely(!fle)) { | ||
162 | @@ -214,12 +250,11 @@ flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | ||
163 | |||
164 | fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); | ||
165 | if (fle) { | ||
166 | - fle->next = *head; | ||
167 | - *head = fle; | ||
168 | fle->family = family; | ||
169 | fle->dir = dir; | ||
170 | memcpy(&fle->key, key, sizeof(*key)); | ||
171 | fle->object = NULL; | ||
172 | + hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); | ||
173 | fcp->hash_count++; | ||
174 | } | ||
175 | } else if (likely(fle->genid == atomic_read(&flow_cache_genid))) { | ||
176 | @@ -262,23 +297,26 @@ static void flow_cache_flush_tasklet(unsigned long data) | ||
177 | struct flow_flush_info *info = (void *)data; | ||
178 | struct flow_cache *fc = info->cache; | ||
179 | struct flow_cache_percpu *fcp; | ||
180 | - int i; | ||
181 | + struct flow_cache_entry *fle; | ||
182 | + struct hlist_node *entry, *tmp; | ||
183 | + LIST_HEAD(gc_list); | ||
184 | + int i, deleted = 0; | ||
185 | |||
186 | fcp = per_cpu_ptr(fc->percpu, smp_processor_id()); | ||
187 | for (i = 0; i < flow_cache_hash_size(fc); i++) { | ||
188 | - struct flow_cache_entry *fle; | ||
189 | - | ||
190 | - fle = fcp->hash_table[i]; | ||
191 | - for (; fle; fle = fle->next) { | ||
192 | + hlist_for_each_entry_safe(fle, entry, tmp, | ||
193 | + &fcp->hash_table[i], u.hlist) { | ||
194 | if (flow_entry_valid(fle)) | ||
195 | continue; | ||
196 | |||
197 | - if (fle->object) | ||
198 | - fle->object->ops->delete(fle->object); | ||
199 | - fle->object = NULL; | ||
200 | + deleted++; | ||
201 | + hlist_del(&fle->u.hlist); | ||
202 | + list_add_tail(&fle->u.gc_list, &gc_list); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | + flow_cache_queue_garbage(fcp, deleted, &gc_list); | ||
207 | + | ||
208 | if (atomic_dec_and_test(&info->cpuleft)) | ||
209 | complete(&info->completion); | ||
210 | } | ||
211 | @@ -320,7 +358,7 @@ void flow_cache_flush(void) | ||
212 | static void __init flow_cache_cpu_prepare(struct flow_cache *fc, | ||
213 | struct flow_cache_percpu *fcp) | ||
214 | { | ||
215 | - fcp->hash_table = (struct flow_cache_entry **) | ||
216 | + fcp->hash_table = (struct hlist_head *) | ||
217 | __get_free_pages(GFP_KERNEL|__GFP_ZERO, fc->order); | ||
218 | if (!fcp->hash_table) | ||
219 | panic("NET: failed to allocate flow cache order %lu\n", fc->order); | ||
220 | @@ -354,7 +392,7 @@ static int flow_cache_init(struct flow_cache *fc) | ||
221 | |||
222 | for (order = 0; | ||
223 | (PAGE_SIZE << order) < | ||
224 | - (sizeof(struct flow_cache_entry *)*flow_cache_hash_size(fc)); | ||
225 | + (sizeof(struct hlist_head)*flow_cache_hash_size(fc)); | ||
226 | order++) | ||
227 | /* NOTHING */; | ||
228 | fc->order = order; | ||
229 | -- | ||
230 | 1.7.0.2 | ||
231 | |||
diff --git a/main/linux-grsec/0018-xfrm-Fix-crashes-in-xfrm_lookup.patch b/main/linux-grsec/0018-xfrm-Fix-crashes-in-xfrm_lookup.patch new file mode 100644 index 0000000000..6f0dc91286 --- /dev/null +++ b/main/linux-grsec/0018-xfrm-Fix-crashes-in-xfrm_lookup.patch | |||
@@ -0,0 +1,46 @@ | |||
1 | From e0c0800740cdf64fe7b121c2ef235c01f1957af0 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> | ||
3 | Date: Thu, 8 Apr 2010 11:27:42 -0700 | ||
4 | Subject: [PATCH 18/18] xfrm: Fix crashes in xfrm_lookup() | ||
5 | MIME-Version: 1.0 | ||
6 | Content-Type: text/plain; charset=UTF-8 | ||
7 | Content-Transfer-Encoding: 8bit | ||
8 | |||
9 | From: Timo Teräs <timo.teras@iki.fi> | ||
10 | |||
11 | Happens because CONFIG_XFRM_SUB_POLICY is not enabled, and one of | ||
12 | the helper functions I used did unexpected things in that case. | ||
13 | |||
14 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
15 | (cherry picked from commit e4077e018b5ead3de9951fc01d8bf12eeeeeefed) | ||
16 | --- | ||
17 | include/net/xfrm.h | 7 ------- | ||
18 | 1 files changed, 0 insertions(+), 7 deletions(-) | ||
19 | |||
20 | diff --git a/include/net/xfrm.h b/include/net/xfrm.h | ||
21 | index d51ef61..280f46f 100644 | ||
22 | --- a/include/net/xfrm.h | ||
23 | +++ b/include/net/xfrm.h | ||
24 | @@ -738,19 +738,12 @@ static inline void xfrm_pol_put(struct xfrm_policy *policy) | ||
25 | xfrm_policy_destroy(policy); | ||
26 | } | ||
27 | |||
28 | -#ifdef CONFIG_XFRM_SUB_POLICY | ||
29 | static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) | ||
30 | { | ||
31 | int i; | ||
32 | for (i = npols - 1; i >= 0; --i) | ||
33 | xfrm_pol_put(pols[i]); | ||
34 | } | ||
35 | -#else | ||
36 | -static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) | ||
37 | -{ | ||
38 | - xfrm_pol_put(pols[0]); | ||
39 | -} | ||
40 | -#endif | ||
41 | |||
42 | extern void __xfrm_state_destroy(struct xfrm_state *); | ||
43 | |||
44 | -- | ||
45 | 1.7.0.2 | ||
46 | |||
diff --git a/main/linux-grsec/APKBUILD b/main/linux-grsec/APKBUILD index 2b81673eaf..b514a1a5d7 100644 --- a/main/linux-grsec/APKBUILD +++ b/main/linux-grsec/APKBUILD | |||
@@ -4,7 +4,7 @@ _flavor=grsec | |||
4 | pkgname=linux-${_flavor} | 4 | pkgname=linux-${_flavor} |
5 | pkgver=2.6.32.11 | 5 | pkgver=2.6.32.11 |
6 | _kernver=2.6.32 | 6 | _kernver=2.6.32 |
7 | pkgrel=1 | 7 | pkgrel=2 |
8 | pkgdesc="Linux kernel with grsecurity" | 8 | pkgdesc="Linux kernel with grsecurity" |
9 | url=http://grsecurity.net | 9 | url=http://grsecurity.net |
10 | depends="mkinitfs linux-firmware" | 10 | depends="mkinitfs linux-firmware" |
@@ -15,12 +15,24 @@ install= | |||
15 | source="ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-$_kernver.tar.bz2 | 15 | source="ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-$_kernver.tar.bz2 |
16 | ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-$pkgver.bz2 | 16 | ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-$pkgver.bz2 |
17 | grsecurity-2.1.14-2.6.32.11-201004071936.patch | 17 | grsecurity-2.1.14-2.6.32.11-201004071936.patch |
18 | ip_gre.patch | 18 | 0001-grsec-revert-conflicting-flow-cache-changes.patch |
19 | ip_gre2.patch | 19 | 0002-gre-fix-hard-header-destination-address-checking.patch |
20 | arp.patch | 20 | 0003-ip_gre-include-route-header_len-in-max_headroom-calc.patch |
21 | xfrm-cache-size-revert.patch | 21 | 0004-arp-flush-arp-cache-on-device-change.patch |
22 | net-git-78f1cd-r8169-fix-broken-register-writes.patch | 22 | 0005-r8169-fix-broken-register-writes.patch |
23 | net-git-c0cd88-r8169-offical-fix-for-CVE-2009-4537-overlength-frame-DMAs.patch | 23 | 0006-r8169-offical-fix-for-CVE-2009-4537-overlength-frame.patch |
24 | 0007-r8169-Fix-rtl8169_rx_interrupt.patch | ||
25 | 0008-r8169-clean-up-my-printk-uglyness.patch | ||
26 | 0009-ipsec-Fix-bogus-bundle-flowi.patch | ||
27 | 0010-xfrm-Remove-xfrm_state_genid.patch | ||
28 | 0011-xfrm_user-verify-policy-direction-at-XFRM_MSG_POLEXP.patch | ||
29 | 0012-xfrm-remove-policy-lock-when-accessing-policy-walk.d.patch | ||
30 | 0013-flow-structurize-flow-cache.patch | ||
31 | 0014-flow-virtualize-flow-cache-entry-methods.patch | ||
32 | 0015-xfrm-cache-bundles-instead-of-policies-for-outgoing-.patch | ||
33 | 0016-xfrm-remove-policy-garbage-collection.patch | ||
34 | 0017-flow-delayed-deletion-of-flow-cache-entries.patch | ||
35 | 0018-xfrm-Fix-crashes-in-xfrm_lookup.patch | ||
24 | kernelconfig.x86 | 36 | kernelconfig.x86 |
25 | " | 37 | " |
26 | subpackages="$pkgname-dev linux-firmware:firmware" | 38 | subpackages="$pkgname-dev linux-firmware:firmware" |
@@ -34,7 +46,8 @@ prepare() { | |||
34 | bunzip2 -c < ../patch-$pkgver.bz2 | patch -p1 -N || return 1 | 46 | bunzip2 -c < ../patch-$pkgver.bz2 | patch -p1 -N || return 1 |
35 | fi | 47 | fi |
36 | 48 | ||
37 | for i in ../*.diff ../*.patch; do | 49 | # first apply the grsecurity patch and then the rest |
50 | for i in "$srcdir"/grsecurity*.patch "$srcdir"/0[0-9]*.patch; do | ||
38 | [ -f $i ] || continue | 51 | [ -f $i ] || continue |
39 | msg "Applying $i..." | 52 | msg "Applying $i..." |
40 | patch -s -p1 -N < $i || return 1 | 53 | patch -s -p1 -N < $i || return 1 |
@@ -127,10 +140,22 @@ firmware() { | |||
127 | md5sums="260551284ac224c3a43c4adac7df4879 linux-2.6.32.tar.bz2 | 140 | md5sums="260551284ac224c3a43c4adac7df4879 linux-2.6.32.tar.bz2 |
128 | 855c248334a71ef5ca3d8cb89d51334f patch-2.6.32.11.bz2 | 141 | 855c248334a71ef5ca3d8cb89d51334f patch-2.6.32.11.bz2 |
129 | 6eabb0c08a988a97a823b5462d1c5018 grsecurity-2.1.14-2.6.32.11-201004071936.patch | 142 | 6eabb0c08a988a97a823b5462d1c5018 grsecurity-2.1.14-2.6.32.11-201004071936.patch |
130 | 3ef822f3a2723b9a80c3f12954457225 ip_gre.patch | 143 | 1d247140abec49b96250aec9aa59b324 0001-grsec-revert-conflicting-flow-cache-changes.patch |
131 | 13ca9e91700e459da269c957062bbea7 ip_gre2.patch | 144 | 437317f88ec13ace8d39c31983a41696 0002-gre-fix-hard-header-destination-address-checking.patch |
132 | 4c39a161d918e7f274292ecfd168b891 arp.patch | 145 | 151b29a161178ed39d62a08f21f3484d 0003-ip_gre-include-route-header_len-in-max_headroom-calc.patch |
133 | 329fcab881425e001d3243caa4648478 xfrm-cache-size-revert.patch | 146 | 776adeeb5272093574f8836c5037dd7d 0004-arp-flush-arp-cache-on-device-change.patch |
134 | 21ed38773d846097b7315e1e0801d87a net-git-78f1cd-r8169-fix-broken-register-writes.patch | 147 | afa06334c81f21c20571286a83d3d928 0005-r8169-fix-broken-register-writes.patch |
135 | 962a6dd7c639612fc8bdaeb836388b0b net-git-c0cd88-r8169-offical-fix-for-CVE-2009-4537-overlength-frame-DMAs.patch | 148 | c538c0f735d79fd71b47dde02bf1f790 0006-r8169-offical-fix-for-CVE-2009-4537-overlength-frame.patch |
149 | 5f8b9a76d95319c5b1aa26b54a42e6b5 0007-r8169-Fix-rtl8169_rx_interrupt.patch | ||
150 | f878c802700e3babd03be3505119c5c2 0008-r8169-clean-up-my-printk-uglyness.patch | ||
151 | cf168620efa63479a6e03da78906e32f 0009-ipsec-Fix-bogus-bundle-flowi.patch | ||
152 | 3af4b5ae1afae3278b0070f585b874e3 0010-xfrm-Remove-xfrm_state_genid.patch | ||
153 | 9f284c3fd5ab38cef4544efc1f50c6ba 0011-xfrm_user-verify-policy-direction-at-XFRM_MSG_POLEXP.patch | ||
154 | b035114e893883cf67530350678e00f5 0012-xfrm-remove-policy-lock-when-accessing-policy-walk.d.patch | ||
155 | 9dea03ec19aaf9a384e4f56f57009257 0013-flow-structurize-flow-cache.patch | ||
156 | fc9ab26abbfec0d3f20000b5e695620b 0014-flow-virtualize-flow-cache-entry-methods.patch | ||
157 | c09b82b89a49ba2a3836a0bc3a3312f4 0015-xfrm-cache-bundles-instead-of-policies-for-outgoing-.patch | ||
158 | 41618efb65ab9ddacfb59a1cde9b4edd 0016-xfrm-remove-policy-garbage-collection.patch | ||
159 | 3b83f0972ab715819d1119b120a987e7 0017-flow-delayed-deletion-of-flow-cache-entries.patch | ||
160 | 45a676c7a1759fec60b724d557b4e295 0018-xfrm-Fix-crashes-in-xfrm_lookup.patch | ||
136 | 7f442049b29ab749180e54ff8f20f1d0 kernelconfig.x86" | 161 | 7f442049b29ab749180e54ff8f20f1d0 kernelconfig.x86" |
diff --git a/main/linux-grsec/arp.patch b/main/linux-grsec/arp.patch deleted file mode 100644 index d2682690f5..0000000000 --- a/main/linux-grsec/arp.patch +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c | ||
2 | index c95cd93..71ab56f 100644 | ||
3 | --- a/net/ipv4/arp.c | ||
4 | +++ b/net/ipv4/arp.c | ||
5 | @@ -1200,6 +1200,9 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo | ||
6 | neigh_changeaddr(&arp_tbl, dev); | ||
7 | rt_cache_flush(dev_net(dev), 0); | ||
8 | break; | ||
9 | + case NETDEV_CHANGE: | ||
10 | + neigh_changeaddr(&arp_tbl, dev); | ||
11 | + break; | ||
12 | default: | ||
13 | break; | ||
14 | } | ||
diff --git a/main/linux-grsec/ip_gre.patch b/main/linux-grsec/ip_gre.patch deleted file mode 100644 index ba5f19b300..0000000000 --- a/main/linux-grsec/ip_gre.patch +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | --- a/net/ipv4/ip_gre.c.orig | ||
2 | +++ b/net/ipv4/ip_gre.c | ||
3 | @@ -1137,11 +1137,8 @@ | ||
4 | |||
5 | if (saddr) | ||
6 | memcpy(&iph->saddr, saddr, 4); | ||
7 | - | ||
8 | - if (daddr) { | ||
9 | + if (daddr) | ||
10 | memcpy(&iph->daddr, daddr, 4); | ||
11 | - return t->hlen; | ||
12 | - } | ||
13 | if (iph->daddr && !ipv4_is_multicast(iph->daddr)) | ||
14 | return t->hlen; | ||
15 | |||
diff --git a/main/linux-grsec/ip_gre2.patch b/main/linux-grsec/ip_gre2.patch deleted file mode 100644 index 52c44076d2..0000000000 --- a/main/linux-grsec/ip_gre2.patch +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | --- linux-2.6.32/net/ipv4/ip_gre.c.orig | ||
2 | +++ linux-2.6.32/net/ipv4/ip_gre.c | ||
3 | @@ -803,11 +803,13 @@ | ||
4 | tunnel->err_count = 0; | ||
5 | } | ||
6 | |||
7 | - max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen; | ||
8 | + max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->u.dst.header_len; | ||
9 | |||
10 | if (skb_headroom(skb) < max_headroom || skb_shared(skb)|| | ||
11 | (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { | ||
12 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); | ||
13 | + if (max_headroom > dev->needed_headroom) | ||
14 | + dev->needed_headroom = max_headroom; | ||
15 | if (!new_skb) { | ||
16 | ip_rt_put(rt); | ||
17 | stats->tx_dropped++; | ||