* netfilter 01/06: ebtables: use nf_register_hooks()
2008-07-26 23:37 netfilter 00/06: netfilter update Patrick McHardy
@ 2008-07-26 23:37 ` Patrick McHardy
2008-07-27 0:48 ` David Miller
2008-07-26 23:37 ` selinux 02/06: " Patrick McHardy
` (4 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-07-26 23:37 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
netfilter: ebtables: use nf_register_hooks()
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 1560ab44b64937c854fedbfedc80a7f2ae491436
tree 530ee8dd17ba9685ab9c9aa8a54ed257e90d233c
parent 7d7e5a60c62e88cb8782760bb6c4d3bd1577a6c6
author Alexey Dobriyan <adobriyan@gmail.com> Sun, 27 Jul 2008 00:37:24 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 27 Jul 2008 00:37:24 +0200
net/bridge/netfilter/ebtable_filter.c | 18 +++++-------------
net/bridge/netfilter/ebtable_nat.c | 18 +++++-------------
2 files changed, 10 insertions(+), 26 deletions(-)
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 690bc3a..1a58af5 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -93,28 +93,20 @@ static struct nf_hook_ops ebt_ops_filter[] __read_mostly = {
static int __init ebtable_filter_init(void)
{
- int i, j, ret;
+ int ret;
ret = ebt_register_table(&frame_filter);
if (ret < 0)
return ret;
- for (i = 0; i < ARRAY_SIZE(ebt_ops_filter); i++)
- if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0)
- goto cleanup;
- return ret;
-cleanup:
- for (j = 0; j < i; j++)
- nf_unregister_hook(&ebt_ops_filter[j]);
- ebt_unregister_table(&frame_filter);
+ ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
+ if (ret < 0)
+ ebt_unregister_table(&frame_filter);
return ret;
}
static void __exit ebtable_filter_fini(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ebt_ops_filter); i++)
- nf_unregister_hook(&ebt_ops_filter[i]);
+ nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
ebt_unregister_table(&frame_filter);
}
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 5b495fe..f60c1e7 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -100,28 +100,20 @@ static struct nf_hook_ops ebt_ops_nat[] __read_mostly = {
static int __init ebtable_nat_init(void)
{
- int i, ret, j;
+ int ret;
ret = ebt_register_table(&frame_nat);
if (ret < 0)
return ret;
- for (i = 0; i < ARRAY_SIZE(ebt_ops_nat); i++)
- if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0)
- goto cleanup;
- return ret;
-cleanup:
- for (j = 0; j < i; j++)
- nf_unregister_hook(&ebt_ops_nat[j]);
- ebt_unregister_table(&frame_nat);
+ ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
+ if (ret < 0)
+ ebt_unregister_table(&frame_nat);
return ret;
}
static void __exit ebtable_nat_fini(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ebt_ops_nat); i++)
- nf_unregister_hook(&ebt_ops_nat[i]);
+ nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
ebt_unregister_table(&frame_nat);
}
^ permalink raw reply related [flat|nested] 13+ messages in thread* selinux 02/06: use nf_register_hooks()
2008-07-26 23:37 netfilter 00/06: netfilter update Patrick McHardy
2008-07-26 23:37 ` netfilter 01/06: ebtables: use nf_register_hooks() Patrick McHardy
@ 2008-07-26 23:37 ` Patrick McHardy
2008-07-27 0:48 ` David Miller
2008-07-26 23:37 ` netfilter 03/06: ip{,6}tables_security: fix future section mismatch Patrick McHardy
` (3 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-07-26 23:37 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
selinux: use nf_register_hooks()
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Acked-by: James Morris <jmorris@namei.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 0b2ece9450ccf5ab814cc8d3520f6977db184e28
tree 3d55f92f34e54fb29885979946c1cc9350e09620
parent 1560ab44b64937c854fedbfedc80a7f2ae491436
author Alexey Dobriyan <adobriyan@gmail.com> Sun, 27 Jul 2008 00:40:02 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 27 Jul 2008 00:40:02 +0200
security/selinux/hooks.c | 27 ++++++++-------------------
1 files changed, 8 insertions(+), 19 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 63f131f..df0515d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5670,27 +5670,20 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
static int __init selinux_nf_ip_init(void)
{
int err = 0;
- u32 iter;
if (!selinux_enabled)
goto out;
printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
- for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) {
- err = nf_register_hook(&selinux_ipv4_ops[iter]);
- if (err)
- panic("SELinux: nf_register_hook for IPv4: error %d\n",
- err);
- }
+ err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
+ if (err)
+ panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) {
- err = nf_register_hook(&selinux_ipv6_ops[iter]);
- if (err)
- panic("SELinux: nf_register_hook for IPv6: error %d\n",
- err);
- }
+ err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
+ if (err)
+ panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
#endif /* IPV6 */
out:
@@ -5702,15 +5695,11 @@ __initcall(selinux_nf_ip_init);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
static void selinux_nf_ip_exit(void)
{
- u32 iter;
-
printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
- for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++)
- nf_unregister_hook(&selinux_ipv4_ops[iter]);
+ nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++)
- nf_unregister_hook(&selinux_ipv6_ops[iter]);
+ nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
#endif /* IPV6 */
}
#endif
^ permalink raw reply related [flat|nested] 13+ messages in thread* netfilter 03/06: ip{,6}tables_security: fix future section mismatch
2008-07-26 23:37 netfilter 00/06: netfilter update Patrick McHardy
2008-07-26 23:37 ` netfilter 01/06: ebtables: use nf_register_hooks() Patrick McHardy
2008-07-26 23:37 ` selinux 02/06: " Patrick McHardy
@ 2008-07-26 23:37 ` Patrick McHardy
2008-07-27 0:48 ` David Miller
2008-07-26 23:37 ` netfilter 04/06: arptables in netns for real Patrick McHardy
` (2 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-07-26 23:37 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
netfilter: ip{,6}tables_security: fix future section mismatch
Currently not visible, because NET_NS is mutually exclusive with SYSFS
which is required by SECURITY.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 3e7770f4574672e7e6122b0dee21faf325d7b6a3
tree 7f564b32d493aa1e24040ae76a6510576a908818
parent 0b2ece9450ccf5ab814cc8d3520f6977db184e28
author Alexey Dobriyan <adobriyan@gmail.com> Sun, 27 Jul 2008 00:40:13 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 27 Jul 2008 00:40:13 +0200
net/ipv4/netfilter/iptable_security.c | 2 +-
net/ipv6/netfilter/ip6table_security.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index 2b472ac..db6d312 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -32,7 +32,7 @@ static struct
struct ipt_replace repl;
struct ipt_standard entries[3];
struct ipt_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
.repl = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index a07abee..6e71310 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -31,7 +31,7 @@ static struct
struct ip6t_replace repl;
struct ip6t_standard entries[3];
struct ip6t_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
.repl = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
^ permalink raw reply related [flat|nested] 13+ messages in thread* netfilter 04/06: arptables in netns for real
2008-07-26 23:37 netfilter 00/06: netfilter update Patrick McHardy
` (2 preceding siblings ...)
2008-07-26 23:37 ` netfilter 03/06: ip{,6}tables_security: fix future section mismatch Patrick McHardy
@ 2008-07-26 23:37 ` Patrick McHardy
2008-07-27 0:49 ` David Miller
2008-07-26 23:37 ` netfilter 05/06: fix double-free and use-after free Patrick McHardy
2008-07-26 23:37 ` netfilter 06/06: nf_conntrack_extend: avoid unnecessary "ct->ext" dereferences Patrick McHardy
5 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-07-26 23:37 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
netfilter: arptables in netns for real
IN, FORWARD -- grab netns from in device, OUT -- from out device.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit ea52606851cacfc5bcd6437ac0d97a22494279ac
tree 7929d1eb7468fd9f875bc1d248c0610a9197fe88
parent 3e7770f4574672e7e6122b0dee21faf325d7b6a3
author Alexey Dobriyan <adobriyan@gmail.com> Sun, 27 Jul 2008 00:40:13 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 27 Jul 2008 00:40:13 +0200
net/ipv4/netfilter/arptable_filter.c | 39 ++++++++++++++++++++++++++--------
1 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 3be4d07..082f5dd 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -55,32 +55,53 @@ static struct xt_table packet_filter = {
};
/* The work comes in here from netfilter.c */
-static unsigned int arpt_hook(unsigned int hook,
- struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+static unsigned int arpt_in_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
{
- return arpt_do_table(skb, hook, in, out, init_net.ipv4.arptable_filter);
+ return arpt_do_table(skb, hook, in, out,
+ dev_net(in)->ipv4.arptable_filter);
+}
+
+static unsigned int arpt_out_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return arpt_do_table(skb, hook, in, out,
+ dev_net(out)->ipv4.arptable_filter);
+}
+
+static unsigned int arpt_forward_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return arpt_do_table(skb, hook, in, out,
+ dev_net(in)->ipv4.arptable_filter);
}
static struct nf_hook_ops arpt_ops[] __read_mostly = {
{
- .hook = arpt_hook,
+ .hook = arpt_in_hook,
.owner = THIS_MODULE,
.pf = NF_ARP,
.hooknum = NF_ARP_IN,
.priority = NF_IP_PRI_FILTER,
},
{
- .hook = arpt_hook,
+ .hook = arpt_out_hook,
.owner = THIS_MODULE,
.pf = NF_ARP,
.hooknum = NF_ARP_OUT,
.priority = NF_IP_PRI_FILTER,
},
{
- .hook = arpt_hook,
+ .hook = arpt_forward_hook,
.owner = THIS_MODULE,
.pf = NF_ARP,
.hooknum = NF_ARP_FORWARD,
^ permalink raw reply related [flat|nested] 13+ messages in thread* netfilter 05/06: fix double-free and use-after free
2008-07-26 23:37 netfilter 00/06: netfilter update Patrick McHardy
` (3 preceding siblings ...)
2008-07-26 23:37 ` netfilter 04/06: arptables in netns for real Patrick McHardy
@ 2008-07-26 23:37 ` Patrick McHardy
2008-07-27 0:49 ` David Miller
2008-07-26 23:37 ` netfilter 06/06: nf_conntrack_extend: avoid unnecessary "ct->ext" dereferences Patrick McHardy
5 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-07-26 23:37 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
netfilter: fix double-free and use-after free
As suggested by Patrick McHardy, introduce a __krealloc() that doesn't
free the original buffer to fix a double-free and use-after-free bug
introduced by me in netfilter that uses RCU.
Reported-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
Tested-by: Dieter Ries <clip2@gmx.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit dfecb922fa57237ef11bad7b95cbbceb5fdaccce
tree 37d85ce138cda2eca377980bbf110ec6826f77fe
parent ea52606851cacfc5bcd6437ac0d97a22494279ac
author Pekka Enberg <penberg@cs.helsinki.fi> Sun, 27 Jul 2008 00:40:14 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 27 Jul 2008 00:40:14 +0200
include/linux/slab.h | 1 +
mm/util.c | 44 +++++++++++++++++++++++++++--------
net/netfilter/nf_conntrack_extend.c | 2 +-
3 files changed, 36 insertions(+), 11 deletions(-)
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 9aa90a6..be6f1d4 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -96,6 +96,7 @@ int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
/*
* Common kmalloc functions provided by all allocators
*/
+void * __must_check __krealloc(const void *, size_t, gfp_t);
void * __must_check krealloc(const void *, size_t, gfp_t);
void kfree(const void *);
size_t ksize(const void *);
diff --git a/mm/util.c b/mm/util.c
index 8f18683..6ef9e99 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -68,25 +68,22 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
EXPORT_SYMBOL(kmemdup);
/**
- * krealloc - reallocate memory. The contents will remain unchanged.
+ * __krealloc - like krealloc() but don't free @p.
* @p: object to reallocate memory for.
* @new_size: how many bytes of memory are required.
* @flags: the type of memory to allocate.
*
- * The contents of the object pointed to are preserved up to the
- * lesser of the new and old sizes. If @p is %NULL, krealloc()
- * behaves exactly like kmalloc(). If @size is 0 and @p is not a
- * %NULL pointer, the object pointed to is freed.
+ * This function is like krealloc() except it never frees the originally
+ * allocated buffer. Use this if you don't want to free the buffer immediately
+ * like, for example, with RCU.
*/
-void *krealloc(const void *p, size_t new_size, gfp_t flags)
+void *__krealloc(const void *p, size_t new_size, gfp_t flags)
{
void *ret;
size_t ks = 0;
- if (unlikely(!new_size)) {
- kfree(p);
+ if (unlikely(!new_size))
return ZERO_SIZE_PTR;
- }
if (p)
ks = ksize(p);
@@ -95,10 +92,37 @@ void *krealloc(const void *p, size_t new_size, gfp_t flags)
return (void *)p;
ret = kmalloc_track_caller(new_size, flags);
- if (ret && p) {
+ if (ret && p)
memcpy(ret, p, ks);
+
+ return ret;
+}
+EXPORT_SYMBOL(__krealloc);
+
+/**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes. If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc(). If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+
+ if (unlikely(!new_size)) {
kfree(p);
+ return ZERO_SIZE_PTR;
}
+
+ ret = __krealloc(p, new_size, flags);
+ if (ret && p != ret)
+ kfree(p);
+
return ret;
}
EXPORT_SYMBOL(krealloc);
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index 3469bc7..c956ef7 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -95,7 +95,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
newlen = newoff + t->len;
rcu_read_unlock();
- new = krealloc(ct->ext, newlen, gfp);
+ new = __krealloc(ct->ext, newlen, gfp);
if (!new)
return NULL;
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: netfilter 05/06: fix double-free and use-after free
2008-07-26 23:37 ` netfilter 05/06: fix double-free and use-after free Patrick McHardy
@ 2008-07-27 0:49 ` David Miller
0 siblings, 0 replies; 13+ messages in thread
From: David Miller @ 2008-07-27 0:49 UTC (permalink / raw)
To: kaber; +Cc: netfilter-devel
From: Patrick McHardy <kaber@trash.net>
Date: Sun, 27 Jul 2008 01:37:14 +0200 (MEST)
> netfilter: fix double-free and use-after free
>
> As suggested by Patrick McHardy, introduce a __krealloc() that doesn't
> free the original buffer to fix a double-free and use-after-free bug
> introduced by me in netfilter that uses RCU.
>
> Reported-by: Patrick McHardy <kaber@trash.net>
> Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
> Tested-by: Dieter Ries <clip2@gmx.de>
> Signed-off-by: Patrick McHardy <kaber@trash.net>
Applied.
^ permalink raw reply [flat|nested] 13+ messages in thread
* netfilter 06/06: nf_conntrack_extend: avoid unnecessary "ct->ext" dereferences
2008-07-26 23:37 netfilter 00/06: netfilter update Patrick McHardy
` (4 preceding siblings ...)
2008-07-26 23:37 ` netfilter 05/06: fix double-free and use-after free Patrick McHardy
@ 2008-07-26 23:37 ` Patrick McHardy
2008-07-27 0:50 ` David Miller
5 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-07-26 23:37 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
netfilter: nf_conntrack_extend: avoid unnecessary "ct->ext" dereferences
As Linus points out, "ct->ext" and "new" are always equal, avoid unnecessary
dereferences and use "new" directly.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit d928bf64722c65a7723ebff4161c4ca1256db6cf
tree 0f9bf278b49529096f187b48b286f4dbe3c289b5
parent dfecb922fa57237ef11bad7b95cbbceb5fdaccce
author Patrick McHardy <kaber@trash.net> Sun, 27 Jul 2008 00:40:14 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 27 Jul 2008 00:40:14 +0200
net/netfilter/nf_conntrack_extend.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index c956ef7..4b2c769 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -115,10 +115,10 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
ct->ext = new;
}
- ct->ext->offset[id] = newoff;
- ct->ext->len = newlen;
- memset((void *)ct->ext + newoff, 0, newlen - newoff);
- return (void *)ct->ext + newoff;
+ new->offset[id] = newoff;
+ new->len = newlen;
+ memset((void *)new + newoff, 0, newlen - newoff);
+ return (void *)new + newoff;
}
EXPORT_SYMBOL(__nf_ct_ext_add);
^ permalink raw reply related [flat|nested] 13+ messages in thread