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

Commit 3e865c20 authored by Will Deacon's avatar Will Deacon Committed by Bernhard Thoben
Browse files

locking/refcount: Ensure integer operands are treated as signed



In 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.

Signed-off-by: default avatarWill Deacon <will@kernel.org>
Reviewed-by: default avatarArd Biesheuvel <ardb@kernel.org>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Tested-by: default avatarHanjun Guo <guohanjun@huawei.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Elena Reshetova <elena.reshetova@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20191121115902.2551-3-will@kernel.org


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
(cherry picked from commit 97a1420adf0cdf0cf6f41bab0b2acf658c96b94b)
parent 42e7c229
Loading
Loading
Loading
Loading
+7 −7
Original line number Original line Diff line number Diff line
@@ -27,7 +27,7 @@ typedef struct refcount_struct {
 * @r: the refcount
 * @r: the refcount
 * @n: value to which the refcount will be set
 * @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);
	atomic_set(&r->refs, n);
}
}
@@ -43,13 +43,13 @@ static inline unsigned int refcount_read(const refcount_t *r)
	return atomic_read(&r->refs);
	return atomic_read(&r->refs);
}
}


extern __must_check bool refcount_add_not_zero_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(unsigned 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 __must_check bool refcount_inc_not_zero_checked(refcount_t *r);
extern void refcount_inc_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 __must_check bool refcount_dec_and_test_checked(refcount_t *r);
extern void refcount_dec_checked(refcount_t *r);
extern void refcount_dec_checked(refcount_t *r);
@@ -80,12 +80,12 @@ extern void refcount_sub(unsigned int i, refcount_t *r);
# ifdef CONFIG_ARCH_HAS_REFCOUNT
# ifdef CONFIG_ARCH_HAS_REFCOUNT
#  include <asm/refcount.h>
#  include <asm/refcount.h>
# else
# 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);
	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);
	atomic_add(i, &r->refs);
}
}
@@ -100,7 +100,7 @@ static inline void refcount_inc(refcount_t *r)
	atomic_inc(&r->refs);
	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);
	return atomic_sub_and_test(i, &r->refs);
}
}
+3 −3
Original line number Original line Diff line number Diff line
@@ -60,7 +60,7 @@
 *
 *
 * Return: false if the passed refcount is 0, true otherwise
 * 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);
	unsigned int new, val = atomic_read(&r->refs);


@@ -100,7 +100,7 @@ EXPORT_SYMBOL(refcount_add_not_zero_checked);
 * cases, refcount_inc(), or one of its variants, should instead be used to
 * cases, refcount_inc(), or one of its variants, should instead be used to
 * increment a reference count.
 * 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");
	WARN_ONCE(!refcount_add_not_zero_checked(i, r), "refcount_t: addition on 0; use-after-free.\n");
}
}
@@ -179,7 +179,7 @@ EXPORT_SYMBOL(refcount_inc_checked);
 *
 *
 * Return: true if the resulting refcount is 0, false otherwise
 * 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);
	unsigned int new, val = atomic_read(&r->refs);