From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. This bug exposed the foloowing
phandle cache refcount bug.
The refcount of phandle_cache entries is not incremented while in
the cache, allowing use after free error after kfree() of the
cached entry.
Changes since v1:
- make __of_free_phandle_cache() static
- add WARN_ON(1) for unexpected condition in of_find_node_by_phandle()
Frank Rowand (2):
of: of_node_get()/of_node_put() nodes held in phandle cache
of: __of_detach_node() - remove node from phandle cache
drivers/of/base.c | 100 ++++++++++++++++++++++++++++++++++++------------
drivers/of/dynamic.c | 3 ++
drivers/of/of_private.h | 4 ++
3 files changed, 82 insertions(+), 25 deletions(-)
--
Frank Rowand [off-list ref]
From: Frank Rowand <redacted>
The phandle cache contains struct device_node pointers. The refcount
of the pointers was not incremented while in the cache, allowing use
after free error after kfree() of the node. Add the proper increment
and decrement of the use count.
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Signed-off-by: Frank Rowand <redacted>
---
changes since v1
- make __of_free_phandle_cache() static
drivers/of/base.c | 70 ++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 46 insertions(+), 24 deletions(-)
@@ -1195,8 +1214,11 @@ struct device_node *of_find_node_by_phandle(phandle handle)if(!np){for_each_of_allnodes(np)if(np->phandle==handle){-if(phandle_cache)+if(phandle_cache){+/* will put when removed from cache */+of_node_get(np);phandle_cache[masked_handle]=np;+}break;}}
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
changes since v1:
- add WARN_ON(1) for unexpected condition in of_find_node_by_phandle()
drivers/of/base.c | 30 +++++++++++++++++++++++++++++-
drivers/of/dynamic.c | 3 +++
drivers/of/of_private.h | 4 ++++
3 files changed, 36 insertions(+), 1 deletion(-)
@@ -162,6 +162,27 @@ int of_free_phandle_cache(void)late_initcall_sync(of_free_phandle_cache);#endif+/*+*Callermustholddevtree_lock.+*/+void__of_free_phandle_cache_entry(phandlehandle)+{+phandlemasked_handle;++if(!handle)+return;++masked_handle=handle&phandle_cache_mask;++if(phandle_cache){+if(phandle_cache[masked_handle]&&+handle==phandle_cache[masked_handle]->phandle){+of_node_put(phandle_cache[masked_handle]);+phandle_cache[masked_handle]=NULL;+}+}+}+voidof_populate_phandle_cache(void){unsignedlongflags;
@@ -1209,11 +1230,18 @@ struct device_node *of_find_node_by_phandle(phandle handle)if(phandle_cache[masked_handle]&&handle==phandle_cache[masked_handle]->phandle)np=phandle_cache[masked_handle];+if(np&&of_node_check_flag(np,OF_DETACHED)){+WARN_ON(1);+of_node_put(np);+phandle_cache[masked_handle]=NULL;+np=NULL;+}}if(!np){for_each_of_allnodes(np)-if(np->phandle==handle){+if(np->phandle==handle&&+!of_node_check_flag(np,OF_DETACHED)){if(phandle_cache){/* will put when removed from cache */of_node_get(np);
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2018-12-17 10:43:27
Hi Frank,
frowand.list@gmail.com writes:
From: Frank Rowand <redacted>
The phandle cache contains struct device_node pointers. The refcount
of the pointers was not incremented while in the cache, allowing use
after free error after kfree() of the node. Add the proper increment
and decrement of the use count.
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Can we also add:
Cc: stable@vger.kernel.org # v4.17+
This and the next patch solve WARN_ONs and other problems for us on some
systems so I think they meet the criteria for a stable backport.
Rest of the patch LGTM, I'm not able to test it unfortunately, I have to
defer to mwb for that.
cheers
@@ -1195,8 +1214,11 @@ struct device_node *of_find_node_by_phandle(phandle handle)if(!np){for_each_of_allnodes(np)if(np->phandle==handle){-if(phandle_cache)+if(phandle_cache){+/* will put when removed from cache */+of_node_get(np);phandle_cache[masked_handle]=np;+}break;}}
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2018-12-17 10:52:37
Hi Frank,
frowand.list@gmail.com writes:
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
Similarly here can we add:
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Cc: stable@vger.kernel.org # v4.17+
Thanks for doing this series.
Some minor comments below.
A temporary would help the readability here I think, eg:
struct device_node *np;
np = phandle_cache[masked_handle];
if (np && handle == np->phandle) {
of_node_put(np);
phandle_cache[masked_handle] = NULL;
}
Do we really want to do the put here?
We're here because something has gone wrong, possibly even memory
corruption such that np is not even pointing at a device node anymore.
So it seems like it would be safer to just leave the ref count alone,
possibly leak a small amount of memory, and NULL out the reference.
cheers
From: Rob Herring <robh+dt@kernel.org> Date: 2018-12-18 15:43:22
On Mon, Dec 17, 2018 at 1:56 AM [off-list ref] wrote:
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. This bug exposed the foloowing
phandle cache refcount bug.
The refcount of phandle_cache entries is not incremented while in
the cache, allowing use after free error after kfree() of the
cached entry.
Changes since v1:
- make __of_free_phandle_cache() static
- add WARN_ON(1) for unexpected condition in of_find_node_by_phandle()
Frank Rowand (2):
of: of_node_get()/of_node_put() nodes held in phandle cache
of: __of_detach_node() - remove node from phandle cache
I'll send this to Linus this week if I get a tested by. Otherwise, it
will go in for 4.21.
Rob
From: Frank Rowand <hidden> Date: 2018-12-18 18:57:44
On 12/17/18 2:52 AM, Michael Ellerman wrote:
Hi Frank,
frowand.list@gmail.com writes:
quoted
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
Similarly here can we add:
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Yes, thanks.
Cc: stable@vger.kernel.org # v4.17+
Nope, 0b3ce78e90fc does not belong in stable (it is a feature, not a bug
fix). So the bug will not be in stable.
I've debated with myself over this, because there is a possibility that
0b3ce78e90fc could somehow be put into a stable despite not being a
bug fix. We can always explicitly request this patch series be added
to stable in that case.
Thanks for doing this series.
Some minor comments below.
A temporary would help the readability here I think, eg:
struct device_node *np;
np = phandle_cache[masked_handle];
if (np && handle == np->phandle) {
of_node_put(np);
phandle_cache[masked_handle] = NULL;
}
Do we really want to do the put here?
We're here because something has gone wrong, possibly even memory
corruption such that np is not even pointing at a device node anymore.
So it seems like it would be safer to just leave the ref count alone,
possibly leak a small amount of memory, and NULL out the reference.
I like the concept of the code being a little bit paranoid.
But the bug that this check is likely to cache is the bug that led
to this series -- removing a devicetree node, but failing to remove
it from the cache as part of the removal. So I think I'll leave
it as is.
From: Rob Herring <robh+dt@kernel.org> Date: 2018-12-18 20:01:48
On Tue, Dec 18, 2018 at 12:57 PM Frank Rowand [off-list ref] wrote:
On 12/17/18 2:52 AM, Michael Ellerman wrote:
quoted
Hi Frank,
frowand.list@gmail.com writes:
quoted
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
Similarly here can we add:
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Yes, thanks.
quoted
Cc: stable@vger.kernel.org # v4.17+
Nope, 0b3ce78e90fc does not belong in stable (it is a feature, not a bug
fix). So the bug will not be in stable.
0b3ce78e90fc landed in v4.17, so Michael's line above is correct.
Annotating it with 4.17 only saves Greg from trying and then emailing
us to backport this patch as it wouldn't apply.
Rob
From: Frank Rowand <hidden> Date: 2018-12-18 20:09:07
On 12/18/18 12:01 PM, Rob Herring wrote:
On Tue, Dec 18, 2018 at 12:57 PM Frank Rowand [off-list ref] wrote:
quoted
On 12/17/18 2:52 AM, Michael Ellerman wrote:
quoted
Hi Frank,
frowand.list@gmail.com writes:
quoted
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
Similarly here can we add:
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Yes, thanks.
quoted
Cc: stable@vger.kernel.org # v4.17+
Nope, 0b3ce78e90fc does not belong in stable (it is a feature, not a bug
fix). So the bug will not be in stable.
0b3ce78e90fc landed in v4.17, so Michael's line above is correct.
Annotating it with 4.17 only saves Greg from trying and then emailing
us to backport this patch as it wouldn't apply.
Thanks for the correction. I was both under-thinking and over-thinking,
ending up with an incorrect answer.
Can you add the Cc: to version 3 patch comments (both 1/2 and 2/2) or do
you want me to re-spin?
-Frank
From: Frank Rowand <hidden> Date: 2018-12-18 20:33:22
On 12/18/18 12:09 PM, Frank Rowand wrote:
On 12/18/18 12:01 PM, Rob Herring wrote:
quoted
On Tue, Dec 18, 2018 at 12:57 PM Frank Rowand [off-list ref] wrote:
quoted
On 12/17/18 2:52 AM, Michael Ellerman wrote:
quoted
Hi Frank,
frowand.list@gmail.com writes:
quoted
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
Similarly here can we add:
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Yes, thanks.
quoted
Cc: stable@vger.kernel.org # v4.17+
Nope, 0b3ce78e90fc does not belong in stable (it is a feature, not a bug
fix). So the bug will not be in stable.
0b3ce78e90fc landed in v4.17, so Michael's line above is correct.
Annotating it with 4.17 only saves Greg from trying and then emailing
us to backport this patch as it wouldn't apply.
Thanks for the correction. I was both under-thinking and over-thinking,
ending up with an incorrect answer.
Can you add the Cc: to version 3 patch comments (both 1/2 and 2/2) or do
you want me to re-spin?
Now that my thinking has been straightened out, a little bit more checking
for the other pre-requisite patches show:
v4.18: commit b9952b5218ad ("of: overlay: update phandle cache on overlay apply and remove")
v4.19: commit e54192b48da7 ("of: fix phandle cache creation for DTs with no phandles")
These can be addressed by changing the "Cc:" to ... # v4.19+
because stable v4.17.* and v4.18.* are end of life.
Or the pre-requisites can be listed:
# v4.17: b9952b5218ad of: overlay: update phandle cache
# v4.17: e54192b48da7 of: fix phandle cache creation
# v4.17
# v4.18: e54192b48da7 of: fix phandle cache creation
# v4.18
# v4.19+
Do you have a preference?
-Frank
From: Rob Herring <robh+dt@kernel.org> Date: 2018-12-18 20:59:11
On Tue, Dec 18, 2018 at 2:33 PM Frank Rowand [off-list ref] wrote:
On 12/18/18 12:09 PM, Frank Rowand wrote:
quoted
On 12/18/18 12:01 PM, Rob Herring wrote:
quoted
On Tue, Dec 18, 2018 at 12:57 PM Frank Rowand [off-list ref] wrote:
quoted
On 12/17/18 2:52 AM, Michael Ellerman wrote:
quoted
Hi Frank,
frowand.list@gmail.com writes:
quoted
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
Similarly here can we add:
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Yes, thanks.
quoted
Cc: stable@vger.kernel.org # v4.17+
Nope, 0b3ce78e90fc does not belong in stable (it is a feature, not a bug
fix). So the bug will not be in stable.
0b3ce78e90fc landed in v4.17, so Michael's line above is correct.
Annotating it with 4.17 only saves Greg from trying and then emailing
us to backport this patch as it wouldn't apply.
Thanks for the correction. I was both under-thinking and over-thinking,
ending up with an incorrect answer.
Can you add the Cc: to version 3 patch comments (both 1/2 and 2/2) or do
you want me to re-spin?
Now that my thinking has been straightened out, a little bit more checking
for the other pre-requisite patches show:
v4.18: commit b9952b5218ad ("of: overlay: update phandle cache on overlay apply and remove")
v4.19: commit e54192b48da7 ("of: fix phandle cache creation for DTs with no phandles")
These can be addressed by changing the "Cc:" to ... # v4.19+
because stable v4.17.* and v4.18.* are end of life.
EOL shouldn't factor into it. There's always the possibility someone
else picks any kernel version.
Or the pre-requisites can be listed:
# v4.17: b9952b5218ad of: overlay: update phandle cache
# v4.17: e54192b48da7 of: fix phandle cache creation
# v4.17
# v4.18: e54192b48da7 of: fix phandle cache creation
# v4.18
# v4.19+
Do you have a preference?
I think we just list v4.17 and be done with it.
Rob
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2018-12-18 23:44:56
Rob Herring [off-list ref] writes:
On Tue, Dec 18, 2018 at 2:33 PM Frank Rowand [off-list ref] wrote:
quoted
On 12/18/18 12:09 PM, Frank Rowand wrote:
quoted
On 12/18/18 12:01 PM, Rob Herring wrote:
quoted
On Tue, Dec 18, 2018 at 12:57 PM Frank Rowand [off-list ref] wrote:
quoted
On 12/17/18 2:52 AM, Michael Ellerman wrote:
quoted
Hi Frank,
frowand.list@gmail.com writes:
quoted
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. Remove the node from the
cache.
Add paranoia checks in of_find_node_by_phandle() as a second level
of defense (do not return cached node if detached, do not add node
to cache if detached).
Reported-by: Michael Bringmann <redacted>
Signed-off-by: Frank Rowand <redacted>
---
Similarly here can we add:
Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()")
Yes, thanks.
quoted
Cc: stable@vger.kernel.org # v4.17+
Nope, 0b3ce78e90fc does not belong in stable (it is a feature, not a bug
fix). So the bug will not be in stable.
0b3ce78e90fc landed in v4.17, so Michael's line above is correct.
Annotating it with 4.17 only saves Greg from trying and then emailing
us to backport this patch as it wouldn't apply.
Thanks for the correction. I was both under-thinking and over-thinking,
ending up with an incorrect answer.
Can you add the Cc: to version 3 patch comments (both 1/2 and 2/2) or do
you want me to re-spin?
Now that my thinking has been straightened out, a little bit more checking
for the other pre-requisite patches show:
v4.18: commit b9952b5218ad ("of: overlay: update phandle cache on overlay apply and remove")
v4.19: commit e54192b48da7 ("of: fix phandle cache creation for DTs with no phandles")
These can be addressed by changing the "Cc:" to ... # v4.19+
because stable v4.17.* and v4.18.* are end of life.
EOL shouldn't factor into it. There's always the possibility someone
else picks any kernel version.
Yeah, there are other stable branches out there, so the tag should point
to the correct version regardless of whether it's currently EOL on
kernel.org.
quoted
Or the pre-requisites can be listed:
# v4.17: b9952b5218ad of: overlay: update phandle cache
# v4.17: e54192b48da7 of: fix phandle cache creation
# v4.17
# v4.18: e54192b48da7 of: fix phandle cache creation
# v4.18
# v4.19+
Do you have a preference?
I think we just list v4.17 and be done with it.
Yep, anyone who wants to backport it can work it out, or ask us.
cheers
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2018-12-18 23:46:53
Rob Herring [off-list ref] writes:
On Mon, Dec 17, 2018 at 1:56 AM [off-list ref] wrote:
quoted
From: Frank Rowand <redacted>
Non-overlay dynamic devicetree node removal may leave the node in
the phandle cache. Subsequent calls to of_find_node_by_phandle()
will incorrectly find the stale entry. This bug exposed the foloowing
phandle cache refcount bug.
The refcount of phandle_cache entries is not incremented while in
the cache, allowing use after free error after kfree() of the
cached entry.
Changes since v1:
- make __of_free_phandle_cache() static
- add WARN_ON(1) for unexpected condition in of_find_node_by_phandle()
Frank Rowand (2):
of: of_node_get()/of_node_put() nodes held in phandle cache
of: __of_detach_node() - remove node from phandle cache
I'll send this to Linus this week if I get a tested by. Otherwise, it
will go in for 4.21.
I think it can wait to go into 4.21, it's not super critical and it's
not a regression since 4.19.
cheers