mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-27 03:28:09 -04:00
Merge tag 'hardening-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull kernel hardening updates from Kees Cook:
- Convert flexible array members, fix -Wstringop-overflow warnings, and
fix KCFI function type mismatches that went ignored by maintainers
(Gustavo A. R. Silva, Nathan Chancellor, Kees Cook)
- Remove the remaining side-effect users of ksize() by converting
dma-buf, btrfs, and coredump to using kmalloc_size_roundup(), add
more __alloc_size attributes, and introduce full testing of all
allocator functions. Finally remove the ksize() side-effect so that
each allocation-aware checker can finally behave without exceptions
- Introduce oops_limit (default 10,000) and warn_limit (default off) to
provide greater granularity of control for panic_on_oops and
panic_on_warn (Jann Horn, Kees Cook)
- Introduce overflows_type() and castable_to_type() helpers for cleaner
overflow checking
- Improve code generation for strscpy() and update str*() kern-doc
- Convert strscpy and sigphash tests to KUnit, and expand memcpy tests
- Always use a non-NULL argument for prepare_kernel_cred()
- Disable structleak plugin in FORTIFY KUnit test (Anders Roxell)
- Adjust orphan linker section checking to respect CONFIG_WERROR (Xin
Li)
- Make sure siginfo is cleared for forced SIGKILL (haifeng.xu)
- Fix um vs FORTIFY warnings for always-NULL arguments
* tag 'hardening-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: (31 commits)
ksmbd: replace one-element arrays with flexible-array members
hpet: Replace one-element array with flexible-array member
um: virt-pci: Avoid GCC non-NULL warning
signal: Initialize the info in ksignal
lib: fortify_kunit: build without structleak plugin
panic: Expose "warn_count" to sysfs
panic: Introduce warn_limit
panic: Consolidate open-coded panic_on_warn checks
exit: Allow oops_limit to be disabled
exit: Expose "oops_count" to sysfs
exit: Put an upper limit on how often we can oops
panic: Separate sysctl logic from CONFIG_SMP
mm/pgtable: Fix multiple -Wstringop-overflow warnings
mm: Make ksize() a reporting-only function
kunit/fortify: Validate __alloc_size attribute results
drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
driver core: Add __alloc_size hint to devm allocators
overflow: Introduce overflows_type() and castable_to_type()
coredump: Proactively round up to kmalloc bucket size
...
This commit is contained in:
@@ -236,6 +236,7 @@ static inline void *offset_to_ptr(const int *off)
|
||||
* bool and also pointer types.
|
||||
*/
|
||||
#define is_signed_type(type) (((type)(-1)) < (__force type)1)
|
||||
#define is_unsigned_type(type) (!is_signed_type(type))
|
||||
|
||||
/*
|
||||
* This is needed in functions which generate the stack canary, see
|
||||
|
||||
@@ -197,9 +197,9 @@ void devres_remove_group(struct device *dev, void *id);
|
||||
int devres_release_group(struct device *dev, void *id);
|
||||
|
||||
/* managed devm_k.alloc/kfree for device drivers */
|
||||
void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __malloc;
|
||||
void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __alloc_size(2);
|
||||
void *devm_krealloc(struct device *dev, void *ptr, size_t size,
|
||||
gfp_t gfp) __must_check;
|
||||
gfp_t gfp) __must_check __realloc_size(3);
|
||||
__printf(3, 0) char *devm_kvasprintf(struct device *dev, gfp_t gfp,
|
||||
const char *fmt, va_list ap) __malloc;
|
||||
__printf(3, 4) char *devm_kasprintf(struct device *dev, gfp_t gfp,
|
||||
@@ -226,7 +226,8 @@ static inline void *devm_kcalloc(struct device *dev,
|
||||
void devm_kfree(struct device *dev, const void *p);
|
||||
char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
|
||||
const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);
|
||||
void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp);
|
||||
void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp)
|
||||
__realloc_size(3);
|
||||
|
||||
unsigned long devm_get_free_pages(struct device *dev,
|
||||
gfp_t gfp_mask, unsigned int order);
|
||||
|
||||
@@ -18,7 +18,7 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning("
|
||||
|
||||
#define __compiletime_strlen(p) \
|
||||
({ \
|
||||
unsigned char *__p = (unsigned char *)(p); \
|
||||
char *__p = (char *)(p); \
|
||||
size_t __ret = SIZE_MAX; \
|
||||
size_t __p_size = __member_size(p); \
|
||||
if (__p_size != SIZE_MAX && \
|
||||
@@ -119,13 +119,13 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size)
|
||||
* Instead, please choose an alternative, so that the expectation
|
||||
* of @p's contents is unambiguous:
|
||||
*
|
||||
* +--------------------+-----------------+------------+
|
||||
* | @p needs to be: | padded to @size | not padded |
|
||||
* +====================+=================+============+
|
||||
* | NUL-terminated | strscpy_pad() | strscpy() |
|
||||
* +--------------------+-----------------+------------+
|
||||
* | not NUL-terminated | strtomem_pad() | strtomem() |
|
||||
* +--------------------+-----------------+------------+
|
||||
* +--------------------+--------------------+------------+
|
||||
* | **p** needs to be: | padded to **size** | not padded |
|
||||
* +====================+====================+============+
|
||||
* | NUL-terminated | strscpy_pad() | strscpy() |
|
||||
* +--------------------+--------------------+------------+
|
||||
* | not NUL-terminated | strtomem_pad() | strtomem() |
|
||||
* +--------------------+--------------------+------------+
|
||||
*
|
||||
* Note strscpy*()'s differing return values for detecting truncation,
|
||||
* and strtomem*()'s expectation that the destination is marked with
|
||||
@@ -144,6 +144,21 @@ char *strncpy(char * const POS p, const char *q, __kernel_size_t size)
|
||||
return __underlying_strncpy(p, q, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* strcat - Append a string to an existing string
|
||||
*
|
||||
* @p: pointer to NUL-terminated string to append to
|
||||
* @q: pointer to NUL-terminated source string to append from
|
||||
*
|
||||
* Do not use this function. While FORTIFY_SOURCE tries to avoid
|
||||
* read and write overflows, this is only possible when the
|
||||
* destination buffer size is known to the compiler. Prefer
|
||||
* building the string with formatting, via scnprintf() or similar.
|
||||
* At the very least, use strncat().
|
||||
*
|
||||
* Returns @p.
|
||||
*
|
||||
*/
|
||||
__FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2)
|
||||
char *strcat(char * const POS p, const char *q)
|
||||
{
|
||||
@@ -157,6 +172,16 @@ char *strcat(char * const POS p, const char *q)
|
||||
}
|
||||
|
||||
extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);
|
||||
/**
|
||||
* strnlen - Return bounded count of characters in a NUL-terminated string
|
||||
*
|
||||
* @p: pointer to NUL-terminated string to count.
|
||||
* @maxlen: maximum number of characters to count.
|
||||
*
|
||||
* Returns number of characters in @p (NOT including the final NUL), or
|
||||
* @maxlen, if no NUL has been found up to there.
|
||||
*
|
||||
*/
|
||||
__FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size_t maxlen)
|
||||
{
|
||||
size_t p_size = __member_size(p);
|
||||
@@ -182,6 +207,19 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size
|
||||
* possible for strlen() to be used on compile-time strings for use in
|
||||
* static initializers (i.e. as a constant expression).
|
||||
*/
|
||||
/**
|
||||
* strlen - Return count of characters in a NUL-terminated string
|
||||
*
|
||||
* @p: pointer to NUL-terminated string to count.
|
||||
*
|
||||
* Do not use this function unless the string length is known at
|
||||
* compile-time. When @p is unterminated, this function may crash
|
||||
* or return unexpected counts that could lead to memory content
|
||||
* exposures. Prefer strnlen().
|
||||
*
|
||||
* Returns number of characters in @p (NOT including the final NUL).
|
||||
*
|
||||
*/
|
||||
#define strlen(p) \
|
||||
__builtin_choose_expr(__is_constexpr(__builtin_strlen(p)), \
|
||||
__builtin_strlen(p), __fortify_strlen(p))
|
||||
@@ -200,8 +238,26 @@ __kernel_size_t __fortify_strlen(const char * const POS p)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* defined after fortified strlen to reuse it */
|
||||
/* Defined after fortified strlen() to reuse it. */
|
||||
extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy);
|
||||
/**
|
||||
* strlcpy - Copy a string into another string buffer
|
||||
*
|
||||
* @p: pointer to destination of copy
|
||||
* @q: pointer to NUL-terminated source string to copy
|
||||
* @size: maximum number of bytes to write at @p
|
||||
*
|
||||
* If strlen(@q) >= @size, the copy of @q will be truncated at
|
||||
* @size - 1 bytes. @p will always be NUL-terminated.
|
||||
*
|
||||
* Do not use this function. While FORTIFY_SOURCE tries to avoid
|
||||
* over-reads when calculating strlen(@q), it is still possible.
|
||||
* Prefer strscpy(), though note its different return values for
|
||||
* detecting truncation.
|
||||
*
|
||||
* Returns total number of bytes written to @p, including terminating NUL.
|
||||
*
|
||||
*/
|
||||
__FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, size_t size)
|
||||
{
|
||||
size_t p_size = __member_size(p);
|
||||
@@ -227,8 +283,32 @@ __FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, si
|
||||
return q_len;
|
||||
}
|
||||
|
||||
/* defined after fortified strnlen to reuse it */
|
||||
/* Defined after fortified strnlen() to reuse it. */
|
||||
extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy);
|
||||
/**
|
||||
* strscpy - Copy a C-string into a sized buffer
|
||||
*
|
||||
* @p: Where to copy the string to
|
||||
* @q: Where to copy the string from
|
||||
* @size: Size of destination buffer
|
||||
*
|
||||
* Copy the source string @p, or as much of it as fits, into the destination
|
||||
* @q buffer. The behavior is undefined if the string buffers overlap. The
|
||||
* destination @p buffer is always NUL terminated, unless it's zero-sized.
|
||||
*
|
||||
* Preferred to strlcpy() since the API doesn't require reading memory
|
||||
* from the source @q string beyond the specified @size bytes, and since
|
||||
* the return value is easier to error-check than strlcpy()'s.
|
||||
* In addition, the implementation is robust to the string changing out
|
||||
* from underneath it, unlike the current strlcpy() implementation.
|
||||
*
|
||||
* Preferred to strncpy() since it always returns a valid string, and
|
||||
* doesn't unnecessarily force the tail of the destination buffer to be
|
||||
* zero padded. If padding is desired please use strscpy_pad().
|
||||
*
|
||||
* Returns the number of characters copied in @p (not including the
|
||||
* trailing %NUL) or -E2BIG if @size is 0 or the copy of @q was truncated.
|
||||
*/
|
||||
__FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, size_t size)
|
||||
{
|
||||
size_t len;
|
||||
@@ -247,6 +327,16 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s
|
||||
if (__compiletime_lessthan(p_size, size))
|
||||
__write_overflow();
|
||||
|
||||
/* Short-circuit for compile-time known-safe lengths. */
|
||||
if (__compiletime_lessthan(p_size, SIZE_MAX)) {
|
||||
len = __compiletime_strlen(q);
|
||||
|
||||
if (len < SIZE_MAX && __compiletime_lessthan(len, size)) {
|
||||
__underlying_memcpy(p, q, len + 1);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This call protects from read overflow, because len will default to q
|
||||
* length if it smaller than size.
|
||||
@@ -274,7 +364,26 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s
|
||||
return __real_strscpy(p, q, len);
|
||||
}
|
||||
|
||||
/* defined after fortified strlen and strnlen to reuse them */
|
||||
/**
|
||||
* strncat - Append a string to an existing string
|
||||
*
|
||||
* @p: pointer to NUL-terminated string to append to
|
||||
* @q: pointer to source string to append from
|
||||
* @count: Maximum bytes to read from @q
|
||||
*
|
||||
* Appends at most @count bytes from @q (stopping at the first
|
||||
* NUL byte) after the NUL-terminated string at @p. @p will be
|
||||
* NUL-terminated.
|
||||
*
|
||||
* Do not use this function. While FORTIFY_SOURCE tries to avoid
|
||||
* read and write overflows, this is only possible when the sizes
|
||||
* of @p and @q are known to the compiler. Prefer building the
|
||||
* string with formatting, via scnprintf() or similar.
|
||||
*
|
||||
* Returns @p.
|
||||
*
|
||||
*/
|
||||
/* Defined after fortified strlen() and strnlen() to reuse them. */
|
||||
__FORTIFY_INLINE __diagnose_as(__builtin_strncat, 1, 2, 3)
|
||||
char *strncat(char * const POS p, const char * const POS q, __kernel_size_t count)
|
||||
{
|
||||
@@ -573,7 +682,8 @@ __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size)
|
||||
return __real_memchr_inv(p, c, size);
|
||||
}
|
||||
|
||||
extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kmemdup);
|
||||
extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kmemdup)
|
||||
__realloc_size(2);
|
||||
__FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp)
|
||||
{
|
||||
size_t p_size = __struct_size(p);
|
||||
@@ -585,6 +695,20 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp
|
||||
return __real_kmemdup(p, size, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* strcpy - Copy a string into another string buffer
|
||||
*
|
||||
* @p: pointer to destination of copy
|
||||
* @q: pointer to NUL-terminated source string to copy
|
||||
*
|
||||
* Do not use this function. While FORTIFY_SOURCE tries to avoid
|
||||
* overflows, this is only possible when the sizes of @q and @p are
|
||||
* known to the compiler. Prefer strscpy(), though note its different
|
||||
* return values for detecting truncation.
|
||||
*
|
||||
* Returns @p.
|
||||
*
|
||||
*/
|
||||
/* Defined after fortified strlen to reuse it. */
|
||||
__FORTIFY_INLINE __diagnose_as(__builtin_strcpy, 1, 2)
|
||||
char *strcpy(char * const POS p, const char * const POS q)
|
||||
|
||||
@@ -30,7 +30,7 @@ struct hpet {
|
||||
unsigned long _hpet_compare;
|
||||
} _u1;
|
||||
u64 hpet_fsb[2]; /* FSB route */
|
||||
} hpet_timers[1];
|
||||
} hpet_timers[];
|
||||
};
|
||||
|
||||
#define hpet_mc _u0._hpet_mc
|
||||
|
||||
@@ -128,6 +128,53 @@ static inline bool __must_check __must_check_overflow(bool overflow)
|
||||
(*_d >> _to_shift) != _a); \
|
||||
}))
|
||||
|
||||
#define __overflows_type_constexpr(x, T) ( \
|
||||
is_unsigned_type(typeof(x)) ? \
|
||||
(x) > type_max(typeof(T)) : \
|
||||
is_unsigned_type(typeof(T)) ? \
|
||||
(x) < 0 || (x) > type_max(typeof(T)) : \
|
||||
(x) < type_min(typeof(T)) || (x) > type_max(typeof(T)))
|
||||
|
||||
#define __overflows_type(x, T) ({ \
|
||||
typeof(T) v = 0; \
|
||||
check_add_overflow((x), v, &v); \
|
||||
})
|
||||
|
||||
/**
|
||||
* overflows_type - helper for checking the overflows between value, variables,
|
||||
* or data type
|
||||
*
|
||||
* @n: source constant value or variable to be checked
|
||||
* @T: destination variable or data type proposed to store @x
|
||||
*
|
||||
* Compares the @x expression for whether or not it can safely fit in
|
||||
* the storage of the type in @T. @x and @T can have different types.
|
||||
* If @x is a constant expression, this will also resolve to a constant
|
||||
* expression.
|
||||
*
|
||||
* Returns: true if overflow can occur, false otherwise.
|
||||
*/
|
||||
#define overflows_type(n, T) \
|
||||
__builtin_choose_expr(__is_constexpr(n), \
|
||||
__overflows_type_constexpr(n, T), \
|
||||
__overflows_type(n, T))
|
||||
|
||||
/**
|
||||
* castable_to_type - like __same_type(), but also allows for casted literals
|
||||
*
|
||||
* @n: variable or constant value
|
||||
* @T: variable or data type
|
||||
*
|
||||
* Unlike the __same_type() macro, this allows a constant value as the
|
||||
* first argument. If this value would not overflow into an assignment
|
||||
* of the second argument's type, it returns true. Otherwise, this falls
|
||||
* back to __same_type().
|
||||
*/
|
||||
#define castable_to_type(n, T) \
|
||||
__builtin_choose_expr(__is_constexpr(n), \
|
||||
!__overflows_type_constexpr(n, T), \
|
||||
__same_type(n, T))
|
||||
|
||||
/**
|
||||
* size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX
|
||||
* @factor1: first factor
|
||||
|
||||
@@ -11,6 +11,7 @@ extern long (*panic_blink)(int state);
|
||||
__printf(1, 2)
|
||||
void panic(const char *fmt, ...) __noreturn __cold;
|
||||
void nmi_panic(struct pt_regs *regs, const char *msg);
|
||||
void check_panic_on_warn(const char *origin);
|
||||
extern void oops_enter(void);
|
||||
extern void oops_exit(void);
|
||||
extern bool oops_may_print(void);
|
||||
|
||||
@@ -176,7 +176,7 @@ extern void kfree_const(const void *x);
|
||||
extern char *kstrdup(const char *s, gfp_t gfp) __malloc;
|
||||
extern const char *kstrdup_const(const char *s, gfp_t gfp);
|
||||
extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
|
||||
extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
|
||||
extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
|
||||
extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
|
||||
|
||||
extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
|
||||
|
||||
Reference in New Issue
Block a user