lib: refcount: Cause kernel panic on refcount error detection
Currently, when using the refcount API functions, a warning is printed out once to let a user of the refcount API know that an error case has been detected. Then the refcount functions will silently return, without modifying the reference count, which could be mistaken for a successful modification. This can allow for improper use of the object associated with that refcount later. Trigger a kernel panic in case of refcount error detection to prevent misuse of objects associated with refcounts. Change-Id: Ifb6a331d08a7d6c285225bc9667d2f4054db3561 Signed-off-by: Isaac J. Manjarres <isaacm@codeaurora.org> Signed-off-by: Venkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
This commit is contained in:
parent
bd110257ad
commit
e1bdae2e7a
@ -890,6 +890,15 @@ config HAVE_ARCH_PREL32_RELOCATIONS
|
||||
architectures, and don't require runtime relocation on relocatable
|
||||
kernels.
|
||||
|
||||
config PANIC_ON_REFCOUNT_ERROR
|
||||
bool "Kernel panic on refcount error detection"
|
||||
depends on REFCOUNT_FULL
|
||||
help
|
||||
If enabled, the kernel will panic when the refcount library
|
||||
has detected any type of error (e.g. potential use-after-free
|
||||
or potential memory-leaks) with an object associated with that
|
||||
reference counter.
|
||||
|
||||
source "kernel/gcov/Kconfig"
|
||||
|
||||
source "scripts/gcc-plugins/Kconfig"
|
||||
|
@ -40,6 +40,16 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
#ifdef CONFIG_PANIC_ON_REFCOUNT_ERROR
|
||||
#define REFCOUNT_WARN_ONCE(cond, msg) \
|
||||
do { \
|
||||
if (cond) \
|
||||
panic(msg); \
|
||||
} while (0)
|
||||
#else
|
||||
#define REFCOUNT_WARN_ONCE(cond, msg) WARN_ONCE(cond, msg)
|
||||
#endif /* CONFIG_PANIC_ON_REFCOUNT_ERROR */
|
||||
|
||||
/**
|
||||
* refcount_add_not_zero_checked - add a value to a refcount unless it is 0
|
||||
* @i: the value to add to the refcount
|
||||
@ -75,7 +85,8 @@ bool refcount_add_not_zero_checked(unsigned int i, refcount_t *r)
|
||||
|
||||
} while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new));
|
||||
|
||||
WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n");
|
||||
REFCOUNT_WARN_ONCE(new == UINT_MAX,
|
||||
"refcount_t: saturated; leaking memory.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -99,7 +110,8 @@ EXPORT_SYMBOL(refcount_add_not_zero_checked);
|
||||
*/
|
||||
void refcount_add_checked(unsigned int i, refcount_t *r)
|
||||
{
|
||||
WARN_ONCE(!refcount_add_not_zero_checked(i, r), "refcount_t: addition on 0; use-after-free.\n");
|
||||
REFCOUNT_WARN_ONCE(!refcount_add_not_zero(i, r),
|
||||
"refcount_t: addition on 0; use-after-free.\n");
|
||||
}
|
||||
EXPORT_SYMBOL(refcount_add_checked);
|
||||
|
||||
@ -130,7 +142,8 @@ bool refcount_inc_not_zero_checked(refcount_t *r)
|
||||
|
||||
} while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new));
|
||||
|
||||
WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n");
|
||||
REFCOUNT_WARN_ONCE(new == UINT_MAX,
|
||||
"refcount_t: saturated; leaking memory.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -150,7 +163,8 @@ EXPORT_SYMBOL(refcount_inc_not_zero_checked);
|
||||
*/
|
||||
void refcount_inc_checked(refcount_t *r)
|
||||
{
|
||||
WARN_ONCE(!refcount_inc_not_zero_checked(r), "refcount_t: increment on 0; use-after-free.\n");
|
||||
REFCOUNT_WARN_ONCE(!refcount_inc_not_zero(r),
|
||||
"refcount_t: increment on 0; use-after-free.\n");
|
||||
}
|
||||
EXPORT_SYMBOL(refcount_inc_checked);
|
||||
|
||||
@ -184,7 +198,8 @@ bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r)
|
||||
|
||||
new = val - i;
|
||||
if (new > val) {
|
||||
WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n");
|
||||
REFCOUNT_WARN_ONCE(new > val,
|
||||
"refcount_t: underflow; use-after-free.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -225,7 +240,8 @@ EXPORT_SYMBOL(refcount_dec_and_test_checked);
|
||||
*/
|
||||
void refcount_dec_checked(refcount_t *r)
|
||||
{
|
||||
WARN_ONCE(refcount_dec_and_test_checked(r), "refcount_t: decrement hit 0; leaking memory.\n");
|
||||
REFCOUNT_WARN_ONCE(refcount_dec_and_test(r),
|
||||
"refcount_t: decrement hit 0; leaking memory.\n");
|
||||
}
|
||||
EXPORT_SYMBOL(refcount_dec_checked);
|
||||
|
||||
@ -277,7 +293,8 @@ bool refcount_dec_not_one(refcount_t *r)
|
||||
|
||||
new = val - 1;
|
||||
if (new > val) {
|
||||
WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n");
|
||||
REFCOUNT_WARN_ONCE(new > val,
|
||||
"refcount_t: underflow; use-after-free.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user