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>
This commit is contained in:
Isaac J. Manjarres 2018-05-04 16:02:44 -07:00 committed by xxmustafacooTR
parent a681ba0a3d
commit 9370578cb2
No known key found for this signature in database
GPG key ID: 520B6FE385CBF5C9
2 changed files with 35 additions and 7 deletions

View file

@ -37,6 +37,18 @@
#include <linux/refcount.h>
#include <linux/bug.h>
#ifdef CONFIG_PANIC_ON_REFCOUNT_ERROR
#define REFCOUNT_WARN_ONCE(cond, msg) \
do { \
if (cond) { \
printk(msg); \
BUG(); \
} \
} while (0)
#else
#define REFCOUNT_WARN_ONCE(cond, msg) WARN_ONCE(cond, msg)
#endif /* CONFIG_PANIC_ON_REFCOUNT_ERROR */
#ifdef CONFIG_REFCOUNT_FULL
/**
@ -74,7 +86,8 @@ bool refcount_add_not_zero(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;
}
@ -98,7 +111,8 @@ EXPORT_SYMBOL(refcount_add_not_zero);
*/
void refcount_add(unsigned int i, refcount_t *r)
{
WARN_ONCE(!refcount_add_not_zero(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);
@ -129,7 +143,8 @@ bool refcount_inc_not_zero(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;
}
@ -149,7 +164,8 @@ EXPORT_SYMBOL(refcount_inc_not_zero);
*/
void refcount_inc(refcount_t *r)
{
WARN_ONCE(!refcount_inc_not_zero(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);
@ -183,7 +199,8 @@ bool refcount_sub_and_test(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;
}
@ -224,7 +241,8 @@ EXPORT_SYMBOL(refcount_dec_and_test);
*/
void refcount_dec(refcount_t *r)
{
WARN_ONCE(refcount_dec_and_test(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);
#endif /* CONFIG_REFCOUNT_FULL */
@ -277,7 +295,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;
}