kref: Avoid null pointer dereference after WARN
PATCH 1/1 kref: Avoid null pointer dereference after WARN
From: Daniel Micay <[email protected]>
The WARN_ON() checking for a NULL release pointer should be a BUG() since continuing with a NULL release pointer will lead to a NULL pointer dereference anyway.
The kref_put() case is extracted from PaX, and Kees Cook noted it should be extended to the other two cases.
--- include/linux/kref.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
include/linux/kref.h +3 -3
@@ -66,7 +66,7 @@ static inline void kref_get(struct kref *kref)*/ static inline int kref_put (struct kref *kref,void (*release)(struct kref *kref)) { -WARN_ON (release ==NULL ); +BUG_ON (release ==NULL );if (refcount_dec_and_test (&kref->refcount)) {release (kref);
@@ -79,7 +79,7 @@ static inline int kref_put_mutex(struct kref *kref,void (*release)(struct kref *kref), struct mutex *lock) { - WARN_ON(release == NULL); + BUG_ON(release == NULL);if (refcount_dec_and_mutex_lock (&kref->refcount, lock)) {release (kref);
@@ -92,7 +92,7 @@ static inline int kref_put_lock(struct kref *kref,void (*release)(struct kref *kref), spinlock_t *lock) { - WARN_ON(release == NULL); + BUG_ON(release == NULL);if (refcount_dec_and_lock (&kref->refcount, lock)) {release (kref);
Signature · 2 lines
Kees Cook Pixel Security
Quoted 21 lines · Kees Cook
From: Daniel Micay <[email protected]>
The
WARN_ON()checking for a NULL release pointer should be aBUG()since continuing with a NULL release pointer will lead to a NULL pointer dereference anyway.The
kref_put()case is extracted from PaX, and Kees Cook noted it should be extended to the other two cases.Signed-off-by Daniel Micay <[email protected]>[kees: clarify commit log]Signed-off-by Kees Cook <[email protected]>--- include/linux/kref.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)include/linux/kref.h +0
-0
include/linux/kref.h static inline void kref_get(struct kref *kref) · line 69
Quoted 5 lines
include/linux/kref.h +1
-1@@ -66,7 +66,7 @@ static inline void kref_get(struct kref *kref)*/ static inline int kref_put (struct kref *kref,void (*release)(struct kref *kref)) { -WARN_ON (release ==NULL ); +BUG_ON (release ==NULL );
I remember one complaint was that WARN_ON was "huge" and this bloated the kernel code a lot. But then that got fixed up. Is BUG_ON going to cause the same complaint again?
thanks,
greg k-h
Quoted 3 lines · Greg Kroah-Hartman
I remember one complaint was that
WARN_ONwas "huge" and this bloated the kernel code a lot. But then that got fixed up. IsBUG_ONgoing to cause the same complaint again?
Complaint or not, I'm pretty sure using BUG_ON here is the right behavior. If removing it will result in a null pointer dereference (and subsequent function call), that's bad news bears, especially on systems with a zero mmap_min_addr or combined with other bugs.
If somehow a driver manages to pass a NULL as the release function, something is really messed up and the kernel should "safely" panic instead.
Quoted 4 lines
thanks,
greg k-h
Signature · 7 lines
Jason A. Donenfeld Deep Space Explorer fr: +33 6 51 90 82 66 us: +1 513 476 1200 www.jasondonenfeld.com www.zx2c4.com zx2c4.com/keys/AB9942E6D4A4CFC3412620A749FC7012A5DE03AE.asc
Quoted 5 lines · Jason A. Donenfeld
Quoted 3 lines · Greg Kroah-Hartman
I remember one complaint was that
WARN_ONwas "huge" and this bloated the kernel code a lot. But then that got fixed up. IsBUG_ONgoing to cause the same complaint again?
Quoted 8 lines
Complaint or not, I'm pretty sure using
BUG_ONhere is the right behavior. If removing it will result in a null pointer dereference (and subsequent function call), that's bad news bears, especially on systems with a zerommap_min_addror combined with other bugs.If somehow a driver manages to pass a NULL as the release function, something is really messed up and the kernel should "safely" panic instead.
Please post data on the kernel text change from this patch.
In general I'm sceptical on the value of changes like this. Why is release so important to check compared to other places?
Is there any data how many security holes this would have caught? Please no hand waving. A lot of the recent security patches seem to have gone in with just a lot of hand waving and security theater
("It's in gr-security, so it must be great")
In general accountability is important, especially in security
-Andi
Quoted 4 lines · Andi Kleen
Is there any data how many security holes this would have caught? Please no hand waving. A lot of the recent security patches seem to have gone in with just a lot of hand waving and security theater
I don't practice security theater. What an offensive insinuation. Maybe you just meant this about other patches, however.
The point was that if there prior was a WARN_ON, this needs to be a BUG_ON, since if the WARN_ON was put there with any validity, continuing after it will always be "fatal and potentially exploitable". Thus, it'd be better to change that to simply "fatal but not potentially exploitable". Not security theater. Logic fix.
The bigger question, though, is the value of these checks in the first place. Has anybody written a coccinelle check to look into this statically? Has it historically been a useful thing for driver developers to have? Is it good defense in depth or is it overkill? At the very least, the original authors of kref thought a WARN_ON was warranted, which means probably a BUG_ON is a sensible fix, until somebody does the work of investigating these more careful questions.
Jason
Quoted 8 lines · Jason A. Donenfeld
Quoted 4 lines · Andi Kleen
Is there any data how many security holes this would have caught? Please no hand waving. A lot of the recent security patches seem to have gone in with just a lot of hand waving and security theater
I don't practice security theater. What an offensive insinuation. Maybe you just meant this about other patches, however.
I'm not naming names, but there was a recent patch that seemed to have fixed one very extremely specific bug, but made every kernel exit forever slower.
That was a classic case IMHO -- the Linux equivalent of shoes at airport checkpoints.
Quoted 4 lines
The point was that if there prior was a
WARN_ON, this needs to be aBUG_ON, since if theWARN_ONwas put there with any validity, continuing after it will always be "fatal and potentially exploitable". Thus, it'd be better to change that to simply "fatal but
That's not necessarily true. Especially not for a release. Typically you would hit if partial teardown on an initialization failure is incorrect. But that's not exploitable at all.
Quoted 7 lines
The bigger question, though, is the value of these checks in the first place. Has anybody written a coccinelle check to look into this statically? Has it historically been a useful thing for driver developers to have? Is it good defense in depth or is it overkill? At the very least, the original authors of kref thought a
WARN_ONwas warranted, which means probably aBUG_ONis a sensible fix, until somebody does the work of investigating these more careful questions.
Right that's the question that should have been answered before this patch.
I don't think it was ever intended to be a defense, just as a hint for driver developers.
My suspicion is that they're mostly useless.
-Andi
Quoted 1 line · Andi Kleen
On Tue, Jun 27, 2017 at 09:11:28PM +0200, Jason A. Donenfeld wrote:
[...]
Quoted 8 lines
Quoted 7 lines
The bigger question, though, is the value of these checks in the first place. Has anybody written a coccinelle check to look into this statically? Has it historically been a useful thing for driver developers to have? Is it good defense in depth or is it overkill? At the very least, the original authors of kref thought a
WARN_ONwas warranted, which means probably aBUG_ONis a sensible fix, until somebody does the work of investigating these more careful questions.
Quoted 7 lines
Right that's the question that should have been answered before this patch.
I don't think it was ever intended to be a defense, just as a hint for driver developers.
My suspicion is that they're mostly useless.
Completely agreed here!
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 17 lines · Greg Kroah-Hartman
Quoted 16 lines · Kees Cook
From: Daniel Micay <[email protected]>
The
WARN_ON()checking for a NULL release pointer should be aBUG()since continuing with a NULL release pointer will lead to a NULL pointer dereference anyway.The
kref_put()case is extracted from PaX, and Kees Cook noted it should be extended to the other two cases.Signed-off-by Daniel Micay <[email protected]>[kees: clarify commit log]Signed-off-by Kees Cook <[email protected]>--- include/linux/kref.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Quoted 14 lines
include/linux/kref.h static inline void kref_get(struct kref *kref) · line 69
Quoted 10 lines
include/linux/kref.h +1
-1@@ -66,7 +66,7 @@ static inline void kref_get(struct kref *kref)*/ static inline int kref_put (struct kref *kref,void (*release)(struct kref *kref)) { -WARN_ON (release ==NULL ); +BUG_ON (release ==NULL );I remember one complaint was that
WARN_ONwas "huge" and this bloated the kernel code a lot. But then that got fixed up. IsBUG_ONgoing to cause the same complaint again?
It used to be that WARN was much larger than BUG, but Peter Z fixed[1] that recently. BUG is very small (on x86 a single instruction). I'll send a v2 with the .text comparison.
-Kees
[1] 9a93848fe787 ("x86/debug: Implement __WARN() using UD0")
Signature · 2 lines
Kees Cook Pixel Security
Quoted 4 lines · Greg Kroah-Hartman
I remember one complaint was that
WARN_ONwas "huge" and this bloated the kernel code a lot. But then that got fixed up. IsBUG_ONgoing to cause the same complaint again?
BUG_ON and WARN_ON should be of equal (small) size.
Quoted 5 lines · Kees Cook
From: Daniel Micay <[email protected]>
The
WARN_ON()checking for a NULL release pointer should be aBUG()since continuing with a NULL release pointer will lead to a NULL pointer dereference anyway.
The reason I enforced the release pointer not being NULL in the first place, was because to not do so is a logic bug, not a run-time bug.
By putting the WARN_ON there, developers get to see the traceback and know to fix their code. The driver core is even harsher printing out a message if the release function is not set, and doing a full WARN_ON().
When you just crash the machine, with BUG(), you are preventing the developer to have a chance to know what to fix. With WARN_ON, the machine still runs, and they can fix up their code. Odds are, when someone doesn't provide a release function, their logic is such that it will never be called anyway as their reference counting is totally broken anyway :)
So this is a helper for the developer, let's not turn it into something that is then a "crash the machine" issue.
Now if we could also come up with a way for the check to see if the release function was something foolish like:
void my_release(kref *kref) { }that would be ideal, as the documentation explicitly says not to do this, and I will be able to make fun of you in public if you do, yet I constantly see _that_ happen all the time..
So let's leave this as WARN_ON(), it's not a security issue / protection issue in any sense of the word. It's a "let's help provide an API that tells the developer when they use it incorrectly" type thing.
Also, you will note, all calls to kref_put() in the kernel tree do not have this issue, so really, one could argue that this check is doing its job :)
So I'll just drop this patch for now, thanks,
greg k-h