hardening updates for v7.0-rc1

- Various missed __counted_by annotations (Thorsten Blum)
 
 - Various missed -Wflex-array-member-not-at-end fixes (Gustavo A. R. Silva)
 
 - Avoid leftover tempfiles for interrupted compile-time FORTIFY tests
   (Nicolas Schier)
 
 - Remove non-existant CONFIG_UBSAN_REPORT_FULL from docs (Stefan Wiehler)
 
 - fortify: Use C arithmetic not FIELD_xxx() in FORTIFY_REASON defines
   (David Laight)
 
 - Add __counted_by_ptr attribute, tests, and first user (Bill Wendling,
   Kees Cook)
 
 - Update MAINTAINERS file to make hardening section not include pstore
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRSPkdeREjth1dHnSE2KwveOeQkuwUCaYopPQAKCRA2KwveOeQk
 u5QDAQDj9ygsbzLj9EtXtU3T03GTvix4Rx7RkaBAMPSDEJGhNQD+M3dP6Z2ogEMz
 1Km6dAC7nTEujsVFur9BVpyEgoBjjQM=
 =G1gb
 -----END PGP SIGNATURE-----

Merge tag 'hardening-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull hardening updates from Kees Cook:
 "Mostly small cleanups and various scattered annotations and flex array
  warning fixes that we reviewed by unlanded in other trees. Introduces
  new annotation for expanding counted_by to pointer members, now that
  compiler behavior between GCC and Clang has been normalized.

   - Various missed __counted_by annotations (Thorsten Blum)

   - Various missed -Wflex-array-member-not-at-end fixes (Gustavo A. R.
     Silva)

   - Avoid leftover tempfiles for interrupted compile-time FORTIFY tests
     (Nicolas Schier)

   - Remove non-existant CONFIG_UBSAN_REPORT_FULL from docs (Stefan
     Wiehler)

   - fortify: Use C arithmetic not FIELD_xxx() in FORTIFY_REASON defines
     (David Laight)

   - Add __counted_by_ptr attribute, tests, and first user (Bill
     Wendling, Kees Cook)

   - Update MAINTAINERS file to make hardening section not include
     pstore"

* tag 'hardening-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  MAINTAINERS: pstore: Remove L: entry
  nfp: tls: Avoid -Wflex-array-member-not-at-end warnings
  carl9170: Avoid -Wflex-array-member-not-at-end warning
  coredump: Use __counted_by_ptr for struct core_name::corename
  lkdtm/bugs: Add __counted_by_ptr() test PTR_BOUNDS
  compiler_types.h: Attributes: Add __counted_by_ptr macro
  fortify: Cleanup temp file also on non-successful exit
  fortify: Rename temporary file to match ignore pattern
  fortify: Use C arithmetic not FIELD_xxx() in FORTIFY_REASON defines
  ecryptfs: Annotate struct ecryptfs_message with __counted_by
  fs/xattr: Annotate struct simple_xattr with __counted_by
  crypto: af_alg - Annotate struct af_alg_iv with __counted_by
  Kconfig.ubsan: Remove CONFIG_UBSAN_REPORT_FULL from documentation
  drm/nouveau: fifo: Avoid -Wflex-array-member-not-at-end warning
This commit is contained in:
Linus Torvalds 2026-02-10 08:54:13 -08:00
commit 85f24b0ace
18 changed files with 161 additions and 44 deletions

View File

@ -20996,7 +20996,6 @@ PSTORE FILESYSTEM
M: Kees Cook <kees@kernel.org>
R: Tony Luck <tony.luck@intel.com>
R: Guilherme G. Piccoli <gpiccoli@igalia.com>
L: linux-hardening@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/pstore
F: Documentation/admin-guide/pstore-blk.rst

View File

@ -952,6 +952,12 @@ KBUILD_CFLAGS += $(CC_AUTO_VAR_INIT_ZERO_ENABLER)
endif
endif
ifdef CONFIG_CC_IS_CLANG
ifdef CONFIG_CC_HAS_COUNTED_BY_PTR
KBUILD_CFLAGS += -fexperimental-late-parse-attributes
endif
endif
# Explicitly clear padding bits during variable initialization
KBUILD_CFLAGS += $(call cc-option,-fzero-init-padding-bits=all)

View File

@ -25,13 +25,12 @@ static int
nvif_fifo_runlists(struct nvif_device *device)
{
struct nvif_object *object = &device->object;
struct {
struct nv_device_info_v1 m;
TRAILING_OVERLAP(struct nv_device_info_v1, m, data,
struct {
struct nv_device_info_v1_data runlists;
struct nv_device_info_v1_data runlist[64];
} v;
} *a;
) *a;
int ret, i;
if (device->runlist)

View File

@ -465,32 +465,32 @@ static void lkdtm_ARRAY_BOUNDS(void)
pr_expected_config(CONFIG_UBSAN_BOUNDS);
}
struct lkdtm_annotated {
struct lkdtm_cb_fam {
unsigned long flags;
int count;
int array[] __counted_by(count);
};
static volatile int fam_count = 4;
static volatile int element_count = 4;
static void lkdtm_FAM_BOUNDS(void)
{
struct lkdtm_annotated *inst;
struct lkdtm_cb_fam *inst;
inst = kzalloc(struct_size(inst, array, fam_count + 1), GFP_KERNEL);
inst = kzalloc(struct_size(inst, array, element_count + 1), GFP_KERNEL);
if (!inst) {
pr_err("FAIL: could not allocate test struct!\n");
return;
}
inst->count = fam_count;
inst->count = element_count;
pr_info("Array access within bounds ...\n");
inst->array[1] = fam_count;
inst->array[1] = element_count;
ignored = inst->array[1];
pr_info("Array access beyond bounds ...\n");
inst->array[fam_count] = fam_count;
ignored = inst->array[fam_count];
inst->array[element_count] = element_count;
ignored = inst->array[element_count];
kfree(inst);
@ -505,6 +505,79 @@ static void lkdtm_FAM_BOUNDS(void)
pr_expected_config(CONFIG_UBSAN_BOUNDS);
}
struct lkdtm_extra {
short a, b;
u16 sixteen;
u32 bigger;
u64 biggest;
};
struct lkdtm_cb_ptr {
int a, b, c;
int nr_extra;
char *buf __counted_by_ptr(len);
size_t len;
struct lkdtm_extra *extra __counted_by_ptr(nr_extra);
};
static noinline void check_ptr_len(struct lkdtm_cb_ptr *p, size_t len)
{
if (__member_size(p->buf) != len)
pr_err("FAIL: could not determine size of inst->buf: %zu\n",
__member_size(p->buf));
else
pr_info("good: inst->buf length is %zu\n", len);
}
static void lkdtm_PTR_BOUNDS(void)
{
struct lkdtm_cb_ptr *inst;
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
if (!inst) {
pr_err("FAIL: could not allocate struct lkdtm_cb_ptr!\n");
return;
}
inst->buf = kzalloc(element_count, GFP_KERNEL);
if (!inst->buf) {
pr_err("FAIL: could not allocate inst->buf!\n");
return;
}
inst->len = element_count;
/* Double element_count */
inst->extra = kcalloc(element_count * 2, sizeof(*inst->extra), GFP_KERNEL);
inst->nr_extra = element_count * 2;
pr_info("Pointer access within bounds ...\n");
check_ptr_len(inst, 4);
/* All 4 bytes */
inst->buf[0] = 'A';
inst->buf[1] = 'B';
inst->buf[2] = 'C';
inst->buf[3] = 'D';
/* Halfway into the array */
inst->extra[element_count].biggest = 0x1000;
pr_info("Pointer access beyond bounds ...\n");
ignored = inst->extra[inst->nr_extra].b;
kfree(inst->extra);
kfree(inst->buf);
kfree(inst);
pr_err("FAIL: survived access of invalid pointer member offset!\n");
if (!IS_ENABLED(CONFIG_CC_HAS_COUNTED_BY_PTR))
pr_warn("This is expected since this %s was built with a compiler that does not support __counted_by_ptr\n",
lkdtm_kernel_info);
else if (IS_ENABLED(CONFIG_UBSAN_BOUNDS))
pr_expected_config(CONFIG_UBSAN_TRAP);
else
pr_expected_config(CONFIG_UBSAN_BOUNDS);
}
static void lkdtm_CORRUPT_LIST_ADD(void)
{
/*
@ -769,6 +842,7 @@ static struct crashtype crashtypes[] = {
CRASHTYPE(OVERFLOW_UNSIGNED),
CRASHTYPE(ARRAY_BOUNDS),
CRASHTYPE(FAM_BOUNDS),
CRASHTYPE(PTR_BOUNDS),
CRASHTYPE(CORRUPT_LIST_ADD),
CRASHTYPE(CORRUPT_LIST_DEL),
CRASHTYPE(STACK_GUARD_PAGE_LEADING),

View File

@ -32,16 +32,22 @@ struct nfp_crypto_req_reset {
#define NFP_NET_TLS_VLAN_UNUSED 4095
struct nfp_crypto_req_add_front {
struct nfp_ccm_hdr hdr;
__be32 ep_id;
u8 resv[3];
u8 opcode;
u8 key_len;
__be16 ipver_vlan __packed;
u8 l4_proto;
/* New members MUST be added within the struct_group() macro below. */
struct_group_tagged(nfp_crypto_req_add_front_hdr, __hdr,
struct nfp_ccm_hdr hdr;
__be32 ep_id;
u8 resv[3];
u8 opcode;
u8 key_len;
__be16 ipver_vlan __packed;
u8 l4_proto;
);
#define NFP_NET_TLS_NON_ADDR_KEY_LEN 8
u8 l3_addrs[];
};
static_assert(offsetof(struct nfp_crypto_req_add_front, l3_addrs) ==
sizeof(struct nfp_crypto_req_add_front_hdr),
"struct member likely outside of struct_group_tagged()");
struct nfp_crypto_req_add_back {
__be16 src_port;
@ -55,14 +61,14 @@ struct nfp_crypto_req_add_back {
};
struct nfp_crypto_req_add_v4 {
struct nfp_crypto_req_add_front front;
struct nfp_crypto_req_add_front_hdr front;
__be32 src_ip;
__be32 dst_ip;
struct nfp_crypto_req_add_back back;
};
struct nfp_crypto_req_add_v6 {
struct nfp_crypto_req_add_front front;
struct nfp_crypto_req_add_front_hdr front;
__be32 src_ip[4];
__be32 dst_ip[4];
struct nfp_crypto_req_add_back back;

View File

@ -180,7 +180,9 @@ nfp_net_tls_set_ipv4(struct nfp_net *nn, struct nfp_crypto_req_add_v4 *req,
req->front.key_len += sizeof(__be32) * 2;
if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
nfp_net_tls_assign_conn_id(nn, &req->front);
nfp_net_tls_assign_conn_id(nn,
container_of(&req->front,
struct nfp_crypto_req_add_front, __hdr));
} else {
req->src_ip = inet->inet_daddr;
req->dst_ip = inet->inet_saddr;
@ -199,7 +201,9 @@ nfp_net_tls_set_ipv6(struct nfp_net *nn, struct nfp_crypto_req_add_v6 *req,
req->front.key_len += sizeof(struct in6_addr) * 2;
if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
nfp_net_tls_assign_conn_id(nn, &req->front);
nfp_net_tls_assign_conn_id(nn,
container_of(&req->front,
struct nfp_crypto_req_add_front, __hdr));
} else {
memcpy(req->src_ip, &sk->sk_v6_daddr, sizeof(req->src_ip));
memcpy(req->dst_ip, &np->saddr, sizeof(req->dst_ip));

View File

@ -375,11 +375,6 @@ struct ar9170 {
u8 *readbuf;
spinlock_t cmd_lock;
struct completion cmd_wait;
union {
__le32 cmd_buf[PAYLOAD_MAX + 1];
struct carl9170_cmd cmd;
struct carl9170_rsp rsp;
};
/* statistics */
unsigned int tx_dropped;
@ -463,6 +458,13 @@ struct ar9170 {
unsigned int cache_idx;
} rng;
#endif /* CONFIG_CARL9170_HWRNG */
/* Must be last as it ends in a flexible-array member. */
union {
__le32 cmd_buf[PAYLOAD_MAX + 1];
struct carl9170_cmd cmd;
struct carl9170_rsp rsp;
};
};
enum carl9170_ps_off_override_reasons {

View File

@ -92,7 +92,7 @@ enum coredump_type_t {
};
struct core_name {
char *corename;
char *corename __counted_by_ptr(size);
int used, size;
unsigned int core_pipe_limit;
bool core_dumped;
@ -106,15 +106,15 @@ static int expand_corename(struct core_name *cn, int size)
size = kmalloc_size_roundup(size);
corename = krealloc(cn->corename, size, GFP_KERNEL);
if (!corename)
return -ENOMEM;
cn->corename = corename;
cn->size = size;
if (size > core_name_size) /* racy but harmless */
core_name_size = size;
cn->size = size;
cn->corename = corename;
return 0;
}

View File

@ -359,7 +359,7 @@ struct ecryptfs_message {
/* Inherits from msg_ctx->index */
u32 index;
u32 data_len;
u8 data[];
u8 data[] __counted_by(data_len);
};
struct ecryptfs_msg_ctx {

View File

@ -369,7 +369,7 @@ struct ftrace_likely_data {
* Optional: only supported since clang >= 18
*
* gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
* clang: https://github.com/llvm/llvm-project/pull/76348
* clang: https://clang.llvm.org/docs/AttributeReference.html#counted-by-counted-by-or-null-sized-by-sized-by-or-null
*
* __bdos on clang < 19.1.2 can erroneously return 0:
* https://github.com/llvm/llvm-project/pull/110497
@ -383,6 +383,22 @@ struct ftrace_likely_data {
# define __counted_by(member)
#endif
/*
* Runtime track number of objects pointed to by a pointer member for use by
* CONFIG_FORTIFY_SOURCE and CONFIG_UBSAN_BOUNDS.
*
* Optional: only supported since gcc >= 16
* Optional: only supported since clang >= 22
*
* gcc: https://gcc.gnu.org/pipermail/gcc-patches/2025-April/681727.html
* clang: https://clang.llvm.org/docs/AttributeReference.html#counted-by-counted-by-or-null-sized-by-sized-by-or-null
*/
#ifdef CONFIG_CC_HAS_COUNTED_BY_PTR
#define __counted_by_ptr(member) __attribute__((__counted_by__(member)))
#else
#define __counted_by_ptr(member)
#endif
/*
* Optional: only supported since gcc >= 15
* Optional: not supported by Clang

View File

@ -2,7 +2,6 @@
#ifndef _LINUX_FORTIFY_STRING_H_
#define _LINUX_FORTIFY_STRING_H_
#include <linux/bitfield.h>
#include <linux/bug.h>
#include <linux/const.h>
#include <linux/limits.h>
@ -10,10 +9,9 @@
#define __FORTIFY_INLINE extern __always_inline __gnu_inline __overloadable
#define __RENAME(x) __asm__(#x)
#define FORTIFY_REASON_DIR(r) FIELD_GET(BIT(0), r)
#define FORTIFY_REASON_FUNC(r) FIELD_GET(GENMASK(7, 1), r)
#define FORTIFY_REASON(func, write) (FIELD_PREP(BIT(0), write) | \
FIELD_PREP(GENMASK(7, 1), func))
#define FORTIFY_REASON_DIR(r) ((r) & 1)
#define FORTIFY_REASON_FUNC(r) ((r) >> 1)
#define FORTIFY_REASON(func, write) ((func) << 1 | (write))
/* Overridden by KUnit tests. */
#ifndef fortify_panic

View File

@ -114,7 +114,7 @@ struct simple_xattr {
struct rb_node rb_node;
char *name;
size_t size;
char value[];
char value[] __counted_by(size);
};
void simple_xattrs_init(struct simple_xattrs *xattrs);

View File

@ -42,7 +42,7 @@ struct sockaddr_alg_new {
struct af_alg_iv {
__u32 ivlen;
__u8 iv[];
__u8 iv[] __counted_by(ivlen);
};
/* Socket options */

View File

@ -72,6 +72,10 @@
#define __counted_by_be(m)
#endif
#ifndef __counted_by_ptr
#define __counted_by_ptr(m)
#endif
#ifdef __KERNEL__
#define __kernel_nonstring __nonstring
#else

View File

@ -143,6 +143,13 @@ config CC_HAS_COUNTED_BY
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
default y if CC_IS_GCC && GCC_VERSION >= 150100
config CC_HAS_COUNTED_BY_PTR
bool
# supported since clang 22
default y if CC_IS_CLANG && CLANG_VERSION >= 220000
# supported since gcc 16.0.0
default y if CC_IS_GCC && GCC_VERSION >= 160000
config CC_HAS_MULTIDIMENSIONAL_NONSTRING
def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror)

View File

@ -104,7 +104,7 @@ config UBSAN_DIV_ZERO
This option enables -fsanitize=integer-divide-by-zero which checks
for integer division by zero. This is effectively redundant with the
kernel's existing exception handling, though it can provide greater
debugging information under CONFIG_UBSAN_REPORT_FULL.
debugging information.
config UBSAN_UNREACHABLE
bool "Perform checking for unreachable code"

View File

@ -17,7 +17,7 @@ WANT="__${FILE%%-*}"
# Argument 2: Where to write the build log.
OUT="$1"
shift
TMP="${OUT}.tmp"
TMP="${OUT%/*}/.${OUT##*/}.tmp"
# Argument 3: Path to "nm" tool.
NM="$1"
@ -29,7 +29,7 @@ shift
__cleanup() {
rm -f "$TMP"
}
trap __cleanup EXIT
trap __cleanup EXIT HUP INT QUIT TERM
# Function names in warnings are wrapped in backticks under UTF-8 locales.
# Run the commands with LANG=C so that grep output will not change.

View File

@ -11,6 +11,8 @@ EXCEPTION
#CORRUPT_STACK Crashes entire system on success
#CORRUPT_STACK_STRONG Crashes entire system on success
ARRAY_BOUNDS call trace:|UBSAN: array-index-out-of-bounds
FAM_BOUNDS call trace:|UBSAN: array-index-out-of-bounds
PTR_BOUNDS call trace:|UBSAN: array-index-out-of-bounds
CORRUPT_LIST_ADD list_add corruption
CORRUPT_LIST_DEL list_del corruption
STACK_GUARD_PAGE_LEADING