Loading arch/Kconfig +9 −0 Original line number Original line Diff line number Diff line Loading @@ -1027,4 +1027,13 @@ config REFCOUNT_FULL against various use-after-free conditions that can be used in against various use-after-free conditions that can be used in security flaw exploits. security flaw exploits. 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 "kernel/gcov/Kconfig" arch/arm64/configs/sm8150-perf_defconfig +1 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y Loading arch/arm64/configs/sm8150_defconfig +2 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,8 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_REFCOUNT_FULL=y CONFIG_PANIC_ON_REFCOUNT_ERROR=y CONFIG_MODULES=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y Loading lib/refcount.c +26 −7 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,18 @@ #include <linux/refcount.h> #include <linux/refcount.h> #include <linux/bug.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 #ifdef CONFIG_REFCOUNT_FULL /** /** Loading Loading @@ -75,7 +87,8 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); } 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; return true; } } Loading @@ -99,7 +112,8 @@ EXPORT_SYMBOL(refcount_add_not_zero); */ */ void refcount_add(unsigned int i, refcount_t *r) 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); EXPORT_SYMBOL(refcount_add); Loading Loading @@ -130,7 +144,8 @@ bool refcount_inc_not_zero(refcount_t *r) } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); } 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; return true; } } Loading @@ -150,7 +165,8 @@ EXPORT_SYMBOL(refcount_inc_not_zero); */ */ void refcount_inc(refcount_t *r) 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); EXPORT_SYMBOL(refcount_inc); Loading Loading @@ -184,7 +200,8 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) new = val - i; new = val - i; if (new > val) { 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; return false; } } Loading Loading @@ -225,7 +242,8 @@ EXPORT_SYMBOL(refcount_dec_and_test); */ */ void refcount_dec(refcount_t *r) 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); EXPORT_SYMBOL(refcount_dec); #endif /* CONFIG_REFCOUNT_FULL */ #endif /* CONFIG_REFCOUNT_FULL */ Loading Loading @@ -278,7 +296,8 @@ bool refcount_dec_not_one(refcount_t *r) new = val - 1; new = val - 1; if (new > val) { 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; return true; } } Loading Loading
arch/Kconfig +9 −0 Original line number Original line Diff line number Diff line Loading @@ -1027,4 +1027,13 @@ config REFCOUNT_FULL against various use-after-free conditions that can be used in against various use-after-free conditions that can be used in security flaw exploits. security flaw exploits. 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 "kernel/gcov/Kconfig"
arch/arm64/configs/sm8150-perf_defconfig +1 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y Loading
arch/arm64/configs/sm8150_defconfig +2 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,8 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_REFCOUNT_FULL=y CONFIG_PANIC_ON_REFCOUNT_ERROR=y CONFIG_MODULES=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y Loading
lib/refcount.c +26 −7 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,18 @@ #include <linux/refcount.h> #include <linux/refcount.h> #include <linux/bug.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 #ifdef CONFIG_REFCOUNT_FULL /** /** Loading Loading @@ -75,7 +87,8 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); } 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; return true; } } Loading @@ -99,7 +112,8 @@ EXPORT_SYMBOL(refcount_add_not_zero); */ */ void refcount_add(unsigned int i, refcount_t *r) 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); EXPORT_SYMBOL(refcount_add); Loading Loading @@ -130,7 +144,8 @@ bool refcount_inc_not_zero(refcount_t *r) } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); } 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; return true; } } Loading @@ -150,7 +165,8 @@ EXPORT_SYMBOL(refcount_inc_not_zero); */ */ void refcount_inc(refcount_t *r) 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); EXPORT_SYMBOL(refcount_inc); Loading Loading @@ -184,7 +200,8 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) new = val - i; new = val - i; if (new > val) { 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; return false; } } Loading Loading @@ -225,7 +242,8 @@ EXPORT_SYMBOL(refcount_dec_and_test); */ */ void refcount_dec(refcount_t *r) 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); EXPORT_SYMBOL(refcount_dec); #endif /* CONFIG_REFCOUNT_FULL */ #endif /* CONFIG_REFCOUNT_FULL */ Loading Loading @@ -278,7 +296,8 @@ bool refcount_dec_not_one(refcount_t *r) new = val - 1; new = val - 1; if (new > val) { 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; return true; } } Loading