Commit 8c1ed302 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ffs const-attribute cleanups from Kees Cook:
 "While working on various hardening refactoring a while back we
  encountered inconsistencies in the application of __attribute_const__
  on the ffs() family of functions.

  This series fixes this across all archs and adds KUnit tests.

  Notably, this found a theoretical underflow in PCI (also fixed here)
  and uncovered an inefficiency in ARC (fixed in the ARC arch PR). I
  kept the series separate from the general hardening PR since it is a
  stand-alone "topic".

   - PCI: Fix theoretical underflow in use of ffs().

   - Universally apply __attribute_const__ to all architecture's
     ffs()-family of functions.

   - Add KUnit tests for ffs() behavior and const-ness"

* tag 'ffs-const-v6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  KUnit: ffs: Validate all the __attribute_const__ annotations
  sparc: Add __attribute_const__ to ffs()-family implementations
  xtensa: Add __attribute_const__ to ffs()-family implementations
  s390: Add __attribute_const__ to ffs()-family implementations
  parisc: Add __attribute_const__ to ffs()-family implementations
  mips: Add __attribute_const__ to ffs()-family implementations
  m68k: Add __attribute_const__ to ffs()-family implementations
  openrisc: Add __attribute_const__ to ffs()-family implementations
  riscv: Add __attribute_const__ to ffs()-family implementations
  hexagon: Add __attribute_const__ to ffs()-family implementations
  alpha: Add __attribute_const__ to ffs()-family implementations
  sh: Add __attribute_const__ to ffs()-family implementations
  powerpc: Add __attribute_const__ to ffs()-family implementations
  x86: Add __attribute_const__ to ffs()-family implementations
  csky: Add __attribute_const__ to ffs()-family implementations
  bitops: Add __attribute_const__ to generic ffs()-family implementations
  KUnit: Introduce ffs()-family tests
  PCI: Test for bit underflow in pcie_set_readrq()
parents 1896ce8e 95719dfa
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -328,7 +328,7 @@ static inline unsigned long ffz_b(unsigned long x)
	return sum;
}

static inline unsigned long ffz(unsigned long word)
static inline unsigned long __attribute_const__ ffz(unsigned long word)
{
#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
	/* Whee.  EV67 can calculate it directly.  */
@@ -348,7 +348,7 @@ static inline unsigned long ffz(unsigned long word)
/*
 * __ffs = Find First set bit in word.  Undefined if no set bit exists.
 */
static inline unsigned long __ffs(unsigned long word)
static inline __attribute_const__ unsigned long __ffs(unsigned long word)
{
#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
	/* Whee.  EV67 can calculate it directly.  */
@@ -373,7 +373,7 @@ static inline unsigned long __ffs(unsigned long word)
 * differs in spirit from the above __ffs.
 */

static inline int ffs(int word)
static inline __attribute_const__ int ffs(int word)
{
	int result = __ffs(word) + 1;
	return word ? result : 0;
@@ -383,14 +383,14 @@ static inline int ffs(int word)
 * fls: find last bit set.
 */
#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
static inline int fls64(unsigned long word)
static inline __attribute_const__ int fls64(unsigned long word)
{
	return 64 - __kernel_ctlz(word);
}
#else
extern const unsigned char __flsm1_tab[256];

static inline int fls64(unsigned long x)
static inline __attribute_const__ int fls64(unsigned long x)
{
	unsigned long t, a, r;

@@ -403,12 +403,12 @@ static inline int fls64(unsigned long x)
}
#endif

static inline unsigned long __fls(unsigned long x)
static inline __attribute_const__ unsigned long __fls(unsigned long x)
{
	return fls64(x) - 1;
}

static inline int fls(unsigned int x)
static inline __attribute_const__ int fls(unsigned int x)
{
	return fls64(x);
}
+4 −4
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@
/*
 * asm-generic/bitops/ffs.h
 */
static inline int ffs(int x)
static inline __attribute_const__ int ffs(int x)
{
	if (!x)
		return 0;
@@ -26,7 +26,7 @@ static inline int ffs(int x)
/*
 * asm-generic/bitops/__ffs.h
 */
static __always_inline unsigned long __ffs(unsigned long x)
static __always_inline __attribute_const__ unsigned long __ffs(unsigned long x)
{
	asm volatile (
		"brev %0\n"
@@ -39,7 +39,7 @@ static __always_inline unsigned long __ffs(unsigned long x)
/*
 * asm-generic/bitops/fls.h
 */
static __always_inline int fls(unsigned int x)
static __always_inline __attribute_const__ int fls(unsigned int x)
{
	asm volatile(
		"ff1 %0\n"
@@ -52,7 +52,7 @@ static __always_inline int fls(unsigned int x)
/*
 * asm-generic/bitops/__fls.h
 */
static __always_inline unsigned long __fls(unsigned long x)
static __always_inline __attribute_const__ unsigned long __fls(unsigned long x)
{
	return fls(x) - 1;
}
+5 −5
Original line number Diff line number Diff line
@@ -200,7 +200,7 @@ arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
 *
 * Undefined if no zero exists, so code should check against ~0UL first.
 */
static inline long ffz(int x)
static inline long __attribute_const__ ffz(int x)
{
	int r;

@@ -217,7 +217,7 @@ static inline long ffz(int x)
 * This is defined the same way as ffs.
 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
 */
static inline int fls(unsigned int x)
static inline __attribute_const__ int fls(unsigned int x)
{
	int r;

@@ -238,7 +238,7 @@ static inline int fls(unsigned int x)
 * the libc and compiler builtin ffs routines, therefore
 * differs in spirit from the above ffz (man ffs).
 */
static inline int ffs(int x)
static inline __attribute_const__ int ffs(int x)
{
	int r;

@@ -260,7 +260,7 @@ static inline int ffs(int x)
 * bits_per_long assumed to be 32
 * numbering starts at 0 I think (instead of 1 like ffs)
 */
static inline unsigned long __ffs(unsigned long word)
static inline __attribute_const__ unsigned long __ffs(unsigned long word)
{
	int num;

@@ -278,7 +278,7 @@ static inline unsigned long __ffs(unsigned long word)
 * Undefined if no set bit exists, so code should check against 0 first.
 * bits_per_long assumed to be 32
 */
static inline unsigned long __fls(unsigned long word)
static inline __attribute_const__ unsigned long __fls(unsigned long word)
{
	int num;

+7 −7
Original line number Diff line number Diff line
@@ -465,7 +465,7 @@ static inline int find_next_bit(const unsigned long *vaddr, int size,
 * ffz = Find First Zero in word. Undefined if no zero exists,
 * so code should check against ~0UL first..
 */
static inline unsigned long ffz(unsigned long word)
static inline unsigned long __attribute_const__ ffz(unsigned long word)
{
	int res;

@@ -488,7 +488,7 @@ static inline unsigned long ffz(unsigned long word)
 */
#if (defined(__mcfisaaplus__) || defined(__mcfisac__)) && \
	!defined(CONFIG_M68000)
static inline unsigned long __ffs(unsigned long x)
static inline __attribute_const__ unsigned long __ffs(unsigned long x)
{
	__asm__ __volatile__ ("bitrev %0; ff1 %0"
		: "=d" (x)
@@ -496,7 +496,7 @@ static inline unsigned long __ffs(unsigned long x)
	return x;
}

static inline int ffs(int x)
static inline __attribute_const__ int ffs(int x)
{
	if (!x)
		return 0;
@@ -518,7 +518,7 @@ static inline int ffs(int x)
 *	the libc and compiler builtin ffs routines, therefore
 *	differs in spirit from the above ffz (man ffs).
 */
static inline int ffs(int x)
static inline __attribute_const__ int ffs(int x)
{
	int cnt;

@@ -528,7 +528,7 @@ static inline int ffs(int x)
	return 32 - cnt;
}

static inline unsigned long __ffs(unsigned long x)
static inline __attribute_const__ unsigned long __ffs(unsigned long x)
{
	return ffs(x) - 1;
}
@@ -536,7 +536,7 @@ static inline unsigned long __ffs(unsigned long x)
/*
 *	fls: find last bit set.
 */
static inline int fls(unsigned int x)
static inline __attribute_const__ int fls(unsigned int x)
{
	int cnt;

@@ -546,7 +546,7 @@ static inline int fls(unsigned int x)
	return 32 - cnt;
}

static inline unsigned long __fls(unsigned long x)
static inline __attribute_const__ unsigned long __fls(unsigned long x)
{
	return fls(x) - 1;
}
+4 −4
Original line number Diff line number Diff line
@@ -327,7 +327,7 @@ static inline void __clear_bit_unlock(unsigned long nr, volatile unsigned long *
 * Return the bit position (0..63) of the most significant 1 bit in a word
 * Returns -1 if no 1 bit exists
 */
static __always_inline unsigned long __fls(unsigned long word)
static __always_inline __attribute_const__ unsigned long __fls(unsigned long word)
{
	int num;

@@ -393,7 +393,7 @@ static __always_inline unsigned long __fls(unsigned long word)
 * Returns 0..SZLONG-1
 * Undefined if no bit exists, so code should check against 0 first.
 */
static __always_inline unsigned long __ffs(unsigned long word)
static __always_inline __attribute_const__ unsigned long __ffs(unsigned long word)
{
	return __fls(word & -word);
}
@@ -405,7 +405,7 @@ static __always_inline unsigned long __ffs(unsigned long word)
 * This is defined the same way as ffs.
 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
 */
static inline int fls(unsigned int x)
static inline __attribute_const__ int fls(unsigned int x)
{
	int r;

@@ -458,7 +458,7 @@ static inline int fls(unsigned int x)
 * the libc and compiler builtin ffs routines, therefore
 * differs in spirit from the below ffz (man ffs).
 */
static inline int ffs(int word)
static inline __attribute_const__ int ffs(int word)
{
	if (!word)
		return 0;
Loading