* [PATCH net-next] net: dsa: remove tree refcount
@ 2017-11-09 17:36 Vivien Didelot
2017-11-09 18:10 ` Andrew Lunn
0 siblings, 1 reply; 3+ messages in thread
From: Vivien Didelot @ 2017-11-09 17:36 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
Stephen Rothwell, lkp, Vivien Didelot
Setting the refcount to 0 when allocating a tree to match the number of
switch devices it holds may cause an 'increment on 0; use-after-free'.
Tracking the number of devices in a tree with a kref is not really
appropriate anyway so removes it completely in favor of a basic counter.
Fixes: 8e5bf9759a06 ("net: dsa: simplify tree reference counting")
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
include/net/dsa.h | 2 +-
net/dsa/dsa2.c | 29 ++++-------------------------
2 files changed, 5 insertions(+), 26 deletions(-)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 35b5dee7bb23..bbcdff43526f 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -119,7 +119,7 @@ struct dsa_switch_tree {
unsigned int index;
/* Number of switches attached to this tree */
- struct kref refcount;
+ unsigned int nr_devices;
/* Has this tree been applied to the hardware? */
bool setup;
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index fd54a8e17986..fda3e5415eaf 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -51,10 +51,6 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index)
INIT_LIST_HEAD(&dst->list);
list_add_tail(&dsa_tree_list, &dst->list);
- /* Initialize the reference counter to the number of switches, not 1 */
- kref_init(&dst->refcount);
- refcount_set(&dst->refcount.refcount, 0);
-
return dst;
}
@@ -75,25 +71,6 @@ static struct dsa_switch_tree *dsa_tree_touch(int index)
return dst;
}
-static void dsa_tree_get(struct dsa_switch_tree *dst)
-{
- kref_get(&dst->refcount);
-}
-
-static void dsa_tree_release(struct kref *ref)
-{
- struct dsa_switch_tree *dst;
-
- dst = container_of(ref, struct dsa_switch_tree, refcount);
-
- dsa_tree_free(dst);
-}
-
-static void dsa_tree_put(struct dsa_switch_tree *dst)
-{
- kref_put(&dst->refcount, dsa_tree_release);
-}
-
static bool dsa_port_is_dsa(struct dsa_port *port)
{
return port->type == DSA_PORT_TYPE_DSA;
@@ -492,7 +469,9 @@ static void dsa_tree_remove_switch(struct dsa_switch_tree *dst,
dsa_tree_teardown(dst);
dst->ds[index] = NULL;
- dsa_tree_put(dst);
+ dst->nr_devices--;
+ if (!dst->nr_devices)
+ dsa_tree_free(dst);
}
static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
@@ -504,7 +483,7 @@ static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
if (dst->ds[index])
return -EBUSY;
- dsa_tree_get(dst);
+ dst->nr_devices++;
dst->ds[index] = ds;
err = dsa_tree_setup(dst);
--
2.15.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH net-next] net: dsa: remove tree refcount
2017-11-09 17:36 [PATCH net-next] net: dsa: remove tree refcount Vivien Didelot
@ 2017-11-09 18:10 ` Andrew Lunn
2017-11-09 18:24 ` Vivien Didelot
0 siblings, 1 reply; 3+ messages in thread
From: Andrew Lunn @ 2017-11-09 18:10 UTC (permalink / raw)
To: Vivien Didelot
Cc: netdev, linux-kernel, kernel, David S. Miller, Florian Fainelli,
Stephen Rothwell, lkp
On Thu, Nov 09, 2017 at 12:36:52PM -0500, Vivien Didelot wrote:
> Setting the refcount to 0 when allocating a tree to match the number of
> switch devices it holds may cause an 'increment on 0; use-after-free'.
>
> Tracking the number of devices in a tree with a kref is not really
> appropriate anyway so removes it completely in favor of a basic counter.
Hi Vivien
How are you protecting this basic counter? switches can come and go at
random, modules are loaded and unloaded, probing can happen in
parallel, probes can fail with EPROBE_DEFFER causing a switch to
unregister itself while others are registering themselves, etc.
The point of using a kref is that it is a well known kernel method of
safely handling this situation. When the last member of the tree goes
away, we safely and atomically remove the tree. It worked well for a
few years, until you refactored it. Maybe the correct solution is to
revert your change?
Andrew
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net-next] net: dsa: remove tree refcount
2017-11-09 18:10 ` Andrew Lunn
@ 2017-11-09 18:24 ` Vivien Didelot
0 siblings, 0 replies; 3+ messages in thread
From: Vivien Didelot @ 2017-11-09 18:24 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, linux-kernel, kernel, David S. Miller, Florian Fainelli,
Stephen Rothwell, lkp
Hi Andrew,
Andrew Lunn <andrew@lunn.ch> writes:
> On Thu, Nov 09, 2017 at 12:36:52PM -0500, Vivien Didelot wrote:
>> Setting the refcount to 0 when allocating a tree to match the number of
>> switch devices it holds may cause an 'increment on 0; use-after-free'.
>>
>> Tracking the number of devices in a tree with a kref is not really
>> appropriate anyway so removes it completely in favor of a basic counter.
>
> How are you protecting this basic counter? switches can come and go at
> random, modules are loaded and unloaded, probing can happen in
> parallel, probes can fail with EPROBE_DEFFER causing a switch to
> unregister itself while others are registering themselves, etc.
As for the kref, the counter is protected by dsa2_mutex which locks
switch registration, nothing changed.
> The point of using a kref is that it is a well known kernel method of
> safely handling this situation. When the last member of the tree goes
> away, we safely and atomically remove the tree. It worked well for a
> few years, until you refactored it. Maybe the correct solution is to
> revert your change?
The kref doesn't add any value here and make the code more complex. If
you prefer to keep it, a simple alternative can be provided to init the
refcount to 1 at initialization and decrement it after registration:
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index fd54a8e17986..1fb8beb66493 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -51,9 +51,7 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index)
INIT_LIST_HEAD(&dst->list);
list_add_tail(&dsa_tree_list, &dst->list);
- /* Initialize the reference counter to the number of switches, not 1 */
kref_init(&dst->refcount);
- refcount_set(&dst->refcount.refcount, 0);
return dst;
}
@@ -69,7 +67,9 @@ static struct dsa_switch_tree *dsa_tree_touch(int index)
struct dsa_switch_tree *dst;
dst = dsa_tree_find(index);
- if (!dst)
+ if (dst)
+ dsa_tree_get(dst);
+ else
dst = dsa_tree_alloc(index);
return dst;
@@ -765,6 +765,8 @@ int dsa_register_switch(struct dsa_switch *ds)
mutex_lock(&dsa2_mutex);
err = dsa_switch_probe(ds);
+ if (ds->dst)
+ dsa_tree_put(ds->dst);
mutex_unlock(&dsa2_mutex);
return err;
Getting rid of the refcount seems simpler, but we can use this
alternative instead. Let me know what you prefer.
Thanks,
Vivien
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2017-11-09 18:24 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-11-09 17:36 [PATCH net-next] net: dsa: remove tree refcount Vivien Didelot
2017-11-09 18:10 ` Andrew Lunn
2017-11-09 18:24 ` Vivien Didelot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).