Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1bdae2e authored by Isaac J. Manjarres's avatar Isaac J. Manjarres Committed by Venkata Narendra Kumar Gutta
Browse files

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: default avatarIsaac J. Manjarres <isaacm@codeaurora.org>
Signed-off-by: default avatarVenkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
parent bd110257
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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"
+24 −7
Original line number Diff line number Diff line
@@ -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;
		}