Rework REFCOUNT_FULL using atomic_fetch_* operations
Subsystems (11)
Will Deacon
maintainerv4 cover Rework REFCOUNT_FULL using atomic_fetch_* operations
Hi all,
This is version four of the patches I previously posted here:
v1: https://lkml.kernel.org/r/[email protected]
v2: https://lkml.kernel.org/r/[email protected]
v3: https://lkml.kernel.org/r/[email protected]
Changes since v3 include:
- Add description of racy behaviour include/linux/refcount.h
- Fix saturation behaviour in refcount_sub_and_test()
- Added Acks and Tested-bys
Cheers,
Will
--->8
Will Deacon (10):
lib/refcount: Define constants for saturation and max refcount values lib/refcount: Ensure integer operands are treated as signed lib/refcount: Remove unused refcount_*_checked() variants lib/refcount: Move bulk of REFCOUNT_FULL implementation into header lib/refcount: Improve performance of generic REFCOUNT_FULL code lib/refcount: Move saturation warnings out of line lib/refcount: Consolidate REFCOUNT_{MAX,SATURATED} definitions
refcount: Consolidate implementations of refcount_t lib/refcount: Remove unused 'refcount_error_report()' function drivers/lkdtm: Remove references to CONFIG_REFCOUNT_FULL
arch/Kconfig | 21 --- arch/arm/Kconfig | 1 - arch/arm64/Kconfig | 1 - arch/s390/configs/debug_defconfig | 1 - arch/x86/Kconfig | 1 - arch/x86/include/asm/asm.h | 6 - arch/x86/include/asm/refcount.h | 126 -------------- arch/x86/mm/extable.c | 49 ------ drivers/gpu/drm/i915/Kconfig.debug | 1 - drivers/misc/lkdtm/refcount.c | 11 +- include/linux/kernel.h | 7 - include/linux/refcount.h | 269 ++++++++++++++++++++++++----- kernel/panic.c | 11 -- lib/refcount.c | 255 +++------------------------ 14 files changed, 257 insertions(+), 503 deletions(-) delete mode 100644 arch/x86/include/asm/refcount.h
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 1/10 lib/refcount: Define constants for saturation and max refcount values
The REFCOUNT_FULL implementation uses a different saturation point than the x86 implementation, which means that the shared refcount code in lib/refcount.c (e.g. refcount_dec_not_one()) needs to be aware of the difference.
Rather than duplicate the definitions from the lkdtm driver, instead move them into linux/refcount.h and update all references accordingly.
--- drivers/misc/lkdtm/refcount.c | 8 -------- include/linux/refcount.h | 10 +++++++++- lib/refcount.c | 37 +++++++++++++++++++---------------- 3 files changed, 29 insertions(+), 26 deletions(-)
drivers/misc/lkdtm/refcount.c +0 -8
@@ -6,14 +6,6 @@#include "lkdtm.h" #include <linux/refcount.h> -#ifdef CONFIG_REFCOUNT_FULL -#define REFCOUNT_MAX (UINT_MAX - 1) -#define REFCOUNT_SATURATED UINT_MAX -#else -#define REFCOUNT_MAX INT_MAX -#define REFCOUNT_SATURATED (INT_MIN / 2) -#endif -static void overflow_check (refcount_t *ref) {switch (refcount_read (ref)) {
include/linux/refcount.h +9 -1
@@ -4,6 +4,7 @@#include <linux/atomic.h> #include <linux/compiler.h> +#include <linux/limits.h> #include <linux/spinlock_types.h> struct mutex ;
@@ -12,7 +13,7 @@ struct mutex;* struct refcount_t - variant of atomic_t specialized for reference counts * @refs: atomic_t counter field * -* The counter saturates at UINT_MAX and will not move once +* The counter saturates at REFCOUNT_SATURATED and will not move once * there. This avoids wrapping the counter and causing 'spurious' * use-after-free bugs. */
@@ -56,6 +57,9 @@ extern void refcount_dec_checked(refcount_t *r);#ifdef CONFIG_REFCOUNT_FULL +#define REFCOUNT_MAX (UINT_MAX - 1) +#define REFCOUNT_SATURATED UINT_MAX +#define refcount_add_not_zero refcount_add_not_zero_checked#define refcount_add refcount_add_checked
@@ -68,6 +72,10 @@ extern void refcount_dec_checked(refcount_t *r);#define refcount_dec refcount_dec_checked#else + +#define REFCOUNT_MAX INT_MAX +#define REFCOUNT_SATURATED (INT_MIN / 2) +# ifdef CONFIG_ARCH_HAS_REFCOUNT # include <asm/refcount.h> # else
lib/refcount.c +20 -17
@@ -5,8 +5,8 @@* The interface matches the atomic_t interface (to aid in porting) but only * provides the few functions one should use for reference counting. * -* It differs in that the counter saturates at UINT_MAX and will not move once -* there. This avoids wrapping the counter and causing 'spurious' +* It differs in that the counter saturates at REFCOUNT_SATURATED and will not +* move once there. This avoids wrapping the counter and causing 'spurious' * use-after-free issues. * * Memory ordering rules are slightly relaxed wrt regular atomic_t functions
@@ -48,7 +48,7 @@* @i: the value to add to the refcount * @r: the refcount * -* Will saturate at UINT_MAX and WARN. +* Will saturate at REFCOUNT_SATURATED and WARN. * * Provides no memory ordering, it is assumed the caller has guaranteed the * object memory to be stable (RCU, etc.). It does provide a control dependency
@@ -69,16 +69,17 @@ bool refcount_add_not_zero_checked(unsigned int i, refcount_t *r)if (!val)return false; -if (unlikely (val ==UINT_MAX )) +if (unlikely (val ==REFCOUNT_SATURATED ))return true; new = val + i;if (new < val) - new =UINT_MAX ; + new =REFCOUNT_SATURATED ; }while (!atomic_try_cmpxchg_relaxed (&r->refs, &val, new)); -WARN_ONCE (new ==UINT_MAX ,"refcount_t: saturated; leaking memory.\n" ); +WARN_ONCE (new ==REFCOUNT_SATURATED , +"refcount_t: saturated; leaking memory.\n" );return true; }
@@ -89,7 +90,7 @@ EXPORT_SYMBOL(refcount_add_not_zero_checked);* @i: the value to add to the refcount * @r: the refcount * -* Similar to atomic_add(), but will saturate at UINT_MAX and WARN. +* Similar to atomic_add(), but will saturate at REFCOUNT_SATURATED and WARN. * * Provides no memory ordering, it is assumed the caller has guaranteed the * object memory to be stable (RCU, etc.). It does provide a control dependency
@@ -110,7 +111,8 @@ EXPORT_SYMBOL(refcount_add_checked);* refcount_inc_not_zero_checked - increment a refcount unless it is 0 * @r: the refcount to increment * -* Similar to atomic_inc_not_zero(), but will saturate at UINT_MAX and WARN. +* Similar to atomic_inc_not_zero(), but will saturate at REFCOUNT_SATURATED +* and WARN. * * Provides no memory ordering, it is assumed the caller has guaranteed the * object memory to be stable (RCU, etc.). It does provide a control dependency
@@ -133,7 +135,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" ); +WARN_ONCE (new ==REFCOUNT_SATURATED , +"refcount_t: saturated; leaking memory.\n" );return true; }
@@ -143,7 +146,7 @@ EXPORT_SYMBOL(refcount_inc_not_zero_checked);* refcount_inc_checked - increment a refcount * @r: the refcount to increment * -* Similar to atomic_inc(), but will saturate at UINT_MAX and WARN. +* Similar to atomic_inc(), but will saturate at REFCOUNT_SATURATED and WARN. * * Provides no memory ordering, it is assumed the caller already has a * reference on the object.
@@ -164,7 +167,7 @@ EXPORT_SYMBOL(refcount_inc_checked);* * Similar to atomic_dec_and_test(), but it will WARN, return false and * ultimately leak on underflow and will fail to decrement when saturated -* at UINT_MAX. +* at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides an acquire ordering on success such that free()
@@ -182,7 +185,7 @@ bool refcount_sub_and_test_checked(unsigned int i, refcount_t *r)unsigned int new, val =atomic_read (&r->refs); do { - if (unlikely(val == UINT_MAX)) + if (unlikely(val == REFCOUNT_SATURATED)) return false; new = val - i;
@@ -207,7 +210,7 @@ EXPORT_SYMBOL(refcount_sub_and_test_checked);* @r: the refcount * * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to -* decrement when saturated at UINT_MAX. +* decrement when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides an acquire ordering on success such that free()
@@ -226,7 +229,7 @@ EXPORT_SYMBOL(refcount_dec_and_test_checked);* @r: the refcount * * Similar to atomic_dec(), it will WARN on underflow and fail to decrement -* when saturated at UINT_MAX. +* when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before.
@@ -277,7 +280,7 @@ bool refcount_dec_not_one(refcount_t *r)unsigned int new, val =atomic_read (&r->refs); do { - if (unlikely(val == UINT_MAX)) + if (unlikely(val == REFCOUNT_SATURATED)) return true; if (val == 1)
@@ -302,7 +305,7 @@ EXPORT_SYMBOL(refcount_dec_not_one);* @lock: the mutex to be locked * * Similar to atomic_dec_and_mutex_lock(), it will WARN on underflow and fail -* to decrement when saturated at UINT_MAX. +* to decrement when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides a control dependency such that free() must come after.
@@ -333,7 +336,7 @@ EXPORT_SYMBOL(refcount_dec_and_mutex_lock);* @lock: the spinlock to be locked * * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to -* decrement when saturated at UINT_MAX. +* decrement when saturated at REFCOUNT_SATURATED. * * Provides release memory ordering, such that prior loads and stores are done * before, and provides a control dependency such that free() must come after.
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 2/10 lib/refcount: Ensure integer operands are treated as signed
In reply to Will DeaconIn preparation for changing the saturation point of REFCOUNT_FULL to INT_MIN / 2, change the type of integer operands passed into the API from 'unsigned int' to 'int' so that we can avoid casting during comparisons when we don't want to fall foul of C integral conversion rules for signed and unsigned types.
Since the kernel is compiled with '-fno-strict-overflow', we don't need to worry about the UB introduced by signed overflow here. Furthermore, we're already making heavy use of the atomic_t API, which operates exclusively on signed types.
--- include/linux/refcount.h | 14 +++++++------- lib/refcount.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-)
include/linux/refcount.h +7 -7
@@ -28,7 +28,7 @@ typedef struct refcount_struct {* @r: the refcount * @n: value to which the refcount will be set */ -static inline void refcount_set (refcount_t *r,unsigned int n) +static inline void refcount_set (refcount_t *r,int n) {atomic_set (&r->refs, n); }
@@ -44,13 +44,13 @@ static inline unsigned int refcount_read(const refcount_t *r)return atomic_read (&r->refs); } -extern __must_check bool refcount_add_not_zero_checked (unsigned int i,refcount_t *r); -extern void refcount_add_checked (unsigned int i,refcount_t *r); +extern __must_check bool refcount_add_not_zero_checked (int i,refcount_t *r); +extern void refcount_add_checked (int i,refcount_t *r);extern __must_check bool refcount_inc_not_zero_checked (refcount_t *r);extern void refcount_inc_checked (refcount_t *r); -extern __must_check bool refcount_sub_and_test_checked (unsigned int i,refcount_t *r); +extern __must_check bool refcount_sub_and_test_checked (int i,refcount_t *r);extern __must_check bool refcount_dec_and_test_checked (refcount_t *r);extern void refcount_dec_checked (refcount_t *r);
@@ -79,12 +79,12 @@ extern void refcount_dec_checked(refcount_t *r);# ifdef CONFIG_ARCH_HAS_REFCOUNT # include <asm/refcount.h> # else -static inline __must_check bool refcount_add_not_zero (unsigned int i,refcount_t *r) +static inline __must_check bool refcount_add_not_zero (int i,refcount_t *r) {return atomic_add_unless (&r->refs, i,0 ); } -static inline void refcount_add (unsigned int i,refcount_t *r) +static inline void refcount_add (int i,refcount_t *r) {atomic_add (i, &r->refs); }
@@ -99,7 +99,7 @@ static inline void refcount_inc(refcount_t *r)atomic_inc (&r->refs); } -static inline __must_check bool refcount_sub_and_test (unsigned int i,refcount_t *r) +static inline __must_check bool refcount_sub_and_test (int i,refcount_t *r) {return atomic_sub_and_test (i, &r->refs); }
lib/refcount.c +3 -3
@@ -61,7 +61,7 @@* * Return: false if the passed refcount is 0, true otherwise */ -bool refcount_add_not_zero_checked (unsigned int i,refcount_t *r) +bool refcount_add_not_zero_checked (int i,refcount_t *r) {unsigned int new, val =atomic_read (&r->refs);
@@ -101,7 +101,7 @@ EXPORT_SYMBOL(refcount_add_not_zero_checked);* cases, refcount_inc(), or one of its variants, should instead be used to * increment a reference count. */ -void refcount_add_checked (unsigned int i,refcount_t *r) +void refcount_add_checked (int i,refcount_t *r) {WARN_ONCE (!refcount_add_not_zero_checked (i, r),"refcount_t: addition on 0; use-after-free.\n" ); }
@@ -180,7 +180,7 @@ EXPORT_SYMBOL(refcount_inc_checked);* * Return: true if the resulting refcount is 0, false otherwise */ -bool refcount_sub_and_test_checked (unsigned int i,refcount_t *r) +bool refcount_sub_and_test_checked (int i,refcount_t *r) {unsigned int new, val =atomic_read (&r->refs);
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 3/10 lib/refcount: Remove unused refcount_*_checked() variants
In reply to Will DeaconThe full-fat refcount implementation is exposed via a set of functions suffixed with "_checked()", the idea being that code can choose to use the more expensive, yet more secure implementation on a case-by-case basis.
In reality, this hasn't happened, so with a grand total of zero users, let's remove the checked variants for now by simply dropping the suffix and predicating the out-of-line functions on CONFIG_REFCOUNT_FULL=y.
--- include/linux/refcount.h | 25 ++++++------------- lib/refcount.c | 54 +++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 43 deletions(-)
include/linux/refcount.h +7 -18
@@ -44,32 +44,21 @@ static inline unsigned int refcount_read(const refcount_t *r)return atomic_read (&r->refs); } -extern __must_check bool refcount_add_not_zero_checked (int i,refcount_t *r); -extern void refcount_add_checked (int i,refcount_t *r); - -extern __must_check bool refcount_inc_not_zero_checked (refcount_t *r); -extern void refcount_inc_checked (refcount_t *r); - -extern __must_check bool refcount_sub_and_test_checked (int i,refcount_t *r); - -extern __must_check bool refcount_dec_and_test_checked (refcount_t *r); -extern void refcount_dec_checked (refcount_t *r); -#ifdef CONFIG_REFCOUNT_FULL #define REFCOUNT_MAX (UINT_MAX - 1)#define REFCOUNT_SATURATED UINT_MAX -#define refcount_add_not_zero refcount_add_not_zero_checked -#define refcount_add refcount_add_checked +extern __must_check bool refcount_add_not_zero (int i,refcount_t *r); +extern void refcount_add (int i,refcount_t *r); -#define refcount_inc_not_zero refcount_inc_not_zero_checked -#define refcount_inc refcount_inc_checked +extern __must_check bool refcount_inc_not_zero (refcount_t *r); +extern void refcount_inc (refcount_t *r); -#define refcount_sub_and_test refcount_sub_and_test_checked +extern __must_check bool refcount_sub_and_test (int i,refcount_t *r); -#define refcount_dec_and_test refcount_dec_and_test_checked -#define refcount_dec refcount_dec_checked +extern __must_check bool refcount_dec_and_test (refcount_t *r); +extern void refcount_dec (refcount_t *r);#else
lib/refcount.c +29 -25
141 lines not on this page · raw message
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 4/10 lib/refcount: Move bulk of REFCOUNT_FULL implementation into header
In reply to Will DeaconIn an effort to improve performance of the REFCOUNT_FULL implementation, move the bulk of its functions into linux/refcount.h. This allows them to be inlined in the same way as if they had been provided via CONFIG_ARCH_HAS_REFCOUNT.
--- include/linux/refcount.h | 237 ++++++++++++++++++++++++++++++++++++-- lib/refcount.c | 238 +-------------------------------------- 2 files changed, 229 insertions(+), 246 deletions(-)
include/linux/refcount.h +228 -9
@@ -45,22 +45,241 @@ static inline unsigned int refcount_read(const refcount_t *r) }#ifdef CONFIG_REFCOUNT_FULL +#include <linux/bug.h> #define REFCOUNT_MAX (UINT_MAX - 1)#define REFCOUNT_SATURATED UINT_MAX -extern __must_check bool refcount_add_not_zero (int i,refcount_t *r); -extern void refcount_add (int i,refcount_t *r); +/* +* Variant of atomic_t specialized for reference counts. +* +* The interface matches the atomic_t interface (to aid in porting) but only +* provides the few functions one should use for reference counting. +* +* It differs in that the counter saturates at REFCOUNT_SATURATED and will not +* move once there. This avoids wrapping the counter and causing 'spurious' +* use-after-free issues. +* +* Memory ordering rules are slightly relaxed wrt regular atomic_t functions +* and provide only what is strictly required for refcounts. +* +* The increments are fully relaxed; these will not provide ordering. The +* rationale is that whatever is used to obtain the object we're increasing the +* reference count on will provide the ordering. For locked data structures, +* its the lock acquire, for RCU/lockless data structures its the dependent +* load. +* +* Do note that inc_not_zero() provides a control dependency which will order +* future stores against the inc, this ensures we'll never modify the object +* if we did not in fact acquire a reference. +* +* The decrements will provide release order, such that all the prior loads and +* stores will be issued before, it also provides a control dependency, which +* will order us against the subsequent free(). +* +* The control dependency is against the load of the cmpxchg (ll/sc) that +* succeeded. This means the stores aren't fully ordered, but this is fine +* because the 1->0 transition indicates no concurrency. +* +* Note that the allocator is responsible for ordering things between free() +* and alloc(). +* +* The decrements dec_and_test() and sub_and_test() also provide acquire +* ordering on success. +* +*/ + +/** +* refcount_add_not_zero - add a value to a refcount unless it is 0 +* @i: the value to add to the refcount +* @r: the refcount +* +* Will saturate at REFCOUNT_SATURATED and WARN. +* +* Provides no memory ordering, it is assumed the caller has guaranteed the +* object memory to be stable (RCU, etc.). It does provide a control dependency +* and thereby orders future stores. See the comment on top. +* +* Use of this function is not recommended for the normal reference counting +* use case in which references are taken and released one at a time. In these +* cases, refcount_inc(), or one of its variants, should instead be used to +* increment a reference count. +* +* Return: false if the passed refcount is 0, true otherwise +*/ +static inline __must_check bool refcount_add_not_zero (int i,refcount_t *r) +{ +unsigned int new, val =atomic_read (&r->refs); + +do { +if (!val) +return false; + +if (unlikely (val ==REFCOUNT_SATURATED )) +return true; + + new = val + i; +if (new < val) + new =REFCOUNT_SATURATED ; + + }while (!atomic_try_cmpxchg_relaxed (&r->refs, &val, new)); + +WARN_ONCE (new ==REFCOUNT_SATURATED , +"refcount_t: saturated; leaking memory.\n" ); + +return true; +} + +/** +* refcount_add - add a value to a refcount +* @i: the value to add to the refcount +* @r: the refcount +* +* Similar to atomic_add(), but will saturate at REFCOUNT_SATURATED and WARN. +* +* Provides no memory ordering, it is assumed the caller has guaranteed the +* object memory to be stable (RCU, etc.). It does provide a control dependency +* and thereby orders future stores. See the comment on top. +* +* Use of this function is not recommended for the normal reference counting +* use case in which references are taken and released one at a time. In these +* cases, refcount_inc(), or one of its variants, should instead be used to +* increment a reference count. +*/ +static inline void refcount_add (int i,refcount_t *r) +{ +WARN_ONCE (!refcount_add_not_zero (i, r),"refcount_t: addition on 0; use-after-free.\n" ); +} + +/** +* refcount_inc_not_zero - increment a refcount unless it is 0 +* @r: the refcount to increment +* +* Similar to atomic_inc_not_zero(), but will saturate at REFCOUNT_SATURATED +* and WARN. +* +* Provides no memory ordering, it is assumed the caller has guaranteed the +* object memory to be stable (RCU, etc.). It does provide a control dependency +* and thereby orders future stores. See the comment on top. +* +* Return: true if the increment was successful, false otherwise +*/ +static inline __must_check bool refcount_inc_not_zero (refcount_t *r) +{ +unsigned int new, val =atomic_read (&r->refs); + +do { + new = val +1 ; -extern __must_check bool refcount_inc_not_zero (refcount_t *r); -extern void refcount_inc (refcount_t *r); +if (!val) +return false; -extern __must_check bool refcount_sub_and_test (int i,refcount_t *r); +if (unlikely (!new)) +return true; -extern __must_check bool refcount_dec_and_test (refcount_t *r); -extern void refcount_dec (refcount_t *r); + }while (!atomic_try_cmpxchg_relaxed (&r->refs, &val, new)); + +WARN_ONCE (new ==REFCOUNT_SATURATED , +"refcount_t: saturated; leaking memory.\n" ); + +return true; +} + +/** +* refcount_inc - increment a refcount +* @r: the refcount to increment +* +* Similar to atomic_inc(), but will saturate at REFCOUNT_SATURATED and WARN. +* +* Provides no memory ordering, it is assumed the caller already has a +* reference on the object. +* +* Will WARN if the refcount is 0, as this represents a possible use-after-free +* condition. +*/ +static inline void refcount_inc (refcount_t *r) +{ +WARN_ONCE (!refcount_inc_not_zero (r),"refcount_t: increment on 0; use-after-free.\n" ); +} + +/** +* refcount_sub_and_test - subtract from a refcount and test if it is 0 +* @i: amount to subtract from the refcount +* @r: the refcount +* +* Similar to atomic_dec_and_test(), but it will WARN, return false and +* ultimately leak on underflow and will fail to decrement when saturated +* at REFCOUNT_SATURATED. +* +* Provides release memory ordering, such that prior loads and stores are done +* before, and provides an acquire ordering on success such that free() +* must come after. +* +* Use of this function is not recommended for the normal reference counting +* use case in which references are taken and released one at a time. In these +* cases, refcount_dec(), or one of its variants, should instead be used to +* decrement a reference count. +* +* Return: true if the resulting refcount is 0, false otherwise +*/ +static inline __must_check bool refcount_sub_and_test (int i,refcount_t *r) +{ +unsigned int new, val =atomic_read (&r->refs); + +do { +if (unlikely (val ==REFCOUNT_SATURATED )) +return false; + + new = val - i; +if (new > val) { +WARN_ONCE (new > val,"refcount_t: underflow; use-after-free.\n" ); +return false; + } + + }while (!atomic_try_cmpxchg_release (&r->refs, &val, new)); + +if (!new) { +smp_acquire__after_ctrl_dep (); +return true; + } +return false; + +} + +/** +* refcount_dec_and_test - decrement a refcount and test if it is 0 +* @r: the refcount +* +* Similar to atomic_dec_and_test(), it will WARN on underflow and fail to +* decrement when saturated at REFCOUNT_SATURATED. +* +* Provides release memory ordering, such that prior loads and stores are done +* before, and provides an acquire ordering on success such that free() +* must come after. +* +* Return: true if the resulting refcount is 0, false otherwise +*/ +static inline __must_check bool refcount_dec_and_test (refcount_t *r) +{ +return refcount_sub_and_test (1 , r); +} + +/** +* refcount_dec - decrement a refcount +* @r: the refcount +* +* Similar to atomic_dec(), it will WARN on underflow and fail to decrement +* when saturated at REFCOUNT_SATURATED. +* +* Provides release memory ordering, such that prior loads and stores are done +* before. +*/ +static inline void refcount_dec (refcount_t *r) +{ +WARN_ONCE (refcount_dec_and_test (r),"refcount_t: decrement hit 0; leaking memory.\n" ); +} -#else +#else /* CONFIG_REFCOUNT_FULL */ #define REFCOUNT_MAX INT_MAX#define REFCOUNT_SATURATED (INT_MIN / 2)
@@ -103,7 +322,7 @@ static inline void refcount_dec(refcount_t *r)atomic_dec (&r->refs); }# endif /* !CONFIG_ARCH_HAS_REFCOUNT */ -#endif /* CONFIG_REFCOUNT_FULL */ +#endif /* !CONFIG_REFCOUNT_FULL */ extern __must_check bool refcount_dec_if_one (refcount_t *r);extern __must_check bool refcount_dec_not_one (refcount_t *r);
lib/refcount.c +1 -237
249 lines not on this page · raw message
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 5/10 lib/refcount: Improve performance of generic REFCOUNT_FULL code
In reply to Will DeaconRewrite the generic REFCOUNT_FULL implementation so that the saturation point is moved to INT_MIN / 2. This allows us to defer the sanity checks until after the atomic operation, which removes many uses of cmpxchg() in favour of atomic_fetch_{add,sub}().
Some crude perf results obtained from lkdtm show substantially less overhead, despite the checking:
$ perf stat -r 3 -B -- echo {ATOMIC,REFCOUNT}_TIMING >/sys/kernel/debug/provoke-crash/DIRECT# arm64 ATOMIC_TIMING: 46.50451 +- 0.00134 seconds time elapsed ( +- 0.00% ) REFCOUNT_TIMING (REFCOUNT_FULL, mainline): 77.57522 +- 0.00982 seconds time elapsed ( +- 0.01% ) REFCOUNT_TIMING (REFCOUNT_FULL, this series): 48.7181 +- 0.0256 seconds time elapsed ( +- 0.05% )
# x86 ATOMIC_TIMING: 31.6225 +- 0.0776 seconds time elapsed ( +- 0.25% ) REFCOUNT_TIMING (!REFCOUNT_FULL, mainline/x86 asm): 31.6689 +- 0.0901 seconds time elapsed ( +- 0.28% ) REFCOUNT_TIMING (REFCOUNT_FULL, mainline): 53.203 +- 0.138 seconds time elapsed ( +- 0.26% ) REFCOUNT_TIMING (REFCOUNT_FULL, this series): 31.7408 +- 0.0486 seconds time elapsed ( +- 0.15% )
--- include/linux/refcount.h | 131 ++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 56 deletions(-)
include/linux/refcount.h +75 -56
@@ -47,8 +47,8 @@ static inline unsigned int refcount_read(const refcount_t *r)#ifdef CONFIG_REFCOUNT_FULL #include <linux/bug.h> -#define REFCOUNT_MAX (UINT_MAX - 1) -#define REFCOUNT_SATURATED UINT_MAX +#define REFCOUNT_MAX INT_MAX +#define REFCOUNT_SATURATED (INT_MIN / 2)/* * Variant of atomic_t specialized for reference counts.
@@ -56,9 +56,47 @@ static inline unsigned int refcount_read(const refcount_t *r)* The interface matches the atomic_t interface (to aid in porting) but only * provides the few functions one should use for reference counting. * -* It differs in that the counter saturates at REFCOUNT_SATURATED and will not -* move once there. This avoids wrapping the counter and causing 'spurious' -* use-after-free issues. +* Saturation semantics +* ==================== +* +* refcount_t differs from atomic_t in that the counter saturates at +* REFCOUNT_SATURATED and will not move once there. This avoids wrapping the +* counter and causing 'spurious' use-after-free issues. In order to avoid the +* cost associated with introducing cmpxchg() loops into all of the saturating +* operations, we temporarily allow the counter to take on an unchecked value +* and then explicitly set it to REFCOUNT_SATURATED on detecting that underflow +* or overflow has occurred. Although this is racy when multiple threads +* access the refcount concurrently, by placing REFCOUNT_SATURATED roughly +* equidistant from 0 and INT_MAX we minimise the scope for error: +* +* INT_MAX REFCOUNT_SATURATED UINT_MAX +* 0 (0x7fff_ffff) (0xc000_0000) (0xffff_ffff) +* +--------------------------------+----------------+----------------+ +* <---------- bad value! ----------> +* +* (in a signed view of the world, the "bad value" range corresponds to +* a negative counter value). +* +* As an example, consider a refcount_inc() operation that causes the counter +* to overflow: +* +* int old = atomic_fetch_add_relaxed(r); +* // old is INT_MAX, refcount now INT_MIN (0x8000_0000) +* if (old < 0) +* atomic_set(r, REFCOUNT_SATURATED); +* +* If another thread also performs a refcount_inc() operation between the two +* atomic operations, then the count will continue to edge closer to 0. If it +* reaches a value of 1 before /any/ of the threads reset it to the saturated +* value, then a concurrent refcount_dec_and_test() may erroneously free the +* underlying object. Given the precise timing details involved with the +* round-robin scheduling of each thread manipulating the refcount and the need +* to hit the race multiple times in succession, there doesn't appear to be a +* practical avenue of attack even if using refcount_add() operations with +* larger increments. +* +* Memory ordering +* =============== * * Memory ordering rules are slightly relaxed wrt regular atomic_t functions * and provide only what is strictly required for refcounts.
@@ -109,25 +147,19 @@ static inline unsigned int refcount_read(const refcount_t *r)*/ static inline __must_check bool refcount_add_not_zero (int i,refcount_t *r) { -unsigned int new, val =atomic_read (&r->refs); +int old =refcount_read (r);do { -if (!val) -return false; - -if (unlikely (val ==REFCOUNT_SATURATED )) -return true; - - new = val + i; -if (new < val) - new =REFCOUNT_SATURATED ; +if (!old) +break ; + }while (!atomic_try_cmpxchg_relaxed (&r->refs, &old, old + i)); - }while (!atomic_try_cmpxchg_relaxed (&r->refs, &val, new)); - -WARN_ONCE (new ==REFCOUNT_SATURATED , -"refcount_t: saturated; leaking memory.\n" ); +if (unlikely (old <0 || old + i <0 )) { +refcount_set (r,REFCOUNT_SATURATED ); +WARN_ONCE (1 ,"refcount_t: saturated; leaking memory.\n" ); + } -return true; +return old; }/**
@@ -148,7 +180,13 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)*/ static inline void refcount_add (int i,refcount_t *r) { -WARN_ONCE (!refcount_add_not_zero (i, r),"refcount_t: addition on 0; use-after-free.\n" ); +int old =atomic_fetch_add_relaxed (i, &r->refs); + +WARN_ONCE (!old,"refcount_t: addition on 0; use-after-free.\n" ); +if (unlikely (old <=0 || old + i <=0 )) { +refcount_set (r,REFCOUNT_SATURATED ); +WARN_ONCE (old,"refcount_t: saturated; leaking memory.\n" ); + } }/**
@@ -166,23 +204,7 @@ static inline void refcount_add(int i, refcount_t *r)*/ static inline __must_check bool refcount_inc_not_zero (refcount_t *r) { -unsigned int new, val =atomic_read (&r->refs); - -do { - new = val +1 ; - -if (!val) -return false; - -if (unlikely (!new)) -return true; - - }while (!atomic_try_cmpxchg_relaxed (&r->refs, &val, new)); - -WARN_ONCE (new ==REFCOUNT_SATURATED , -"refcount_t: saturated; leaking memory.\n" ); - -return true; +return refcount_add_not_zero (1 , r); }/**
@@ -199,7 +221,7 @@ static inline __must_check bool refcount_inc_not_zero(refcount_t *r)*/ static inline void refcount_inc (refcount_t *r) { -WARN_ONCE (!refcount_inc_not_zero (r),"refcount_t: increment on 0; use-after-free.\n" ); +refcount_add (1 , r); }/**
@@ -224,26 +246,19 @@ static inline void refcount_inc(refcount_t *r)*/ static inline __must_check bool refcount_sub_and_test (int i,refcount_t *r) { -unsigned int new, val =atomic_read (&r->refs); - -do { -if (unlikely (val ==REFCOUNT_SATURATED )) -return false; +int old =atomic_fetch_sub_release (i, &r->refs); - new = val - i; -if (new > val) { -WARN_ONCE (new > val,"refcount_t: underflow; use-after-free.\n" ); -return false; - } - - }while (!atomic_try_cmpxchg_release (&r->refs, &val, new)); - -if (!new) { +if (old == i) {smp_acquire__after_ctrl_dep ();return true; } -return false; +if (unlikely (old <0 || old - i <0 )) { +refcount_set (r,REFCOUNT_SATURATED ); +WARN_ONCE (1 ,"refcount_t: underflow; use-after-free.\n" ); + } + +return false; }/**
@@ -276,9 +291,13 @@ static inline __must_check bool refcount_dec_and_test(refcount_t *r)*/ static inline void refcount_dec (refcount_t *r) { -WARN_ONCE (refcount_dec_and_test (r),"refcount_t: decrement hit 0; leaking memory.\n" ); -} +int old =atomic_fetch_sub_release (1 , &r->refs); +if (unlikely (old <=1 )) { +refcount_set (r,REFCOUNT_SATURATED ); +WARN_ONCE (1 ,"refcount_t: decrement hit 0; leaking memory.\n" ); + } +}#else /* CONFIG_REFCOUNT_FULL */ #define REFCOUNT_MAX INT_MAX
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 6/10 lib/refcount: Move saturation warnings out of line
In reply to Will DeaconHaving the refcount saturation and warnings inline bloats the text, despite the fact that these paths should never be executed in normal operation.
Move the refcount saturation and warnings out of line to reduce the image size when refcount_t checking is enabled. Relative to an x86_64 defconfig, the sizes reported by bloat-o-meter are:
# defconfig+REFCOUNT_FULL, inline saturation (i.e. before this patch)
Total: Before=14762076, After=14915442, chg +1.04%
# defconfig+REFCOUNT_FULL, out-of-line saturation (i.e. after this patch)
Total: Before=14762076, After=14835497, chg +0.50%
A side-effect of this change is that we now only get one warning per refcount saturation type, rather than one per problematic call-site.
--- include/linux/refcount.h | 39 ++++++++++++++++++++------------------- lib/refcount.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 19 deletions(-)
include/linux/refcount.h +20 -19
@@ -23,6 +23,16 @@ typedef struct refcount_struct {#define REFCOUNT_INIT (n) { .refs = ATOMIC_INIT(n), } +enum refcount_saturation_type { +REFCOUNT_ADD_NOT_ZERO_OVF , +REFCOUNT_ADD_OVF , +REFCOUNT_ADD_UAF , +REFCOUNT_SUB_UAF , +REFCOUNT_DEC_LEAK , +}; + +void refcount_warn_saturate (refcount_t *r,enum refcount_saturation_type t); +/** * refcount_set - set a refcount's value * @r: the refcount
@@ -154,10 +164,8 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)break ; }while (!atomic_try_cmpxchg_relaxed (&r->refs, &old, old + i)); -if (unlikely (old <0 || old + i <0 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (1 ,"refcount_t: saturated; leaking memory.\n" ); - } +if (unlikely (old <0 || old + i <0 )) +refcount_warn_saturate (r,REFCOUNT_ADD_NOT_ZERO_OVF );return old; }
@@ -182,11 +190,10 @@ static inline void refcount_add(int i, refcount_t *r) {int old =atomic_fetch_add_relaxed (i, &r->refs); -WARN_ONCE (!old,"refcount_t: addition on 0; use-after-free.\n" ); -if (unlikely (old <=0 || old + i <=0 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (old,"refcount_t: saturated; leaking memory.\n" ); - } +if (unlikely (!old)) +refcount_warn_saturate (r,REFCOUNT_ADD_UAF ); +else if (unlikely (old <0 || old + i <0 )) +refcount_warn_saturate (r,REFCOUNT_ADD_OVF ); }/**
@@ -253,10 +260,8 @@ static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)return true; } -if (unlikely (old <0 || old - i <0 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (1 ,"refcount_t: underflow; use-after-free.\n" ); - } +if (unlikely (old <0 || old - i <0 )) +refcount_warn_saturate (r,REFCOUNT_SUB_UAF );return false; }
@@ -291,12 +296,8 @@ static inline __must_check bool refcount_dec_and_test(refcount_t *r)*/ static inline void refcount_dec (refcount_t *r) { -int old =atomic_fetch_sub_release (1 , &r->refs); - -if (unlikely (old <=1 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (1 ,"refcount_t: decrement hit 0; leaking memory.\n" ); - } +if (unlikely (atomic_fetch_sub_release (1 , &r->refs) <=1 )) +refcount_warn_saturate (r,REFCOUNT_DEC_LEAK ); }#else /* CONFIG_REFCOUNT_FULL */
lib/refcount.c +28 -0
@@ -8,6 +8,34 @@#include <linux/spinlock.h> #include <linux/bug.h> +#define REFCOUNT_WARN (str) WARN_ONCE(1, "refcount_t: " str ".\n") + +void refcount_warn_saturate (refcount_t *r,enum refcount_saturation_type t) +{ +refcount_set (r,REFCOUNT_SATURATED ); + +switch (t) { +case REFCOUNT_ADD_NOT_ZERO_OVF : +REFCOUNT_WARN ("saturated; leaking memory" ); +break ; +case REFCOUNT_ADD_OVF : +REFCOUNT_WARN ("saturated; leaking memory" ); +break ; +case REFCOUNT_ADD_UAF : +REFCOUNT_WARN ("addition on 0; use-after-free" ); +break ; +case REFCOUNT_SUB_UAF : +REFCOUNT_WARN ("underflow; use-after-free" ); +break ; +case REFCOUNT_DEC_LEAK : +REFCOUNT_WARN ("decrement hit 0; leaking memory" ); +break ; +default : +REFCOUNT_WARN ("unknown saturation event!?" ); + } +} +EXPORT_SYMBOL (refcount_warn_saturate); +/** * refcount_dec_if_one - decrement a refcount if it is 1 * @r: the refcount
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH v4 06/10] lib/refcount: Move saturation warnings out of line
Quoted 17 lines · Will Deacon
Having the refcount saturation and warnings inline bloats the text, despite the fact that these paths should never be executed in normal operation.
Move the refcount saturation and warnings out of line to reduce the image size when
refcount_tchecking is enabled. Relative to anx86_64defconfig, the sizes reported by bloat-o-meter are:# defconfig+REFCOUNT_FULL, inline saturation (i.e. before this patch)
Total: Before=14762076, After=14915442, chg +1.04%# defconfig+REFCOUNT_FULL, out-of-line saturation (i.e. after this patch)
Total: Before=14762076, After=14835497, chg +0.50%A side-effect of this change is that we now only get one warning per refcount saturation type, rather than one per problematic call-site.
Quoted 6 lines
Cc Ingo Molnar <[email protected]>Cc Elena Reshetova <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Ard Biesheuvel <[email protected]>Cc Kees Cook <[email protected]>Signed-off-by Will Deacon <[email protected]>
-Kees
Quoted 125 lines
--- include/linux/refcount.h | 39 ++++++++++++++++++++------------------- lib/refcount.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 19 deletions(-)include/linux/refcount.h +20
-19@@ -23,6 +23,16 @@ typedef struct refcount_struct {#define REFCOUNT_INIT (n) { .refs = ATOMIC_INIT(n), } +enum refcount_saturation_type { +REFCOUNT_ADD_NOT_ZERO_OVF , +REFCOUNT_ADD_OVF , +REFCOUNT_ADD_UAF , +REFCOUNT_SUB_UAF , +REFCOUNT_DEC_LEAK , +}; + +void refcount_warn_saturate (refcount_t *r,enum refcount_saturation_type t); +/** * refcount_set - set a refcount's value * @r: the refcount @@ -154,10 +164,8 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)break ; }while (!atomic_try_cmpxchg_relaxed (&r->refs, &old, old + i)); -if (unlikely (old <0 || old + i <0 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (1 ,"refcount_t: saturated; leaking memory.\n" ); - } +if (unlikely (old <0 || old + i <0 )) +refcount_warn_saturate (r,REFCOUNT_ADD_NOT_ZERO_OVF );return old; }@@ -182,11 +190,10 @@ static inline void refcount_add(int i, refcount_t *r) {int old =atomic_fetch_add_relaxed (i, &r->refs); -WARN_ONCE (!old,"refcount_t: addition on 0; use-after-free.\n" ); -if (unlikely (old <=0 || old + i <=0 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (old,"refcount_t: saturated; leaking memory.\n" ); - } +if (unlikely (!old)) +refcount_warn_saturate (r,REFCOUNT_ADD_UAF ); +else if (unlikely (old <0 || old + i <0 )) +refcount_warn_saturate (r,REFCOUNT_ADD_OVF ); }/** @@ -253,10 +260,8 @@ static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)return true; } -if (unlikely (old <0 || old - i <0 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (1 ,"refcount_t: underflow; use-after-free.\n" ); - } +if (unlikely (old <0 || old - i <0 )) +refcount_warn_saturate (r,REFCOUNT_SUB_UAF );return false; }@@ -291,12 +296,8 @@ static inline __must_check bool refcount_dec_and_test(refcount_t *r)*/ static inline void refcount_dec (refcount_t *r) { -int old =atomic_fetch_sub_release (1 , &r->refs); - -if (unlikely (old <=1 )) { -refcount_set (r,REFCOUNT_SATURATED ); -WARN_ONCE (1 ,"refcount_t: decrement hit 0; leaking memory.\n" ); - } +if (unlikely (atomic_fetch_sub_release (1 , &r->refs) <=1 )) +refcount_warn_saturate (r,REFCOUNT_DEC_LEAK ); }#else /* CONFIG_REFCOUNT_FULL */ lib/refcount.c +28
-0@@ -8,6 +8,34 @@#include <linux/spinlock.h> #include <linux/bug.h> +#define REFCOUNT_WARN (str) WARN_ONCE(1, "refcount_t: " str ".\n") + +void refcount_warn_saturate (refcount_t *r,enum refcount_saturation_type t) +{ +refcount_set (r,REFCOUNT_SATURATED ); + +switch (t) { +case REFCOUNT_ADD_NOT_ZERO_OVF : +REFCOUNT_WARN ("saturated; leaking memory" ); +break ; +case REFCOUNT_ADD_OVF : +REFCOUNT_WARN ("saturated; leaking memory" ); +break ; +case REFCOUNT_ADD_UAF : +REFCOUNT_WARN ("addition on 0; use-after-free" ); +break ; +case REFCOUNT_SUB_UAF : +REFCOUNT_WARN ("underflow; use-after-free" ); +break ; +case REFCOUNT_DEC_LEAK : +REFCOUNT_WARN ("decrement hit 0; leaking memory" ); +break ; +default : +REFCOUNT_WARN ("unknown saturation event!?" ); + } +} +EXPORT_SYMBOL (refcount_warn_saturate); +/** * refcount_dec_if_one - decrement a refcount if it is 1 * @r: the refcount Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Signature · 1 line
Kees Cook
Will Deacon
maintainerPATCH v4 7/10 lib/refcount: Consolidate REFCOUNT_{MAX,SATURATED} definitions
In reply to Will DeaconThe definitions of REFCOUNT_MAX and REFCOUNT_SATURATED are the same, regardless of CONFIG_REFCOUNT_FULL, so consolidate them into a single pair of definitions.
--- include/linux/refcount.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
include/linux/refcount.h +2 -7
@@ -22,6 +22,8 @@ typedef struct refcount_struct { } refcount_t;#define REFCOUNT_INIT (n) { .refs = ATOMIC_INIT(n), } +#define REFCOUNT_MAX INT_MAX +#define REFCOUNT_SATURATED (INT_MIN / 2)enum refcount_saturation_type {REFCOUNT_ADD_NOT_ZERO_OVF ,
@@ -57,9 +59,6 @@ static inline unsigned int refcount_read(const refcount_t *r)#ifdef CONFIG_REFCOUNT_FULL #include <linux/bug.h> -#define REFCOUNT_MAX INT_MAX -#define REFCOUNT_SATURATED (INT_MIN / 2) -/* * Variant of atomic_t specialized for reference counts. *
@@ -300,10 +299,6 @@ static inline void refcount_dec(refcount_t *r) refcount_warn_saturate(r, REFCOUNT_DEC_LEAK); }#else /* CONFIG_REFCOUNT_FULL */ - -#define REFCOUNT_MAX INT_MAX -#define REFCOUNT_SATURATED (INT_MIN / 2) -# ifdef CONFIG_ARCH_HAS_REFCOUNT # include <asm/refcount.h> # else
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 8/10 refcount: Consolidate implementations of refcount_t
In reply to Will DeaconThe generic implementation of refcount_t should be good enough for everybody, so remove ARCH_HAS_REFCOUNT and REFCOUNT_FULL entirely, leaving the generic implementation enabled unconditionally.
--- arch/Kconfig | 21 ---- arch/arm/Kconfig | 1 - arch/arm64/Kconfig | 1 - arch/s390/configs/debug_defconfig | 1 - arch/x86/Kconfig | 1 - arch/x86/include/asm/asm.h | 6 -- arch/x86/include/asm/refcount.h | 126 ----------------------- arch/x86/mm/extable.c | 49 --------- drivers/gpu/drm/i915/Kconfig.debug | 1 - include/linux/refcount.h | 158 +++++++++++------------------ lib/refcount.c | 2 +- 11 files changed, 59 insertions(+), 308 deletions(-) delete mode 100644 arch/x86/include/asm/refcount.h
arch/Kconfig +0 -21
@@ -892,27 +892,6 @@ config STRICT_MODULE_RWX config ARCH_HAS_PHYS_TO_DMA bool -config ARCH_HAS_REFCOUNT - bool - help - An architecture selects this when it has implemented refcount_t - using open coded assembly primitives that provide an optimized - refcount_t implementation, possibly at the expense of some full - refcount state checks of CONFIG_REFCOUNT_FULL=y. - - The refcount overflow check behavior, however, must be retained. - Catching overflows is the primary security concern for protecting - against bugs in reference counts. - -config REFCOUNT_FULL - bool "Perform full reference count validation at the expense of speed" - help - Enabling this switches the refcounting infrastructure from a fast - unchecked atomic_t implementation to a fully state checked - implementation, which can be (slightly) slower but provides protections - against various use-after-free conditions that can be used in - security flaw exploits. - config HAVE_ARCH_COMPILER_H bool help
arch/arm/Kconfig +0 -1
@@ -117,7 +117,6 @@ config ARM select OLD_SIGSUSPEND3 select PCI_SYSCALL if PCI select PERF_USE_VMALLOC - select REFCOUNT_FULL select RTC_LIB select SYS_SUPPORTS_APM_EMULATION # Above selects are sorted alphabetically; please add new ones
arch/arm64/Kconfig +0 -1
@@ -181,7 +181,6 @@ config ARM64 select PCI_SYSCALL if PCI select POWER_RESET select POWER_SUPPLY - select REFCOUNT_FULL select SPARSE_IRQ select SWIOTLB select SYSCTL_EXCEPTION_TRACE
arch/s390/configs/debug_defconfig +0 -1
@@ -62,7 +62,6 @@ CONFIG_OPROFILE=m CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y CONFIG_STATIC_KEYS_SELFTEST=y -CONFIG_REFCOUNT_FULL=y CONFIG_LOCK_EVENT_COUNTS=y CONFIG_MODULES=y CONFIG_MODULE_FORCE_LOAD=y
arch/x86/Kconfig +0 -1
@@ -73,7 +73,6 @@ config X86 select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_PTE_DEVMAP if X86_64 select ARCH_HAS_PTE_SPECIAL - select ARCH_HAS_REFCOUNT select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_UACCESS_MCSAFE if X86_64 && X86_MCE select ARCH_HAS_SET_MEMORY
arch/x86/include/asm/asm.h +0 -6
@@ -139,9 +139,6 @@# define _ASM_EXTABLE_EX (from, to) \ _ASM_EXTABLE_HANDLE(from, to, ex_handler_ext) -# define _ASM_EXTABLE_REFCOUNT (from, to) \ - _ASM_EXTABLE_HANDLE(from, to, ex_handler_refcount) -# define _ASM_NOKPROBE (entry) \ .pushsection "_kprobe_blacklist","aw" ; \ _ASM_ALIGN ; \
@@ -170,9 +167,6 @@# define _ASM_EXTABLE_EX (from, to) \ _ASM_EXTABLE_HANDLE(from, to, ex_handler_ext) -# define _ASM_EXTABLE_REFCOUNT (from, to) \ - _ASM_EXTABLE_HANDLE(from, to, ex_handler_refcount) -/* For C file, we already have NOKPROBE_SYMBOL macro */ #endif
arch/x86/include/asm/refcount.h deleted +0 -126
126 lines not on this page · raw message
arch/x86/mm/extable.c +0 -49
55 lines not on this page · raw message
drivers/gpu/drm/i915/Kconfig.debug +0 -1
@@ -22,7 +22,6 @@ config DRM_I915_DEBUG depends on DRM_I915 select DEBUG_FS select PREEMPT_COUNT - select REFCOUNT_FULL select I2C_CHARDEV select STACKDEPOT select DRM_DP_AUX_CHARDEV
include/linux/refcount.h +58 -100
174 lines not on this page · raw message
lib/refcount.c +1 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* Out-of-line refcount functions common to all refcount implementations. +* Out-of-line refcount functions. */ #include <linux/mutex.h>
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 9/10 lib/refcount: Remove unused 'refcount_error_report()' function
In reply to Will Deacon'refcount_error_report()' has no callers. Remove it.
--- include/linux/kernel.h | 7 ------- kernel/panic.c | 11 ----------- 2 files changed, 18 deletions(-)
include/linux/kernel.h +0 -7
@@ -328,13 +328,6 @@ extern int oops_may_print(void);void do_exit (long error_code)__noreturn ;void complete_and_exit (struct completion *,long )__noreturn ; -#ifdef CONFIG_ARCH_HAS_REFCOUNT -void refcount_error_report (struct pt_regs *regs,const char *err); -#else -static inline void refcount_error_report (struct pt_regs *regs,const char *err) -{ } -#endif -/* Internal, do not use. */ int __must_check _kstrtoul (const char *s,unsigned int base,unsigned long *res);int __must_check _kstrtol (const char *s,unsigned int base,long *res);
kernel/panic.c +0 -11
@@ -670,17 +670,6 @@ EXPORT_SYMBOL(__stack_chk_fail);#endif -#ifdef CONFIG_ARCH_HAS_REFCOUNT -void refcount_error_report (struct pt_regs *regs,const char *err) -{ -WARN_RATELIMIT (1 ,"refcount_t %s at %pB in %s[%d], uid/euid: %u/%u\n" , - err, (void *)instruction_pointer (regs), - current->comm,task_pid_nr (current), -from_kuid_munged (&init_user_ns,current_uid ()), -from_kuid_munged (&init_user_ns,current_euid ())); -} -#endif -core_param (panic, panic_timeout, int,0644 );core_param (panic_print, panic_print, ulong,0644 );core_param (pause_on_oops, pause_on_oops, int,0644 );
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Will Deacon
maintainerPATCH v4 10/10 drivers/lkdtm: Remove references to CONFIG_REFCOUNT_FULL
In reply to Will DeaconCONFIG_REFCOUNT_FULL no longer exists, so remove all references to it.
--- drivers/misc/lkdtm/refcount.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/misc/lkdtm/refcount.c +1 -2
@@ -119,7 +119,7 @@ void lkdtm_REFCOUNT_DEC_ZERO(void)static void check_negative (refcount_t *ref,int start) {/* -* CONFIG_REFCOUNT_FULL refuses to move a refcount at all on an +* refcount_t refuses to move a refcount at all on an * over-sub, so we have to track our starting position instead of * looking only at zero-pinning. */
@@ -202,7 +202,6 @@ static void check_from_zero(refcount_t *ref)/* * A refcount_inc() from zero should pin to zero or saturate and may WARN. -* Only CONFIG_REFCOUNT_FULL provides this protection currently. */ void lkdtm_REFCOUNT_INC_ZERO (void ) {
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Quoted 8 lines · Will Deacon
Hi all,
This is version four of the patches I previously posted here:
v1: https://lkml.kernel.org/r/[email protected]
v2: https://lkml.kernel.org/r/[email protected]
v3: https://lkml.kernel.org/r/[email protected]
Quoted 5 lines
Changes since v3 include:
- Add description of racy behaviour
include/linux/refcount.h
- Fix saturation behaviour inrefcount_sub_and_test()
- Added Acks and Tested-bys
Thanks again for this! I think this series is in good shape; I'm glad we can sanely expand these protections.
Signature · 1 line
Kees Cook
Will Deacon
maintainerQuoted 9 lines · Kees Cook
Quoted 8 lines · Will Deacon
Hi all,
This is version four of the patches I previously posted here:
v1: https://lkml.kernel.org/r/[email protected]
v2: https://lkml.kernel.org/r/[email protected]
v3: https://lkml.kernel.org/r/[email protected]
Quoted 8 lines
Quoted 5 lines
Changes since v3 include:
- Add description of racy behaviour
include/linux/refcount.h
- Fix saturation behaviour inrefcount_sub_and_test()
- Added Acks and Tested-bysThanks again for this! I think this series is in good shape; I'm glad we can sanely expand these protections.
Cheers, Kees.
Peter -- are you ok with this version? I think I've addressed all of your concerns from v3, including the addition of ASCII-art to explain the saturation behaviour (I can use .rst instead if you prefer).
Will