diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-06-27 21:24:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-06-27 21:24:18 -0700 |
commit | 582c161cf38cf016cd573af6f087fa5fa786949b (patch) | |
tree | 6ae83fe4acfc54fc962ac2fbc15f56746b54d528 | |
parent | 8ad78685ffa6e3836b5b32197bffb03ee3389bec (diff) | |
parent | acf15e07eb06507c69f92394c36052677029b0a8 (diff) |
Merge tag 'hardening-v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull hardening updates from Kees Cook:
"There are three areas of note:
A bunch of strlcpy()->strscpy() conversions ended up living in my tree
since they were either Acked by maintainers for me to carry, or got
ignored for multiple weeks (and were trivial changes).
The compiler option '-fstrict-flex-arrays=3' has been enabled
globally, and has been in -next for the entire devel cycle. This
changes compiler diagnostics (though mainly just -Warray-bounds which
is disabled) and potential UBSAN_BOUNDS and FORTIFY _warning_
coverage. In other words, there are no new restrictions, just
potentially new warnings. Any new FORTIFY warnings we've seen have
been fixed (usually in their respective subsystem trees). For more
details, see commit df8fc4e934c12b.
The under-development compiler attribute __counted_by has been added
so that we can start annotating flexible array members with their
associated structure member that tracks the count of flexible array
elements at run-time. It is possible (likely?) that the exact syntax
of the attribute will change before it is finalized, but GCC and Clang
are working together to sort it out. Any changes can be made to the
macro while we continue to add annotations.
As an example of that last case, I have a treewide commit waiting with
such annotations found via Coccinelle:
https://git.kernel.org/linus/adc5b3cb48a049563dc673f348eab7b6beba8a9b
Also see commit dd06e72e68bcb4 for more details.
Summary:
- Fix KMSAN vs FORTIFY in strlcpy/strlcat (Alexander Potapenko)
- Convert strreplace() to return string start (Andy Shevchenko)
- Flexible array conversions (Arnd Bergmann, Wyes Karny, Kees Cook)
- Add missing function prototypes seen with W=1 (Arnd Bergmann)
- Fix strscpy() kerndoc typo (Arne Welzel)
- Replace strlcpy() with strscpy() across many subsystems which were
either Acked by respective maintainers or were trivial changes that
went ignored for multiple weeks (Azeem Shaikh)
- Remove unneeded cc-option test for UBSAN_TRAP (Nick Desaulniers)
- Add KUnit tests for strcat()-family
- Enable KUnit tests of FORTIFY wrappers under UML
- Add more complete FORTIFY protections for strlcat()
- Add missed disabling of FORTIFY for all arch purgatories.
- Enable -fstrict-flex-arrays=3 globally
- Tightening UBSAN_BOUNDS when using GCC
- Improve checkpatch to check for strcpy, strncpy, and fake flex
arrays
- Improve use of const variables in FORTIFY
- Add requested struct_size_t() helper for types not pointers
- Add __counted_by macro for annotating flexible array size members"
* tag 'hardening-v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: (54 commits)
netfilter: ipset: Replace strlcpy with strscpy
uml: Replace strlcpy with strscpy
um: Use HOST_DIR for mrproper
kallsyms: Replace all non-returning strlcpy with strscpy
sh: Replace all non-returning strlcpy with strscpy
of/flattree: Replace all non-returning strlcpy with strscpy
sparc64: Replace all non-returning strlcpy with strscpy
Hexagon: Replace all non-returning strlcpy with strscpy
kobject: Use return value of strreplace()
lib/string_helpers: Change returned value of the strreplace()
jbd2: Avoid printing outside the boundary of the buffer
checkpatch: Check for 0-length and 1-element arrays
riscv/purgatory: Do not use fortified string functions
s390/purgatory: Do not use fortified string functions
x86/purgatory: Do not use fortified string functions
acpi: Replace struct acpi_table_slit 1-element array with flex-array
clocksource: Replace all non-returning strlcpy with strscpy
string: use __builtin_memcpy() in strlcpy/strlcat
staging: most: Replace all non-returning strlcpy with strscpy
drm/i2c: tda998x: Replace all non-returning strlcpy with strscpy
...
84 files changed, 467 insertions, 203 deletions
diff --git a/Documentation/filesystems/autofs-mount-control.rst b/Documentation/filesystems/autofs-mount-control.rst index bf4b511cdbe8..b5a379d25c40 100644 --- a/Documentation/filesystems/autofs-mount-control.rst +++ b/Documentation/filesystems/autofs-mount-control.rst @@ -196,7 +196,7 @@ information and return operation results:: struct args_ismountpoint ismountpoint; }; - char path[0]; + char path[]; }; The ioctlfd field is a mount point file descriptor of an autofs mount diff --git a/Documentation/filesystems/autofs.rst b/Documentation/filesystems/autofs.rst index 4f490278d22f..3b6e38e646cd 100644 --- a/Documentation/filesystems/autofs.rst +++ b/Documentation/filesystems/autofs.rst @@ -467,7 +467,7 @@ Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure:: struct args_ismountpoint ismountpoint; }; - char path[0]; + char path[]; }; For the **OPEN_MOUNT** and **IS_MOUNTPOINT** commands, the target diff --git a/MAINTAINERS b/MAINTAINERS index c5ad895d6fa4..3e024fac72f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8099,6 +8099,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/har F: include/linux/fortify-string.h F: lib/fortify_kunit.c F: lib/memcpy_kunit.c +F: lib/strcat_kunit.c F: lib/strscpy_kunit.c F: lib/test_fortify/* F: scripts/test_fortify.sh @@ -1026,6 +1026,12 @@ KBUILD_CFLAGS += -Wno-pointer-sign # globally built with -Wcast-function-type. KBUILD_CFLAGS += $(call cc-option, -Wcast-function-type) +# To gain proper coverage for CONFIG_UBSAN_BOUNDS and CONFIG_FORTIFY_SOURCE, +# the kernel uses only C99 flexible arrays for dynamically sized trailing +# arrays. Enforce this for everything that may examine structure sizes and +# perform bounds checking. +KBUILD_CFLAGS += $(call cc-option, -fstrict-flex-arrays=3) + # disable stringop warnings in gcc 8+ KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation) diff --git a/arch/hexagon/kernel/setup.c b/arch/hexagon/kernel/setup.c index 1880d9beaf2b..621674e86232 100644 --- a/arch/hexagon/kernel/setup.c +++ b/arch/hexagon/kernel/setup.c @@ -66,9 +66,9 @@ void __init setup_arch(char **cmdline_p) on_simulator = 0; if (p[0] != '\0') - strlcpy(boot_command_line, p, COMMAND_LINE_SIZE); + strscpy(boot_command_line, p, COMMAND_LINE_SIZE); else - strlcpy(boot_command_line, default_command_line, + strscpy(boot_command_line, default_command_line, COMMAND_LINE_SIZE); /* @@ -76,7 +76,7 @@ void __init setup_arch(char **cmdline_p) * are both picked up by the init code. If no reason to * make them different, pass the same pointer back. */ - strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); + strscpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = cmd_line; parse_early_param(); diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index c5c6186a7e8b..e424c796e297 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -20,7 +20,7 @@ void __init early_init_devtree(void *params) early_init_dt_scan(params); if (!strlen(boot_command_line)) - strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); + strscpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); memblock_allow_resize(); diff --git a/arch/riscv/purgatory/Makefile b/arch/riscv/purgatory/Makefile index bd2e27f82532..dc20e166983e 100644 --- a/arch/riscv/purgatory/Makefile +++ b/arch/riscv/purgatory/Makefile @@ -31,7 +31,7 @@ $(obj)/strncmp.o: $(srctree)/arch/riscv/lib/strncmp.S FORCE $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE $(call if_changed_rule,cc_o_c) -CFLAGS_sha256.o := -D__DISABLE_EXPORTS +CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY CFLAGS_string.o := -D__DISABLE_EXPORTS CFLAGS_ctype.o := -D__DISABLE_EXPORTS diff --git a/arch/s390/purgatory/Makefile b/arch/s390/purgatory/Makefile index cc8cf5abea15..4e930f566878 100644 --- a/arch/s390/purgatory/Makefile +++ b/arch/s390/purgatory/Makefile @@ -10,7 +10,7 @@ PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE $(call if_changed_rule,cc_o_c) -CFLAGS_sha256.o := -D__DISABLE_EXPORTS +CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY $(obj)/mem.o: $(srctree)/arch/s390/lib/mem.S FORCE $(call if_changed_rule,as_o_S) diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index ab9170494dcc..89cd4a3b4cca 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c @@ -198,7 +198,7 @@ int request_dma(unsigned int chan, const char *dev_id) if (atomic_xchg(&channel->busy, 1)) return -EBUSY; - strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); + strscpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); if (info->ops->request) { result = info->ops->request(channel); diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index cf7c0f72f293..b3da2757faaf 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -305,9 +305,9 @@ void __init setup_arch(char **cmdline_p) bss_resource.end = virt_to_phys(__bss_stop)-1; #ifdef CONFIG_CMDLINE_OVERWRITE - strlcpy(command_line, CONFIG_CMDLINE, sizeof(command_line)); + strscpy(command_line, CONFIG_CMDLINE, sizeof(command_line)); #else - strlcpy(command_line, COMMAND_LINE, sizeof(command_line)); + strscpy(command_line, COMMAND_LINE, sizeof(command_line)); #ifdef CONFIG_CMDLINE_EXTEND strlcat(command_line, " ", sizeof(command_line)); strlcat(command_line, CONFIG_CMDLINE, sizeof(command_line)); diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 4e4f3d3263e4..a8cbe403301f 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -191,7 +191,7 @@ static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, tack += sizeof (struct resource); } - strlcpy(tack, name, XNMLN+1); + strscpy(tack, name, XNMLN+1); res->name = tack; va = _sparc_ioremap(res, busno, phys, size); diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index c9d1ba4f311b..1adf5c1c16b8 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -302,7 +302,7 @@ void __init setup_arch(char **cmdline_p) /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); - strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); + strscpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); parse_early_param(); boot_flags_init(*cmdline_p); diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 48abee4eee29..6546ca9d4d3f 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -636,7 +636,7 @@ void __init setup_arch(char **cmdline_p) { /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); - strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); + strscpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); parse_early_param(); boot_flags_init(*cmdline_p); diff --git a/arch/sparc/prom/bootstr_32.c b/arch/sparc/prom/bootstr_32.c index e3b731ff00f0..1c7cd258b0dc 100644 --- a/arch/sparc/prom/bootstr_32.c +++ b/arch/sparc/prom/bootstr_32.c @@ -52,7 +52,7 @@ prom_getbootargs(void) * V3 PROM cannot supply as with more than 128 bytes * of an argument. But a smart bootstrap loader can. */ - strlcpy(barg_buf, *romvec->pv_v2bootargs.bootargs, sizeof(barg_buf)); + strscpy(barg_buf, *romvec->pv_v2bootargs.bootargs, sizeof(barg_buf)); break; default: break; diff --git a/arch/um/Makefile b/arch/um/Makefile index 8186d4761bda..da4d5256af2f 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -149,7 +149,7 @@ export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) $(CC_FLAGS_ # When cleaning we don't include .config, so we don't include # TT or skas makefiles and don't clean skas_ptregs.h. CLEAN_FILES += linux x.i gmon.out -MRPROPER_FILES += arch/$(SUBARCH)/include/generated +MRPROPER_FILES += $(HOST_DIR)/include/generated archclean: @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ diff --git a/arch/um/include/shared/user.h b/arch/um/include/shared/user.h index bda66e5a9d4e..0347a190429c 100644 --- a/arch/um/include/shared/user.h +++ b/arch/um/include/shared/user.h @@ -52,6 +52,7 @@ static inline int printk(const char *fmt, ...) extern int in_aton(char *str); extern size_t strlcpy(char *, const char *, size_t); extern size_t strlcat(char *, const char *, size_t); +extern size_t strscpy(char *, const char *, size_t); /* Copied from linux/compiler-gcc.h since we can't include it directly */ #define barrier() __asm__ __volatile__("": : :"memory") diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 53eb3d508645..2284e9c1cbbb 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -146,7 +146,7 @@ static int tuntap_open(void *data) } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); + strscpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); if (ioctl(pri->fd, TUNSETIFF, &ifr) < 0) { err = -errno; printk(UM_KERN_ERR "TUNSETIFF failed, errno = %d\n", diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile index 42abd6af1198..c2a29be35c01 100644 --- a/arch/x86/purgatory/Makefile +++ b/arch/x86/purgatory/Makefile @@ -12,7 +12,7 @@ $(obj)/string.o: $(srctree)/arch/x86/boot/compressed/string.c FORCE $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE $(call if_changed_rule,cc_o_c) -CFLAGS_sha256.o := -D__DISABLE_EXPORTS +CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY # When profile-guided optimization is enabled, llvm emits two different # overlapping text sections, which is not supported by kexec. Remove profile diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index 1c5d9388ad0b..5f610e9a5f0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -1509,7 +1509,7 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios) str = CSTR(idx); if (*str != '\0') { pr_info("ATOM BIOS: %s\n", str); - strlcpy(ctx->vbios_version, str, sizeof(ctx->vbios_version)); + strscpy(ctx->vbios_version, str, sizeof(ctx->vbios_version)); } atom_rom_header = (struct _ATOM_ROM_HEADER *)CSTR(base); diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c index d3fe149d8476..81fb4e5dd804 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c @@ -794,7 +794,7 @@ void amdgpu_add_thermal_controller(struct amdgpu_device *adev) struct i2c_board_info info = { }; const char *name = pp_lib_thermal_controller_names[controller->ucType]; info.addr = controller->ucI2cAddress >> 1; - strlcpy(info.type, name, sizeof(info.type)); + strscpy(info.type, name, sizeof(info.type)); i2c_new_client_device(&adev->pm.i2c_bus->adapter, &info); } } else { diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 16565a0a5da6..e6a78fd32380 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2103,7 +2103,7 @@ int drm_dp_aux_register(struct drm_dp_aux *aux) aux->ddc.owner = THIS_MODULE; aux->ddc.dev.parent = aux->dev; - strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), + strscpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), sizeof(aux->ddc.name)); ret = drm_dp_aux_register_devnode(aux); diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index e2e21ce79510..943a00db77d4 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -5702,7 +5702,7 @@ static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port) aux->ddc.dev.parent = parent_dev; aux->ddc.dev.of_node = parent_dev->of_node; - strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(parent_dev), + strscpy(aux->ddc.name, aux->name ? aux->name : dev_name(parent_dev), sizeof(aux->ddc.name)); return i2c_add_adapter(&aux->ddc); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 3fd6c733ff4e..6252ac01e945 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -223,7 +223,7 @@ mipi_dsi_device_register_full(struct mipi_dsi_host *host, device_set_node(&dsi->dev, of_fwnode_handle(info->node)); dsi->channel = info->channel; - strlcpy(dsi->name, info->type, sizeof(dsi->name)); + strscpy(dsi->name, info->type, sizeof(dsi->name)); ret = mipi_dsi_device_add(dsi); if (ret) { diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index db5c9343a3d2..0918d80672bb 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1951,7 +1951,7 @@ static int tda998x_create(struct device *dev) * offset. */ memset(&cec_info, 0, sizeof(cec_info)); - strlcpy(cec_info.type, "tda9950", sizeof(cec_info.type)); + strscpy(cec_info.type, "tda9950", sizeof(cec_info.type)); cec_info.addr = priv->cec_addr; cec_info.platform_data = &priv->cec_glue; cec_info.irq = client->irq; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c index 2fc9214ffa82..4d39ea0a05ca 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c @@ -295,7 +295,7 @@ static int mtk_hdmi_ddc_probe(struct platform_device *pdev) return ret; } - strlcpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name)); + strscpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name)); ddc->adap.owner = THIS_MODULE; ddc->adap.class = I2C_CLASS_DDC; ddc->adap.algo = &mtk_hdmi_ddc_algorithm; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 4ad5a328d920..bf3c411a55c5 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2105,7 +2105,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) const char *name = thermal_controller_names[power_info->info. ucOverdriveThermalController]; info.addr = power_info->info.ucOverdriveControllerAddress >> 1; - strlcpy(info.type, name, sizeof(info.type)); + strscpy(info.type, name, sizeof(info.type)); i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); } } @@ -2355,7 +2355,7 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r struct i2c_board_info info = { }; const char *name = pp_lib_thermal_controller_names[controller->ucType]; info.addr = controller->ucI2cAddress >> 1; - strlcpy(info.type, name, sizeof(info.type)); + strscpy(info.type, name, sizeof(info.type)); i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); } } else { diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 783a6b8802d5..795c3667f6d6 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2702,7 +2702,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) struct i2c_board_info info = { }; const char *name = thermal_controller_names[thermal_controller]; info.addr = i2c_addr >> 1; - strlcpy(info.type, name, sizeof(info.type)); + strscpy(info.type, name, sizeof(info.type)); i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); } } @@ -2719,7 +2719,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) struct i2c_board_info info = { }; const char *name = "f75375"; info.addr = 0x28; - strlcpy(info.type, name, sizeof(info.type)); + strscpy(info.type, name, sizeof(info.type)); i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); DRM_INFO("Possible %s thermal controller at 0x%02x\n", name, info.addr); diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f51774866f41..9afb889963c1 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -797,7 +797,7 @@ static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi) adap->dev.parent = hdmi->dev; adap->dev.of_node = hdmi->dev->of_node; adap->algo = &inno_hdmi_algorithm; - strlcpy(adap->name, "Inno HDMI", sizeof(adap->name)); + strscpy(adap->name, "Inno HDMI", sizeof(adap->name)); i2c_set_adapdata(adap, hdmi); ret = i2c_add_adapter(adap); diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 90145ad96984..b5d042ee052f 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -730,7 +730,7 @@ static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi) adap->dev.parent = hdmi->dev; adap->dev.of_node = hdmi->dev->of_node; adap->algo = &rk3066_hdmi_algorithm; - strlcpy(adap->name, "RK3066 HDMI", sizeof(adap->name)); + strscpy(adap->name, "RK3066 HDMI", sizeof(adap->name)); i2c_set_adapdata(adap, hdmi); ret = i2c_add_adapter(adap); diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c index c7d7e9fff91c..d1a65a921f5a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c @@ -304,7 +304,7 @@ int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi) adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DDC; adap->algo = &sun4i_hdmi_i2c_algorithm; - strlcpy(adap->name, "sun4i_hdmi_i2c adapter", sizeof(adap->name)); + strscpy(adap->name, "sun4i_hdmi_i2c adapter", sizeof(adap->name)); i2c_set_adapdata(adap, hdmi); ret = i2c_add_adapter(adap); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6615abf54d3f..85b3004594e0 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2433,7 +2433,7 @@ static int grow_stripes(struct r5conf *conf, int num) conf->active_name = 0; sc = kmem_cache_create(conf->cache_name[conf->active_name], - sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), + struct_size_t(struct stripe_head, dev, devs), 0, 0, NULL); if (!sc) return 1; @@ -2559,7 +2559,7 @@ static int resize_stripes(struct r5conf *conf, int newsize) /* Step 1 */ sc = kmem_cache_create(conf->cache_name[1-conf->active_name], - sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev), + struct_size_t(struct stripe_head, dev, newsize), 0, 0, NULL); if (!sc) return -ENOMEM; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index f19707189a7b..97a795979a35 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -268,7 +268,7 @@ struct stripe_head { unsigned long flags; u32 log_checksum; unsigned short write_hint; - } dev[1]; /* allocated with extra space depending of RAID geometry */ + } dev[]; /* allocated depending of RAID geometry ("disks" member) */ }; /* stripe_head_state - collects and tracks the dynamic state of a stripe_head diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 92110cb6a0eb..3c95600ab2f7 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -309,7 +309,7 @@ static void lkdtm_OVERFLOW_UNSIGNED(void) struct array_bounds_flex_array { int one; int two; - char data[1]; + char data[]; }; struct array_bounds { @@ -341,7 +341,7 @@ static void lkdtm_ARRAY_BOUNDS(void) * For the uninstrumented flex array member, also touch 1 byte * beyond to verify it is correctly uninstrumented. */ - for (i = 0; i < sizeof(not_checked->data) + 1; i++) + for (i = 0; i < 2; i++) not_checked->data[i] = 'A'; pr_info("Array access beyond bounds ...\n"); diff --git a/drivers/most/configfs.c b/drivers/most/configfs.c index 27b0c923597f..36d8c917f65f 100644 --- a/drivers/most/configfs.c +++ b/drivers/most/configfs.c @@ -204,7 +204,7 @@ static ssize_t mdev_link_device_store(struct config_item *item, { struct mdev_link *mdev_link = to_mdev_link(item); - strlcpy(mdev_link->device, page, sizeof(mdev_link->device)); + strscpy(mdev_link->device, page, sizeof(mdev_link->device)); strim(mdev_link->device); return count; } @@ -219,7 +219,7 @@ static ssize_t mdev_link_channel_store(struct config_item *item, { struct mdev_link *mdev_link = to_mdev_link(item); - strlcpy(mdev_link->channel, page, sizeof(mdev_link->channel)); + strscpy(mdev_link->channel, page, sizeof(mdev_link->channel)); strim(mdev_link->channel); return count; } @@ -234,7 +234,7 @@ static ssize_t mdev_link_comp_store(struct config_item *item, { struct mdev_link *mdev_link = to_mdev_link(item); - strlcpy(mdev_link->comp, page, sizeof(mdev_link->comp)); + strscpy(mdev_link->comp, page, sizeof(mdev_link->comp)); strim(mdev_link->comp); return count; } @@ -250,7 +250,7 @@ static ssize_t mdev_link_comp_params_store(struct config_item *item, { struct mdev_link *mdev_link = to_mdev_link(item); - strlcpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params)); + strscpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params)); strim(mdev_link->comp_params); return count; } diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.h b/drivers/net/ethernet/intel/ice/ice_ddp.h index 37eadb3d27a8..41acfe26df1c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ddp.h +++ b/drivers/net/ethernet/intel/ice/ice_ddp.h @@ -185,7 +185,7 @@ struct ice_buf_hdr { #define ICE_MAX_ENTRIES_IN_BUF(hd_sz, ent_sz) \ ((ICE_PKG_BUF_SIZE - \ - struct_size((struct ice_buf_hdr *)0, section_entry, 1) - (hd_sz)) / \ + struct_size_t(struct ice_buf_hdr, section_entry, 1) - (hd_sz)) / \ (ent_sz)) /* ice package section IDs */ @@ -297,7 +297,7 @@ struct ice_label_section { }; #define ICE_MAX_LABELS_IN_BUF \ - ICE_MAX_ENTRIES_IN_BUF(struct_size((struct ice_label_section *)0, \ + ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_label_section, \ label, 1) - \ sizeof(struct ice_label), \ sizeof(struct ice_label)) @@ -352,7 +352,7 @@ struct ice_boost_tcam_section { }; #define ICE_MAX_BST_TCAMS_IN_BUF \ - ICE_MAX_ENTRIES_IN_BUF(struct_size((struct ice_boost_tcam_section *)0, \ + ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_boost_tcam_section, \ tcam, 1) - \ sizeof(struct ice_boost_tcam_entry), \ sizeof(struct ice_boost_tcam_entry)) @@ -372,8 +372,7 @@ struct ice_marker_ptype_tcam_section { }; #define ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF \ - ICE_MAX_ENTRIES_IN_BUF( \ - struct_size((struct ice_marker_ptype_tcam_section *)0, tcam, \ + ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_marker_ptype_tcam_section, tcam, \ 1) - \ sizeof(struct ice_marker_ptype_tcam_entry), \ sizeof(struct ice_marker_ptype_tcam_entry)) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 2ed75923507d..691f2df574ce 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -2917,8 +2917,8 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl) ret = nvme_alloc_io_tag_set(&ctrl->ctrl, &ctrl->tag_set, &nvme_fc_mq_ops, 1, - struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, - ctrl->lport->ops->fcprqst_priv_sz)); + struct_size_t(struct nvme_fcp_op_w_sgl, priv, + ctrl->lport->ops->fcprqst_priv_sz)); if (ret) return ret; @@ -3536,8 +3536,8 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set, &nvme_fc_admin_mq_ops, - struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, - ctrl->lport->ops->fcprqst_priv_sz)); + struct_size_t(struct nvme_fcp_op_w_sgl, priv, + ctrl->lport->ops->fcprqst_priv_sz)); if (ret) goto fail_ctrl; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 38d20a69ee12..f925f8664c2c 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -617,7 +617,7 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) } /* Load rest of compatibility struct */ - strlcpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, + strscpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, sizeof(tw_dev->tw_compat_info.driver_version)); tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 24c049eff157..70e1cac1975e 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -3289,7 +3289,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg) else qd.unmapped = 0; - strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname, + strscpy(qd.name, fsa_dev_ptr[qd.cnum].devname, min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1)); if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 2b3f0c10478e..872ad37e2a6e 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -383,7 +383,7 @@ int bnx2i_get_stats(void *handle) if (!stats) return -ENOMEM; - strlcpy(stats->version, DRV_MODULE_VERSION, sizeof(stats->version)); + strscpy(stats->version, DRV_MODULE_VERSION, sizeof(stats->version)); memcpy(stats->mac_add1 + 2, hba->cnic->mac_addr, ETH_ALEN); stats->max_frame_size = hba->netdev->mtu; diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 06ccb51bf6a9..f5334ccbf2ca 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1394,8 +1394,8 @@ static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id) host->cmd_per_lun = le32_to_cpu(iop_config.max_requests); host->max_cmd_len = 16; - req_size = struct_size((struct hpt_iop_request_scsi_command *)0, - sg_list, hba->max_sg_descriptors); + req_size = struct_size_t(struct hpt_iop_request_scsi_command, + sg_list, hba->max_sg_descriptors); if ((req_size & 0x1f) != 0) req_size = (req_size + 0x1f) & ~0x1f; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 63f32f843e75..59599299615d 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -250,7 +250,7 @@ static void gather_partition_info(void) ppartition_name = of_get_property(of_root, "ibm,partition-name", NULL); if (ppartition_name) - strlcpy(partition_name, ppartition_name, + strscpy(partition_name, ppartition_name, sizeof(partition_name)); p_number_ptr = of_get_property(of_root, "ibm,partition-no", NULL); if (p_number_ptr) @@ -1282,12 +1282,12 @@ static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata) if (hostdata->client_migrated) hostdata->caps.flags |= cpu_to_be32(CLIENT_MIGRATED); - strlcpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev), + strscpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev), sizeof(hostdata->caps.name)); location = of_get_property(of_node, "ibm,loc-code", NULL); location = location ? location : dev_name(hostdata->dev); - strlcpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc)); + strscpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc)); req->common.type = cpu_to_be32(VIOSRP_CAPABILITIES_TYPE); req->buffer = cpu_to_be64(hostdata->caps_addr); diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 317c944c68e3..050eed8e2684 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5153,8 +5153,8 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance) fusion->max_map_sz = ventura_map_sz; } else { fusion->old_map_sz = - struct_size((struct MR_FW_RAID_MAP *)0, ldSpanMap, - instance->fw_supported_vd_count); + struct_size_t(struct MR_FW_RAID_MAP, ldSpanMap, + instance->fw_supported_vd_count); fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); fusion->max_map_sz = @@ -5789,8 +5789,8 @@ megasas_setup_jbod_map(struct megasas_instance *instance) struct fusion_context *fusion = instance->ctrl_context; size_t pd_seq_map_sz; - pd_seq_map_sz = struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0, seq, - MAX_PHYSICAL_DEVICES); + pd_seq_map_sz = struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC, seq, + MAX_PHYSICAL_DEVICES); instance->use_seqnum_jbod_fp = instance->support_seqnum_jbod_fp; @@ -8033,8 +8033,8 @@ skip_firing_dcmds: if (instance->adapter_type != MFI_SERIES) { megasas_release_fusion(instance); pd_seq_map_sz = - struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0, - seq, MAX_PHYSICAL_DEVICES); + struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC, + seq, MAX_PHYSICAL_DEVICES); for (i = 0; i < 2 ; i++) { if (fusion->ld_map[i]) dma_free_coherent(&instance->pdev->dev, diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 4463a538102a..b8b388a4e28f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -326,9 +326,9 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id) else if (instance->supportmax256vd) expected_size = sizeof(struct MR_FW_RAID_MAP_EXT); else - expected_size = struct_size((struct MR_FW_RAID_MAP *)0, - ldSpanMap, - le16_to_cpu(pDrvRaidMap->ldCount)); + expected_size = struct_size_t(struct MR_FW_RAID_MAP, + ldSpanMap, + le16_to_cpu(pDrvRaidMap->ldCount)); if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) { dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x", diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 45d359554182..450522b204d6 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -2593,7 +2593,7 @@ retry_probe: sp_params.drv_minor = QEDI_DRIVER_MINOR_VER; sp_params.drv_rev = QEDI_DRIVER_REV_VER; sp_params.drv_eng = QEDI_DRIVER_ENG_VER; - strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); + strscpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params); if (rc) { QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n"); diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 03de97cd72c2..f4e0aa262164 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -5015,7 +5015,7 @@ static int pqi_create_queues(struct pqi_ctrl_info *ctrl_info) } #define PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH \ - struct_size((struct pqi_event_config *)0, descriptors, PQI_MAX_EVENT_DESCRIPTORS) + struct_size_t(struct pqi_event_config, descriptors, PQI_MAX_EVENT_DESCRIPTORS) static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info, bool enable_events) diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 1b7e0f7128d6..53b36aa29978 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -500,7 +500,7 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds, goto error_alloc; } - strlcpy(keybuf, keystart, keylen + 1); + strscpy(keybuf, keystart, keylen + 1); *value = fs64_to_cpu(sb, valarray[cur_key]); *keysize = keylen; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 32749fcee090..eee9237386e2 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -374,7 +374,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) if (S_ISLNK(inode->i_mode) && !(befs_ino->i_flags & BEFS_LONG_SYMLINK)){ inode->i_size = 0; inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE; - strlcpy(befs_ino->i_data.symlink, raw_inode->data.symlink, + strscpy(befs_ino->i_data.symlink, raw_inode->data.symlink, BEFS_SYMLINK_LEN); } else { int num_blks; diff --git a/fs/dlm/config.c b/fs/dlm/config.c index d31319d08581..2beceff024e3 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -116,9 +116,9 @@ static ssize_t cluster_cluster_name_store(struct config_item *item, { struct dlm_cluster *cl = config_item_to_cluster(item); - strlcpy(dlm_config.ci_cluster_name, buf, + strscpy(dlm_config.ci_cluster_name, buf, sizeof(dlm_config.ci_cluster_name)); - strlcpy(cl->cl_cluster_name, buf, sizeof(cl->cl_cluster_name)); + strscpy(cl->cl_cluster_name, buf, sizeof(cl->cl_cluster_name)); return len; } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 8ae419152ff6..6e17f8f94dfd 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1491,7 +1491,6 @@ journal_t *jbd2_journal_init_inode(struct inode *inode) { journal_t *journal; sector_t blocknr; - char *p; int err = 0; blocknr = 0; @@ -1515,9 +1514,8 @@ journal_t *jbd2_journal_init_inode(struct inode *inode) journal->j_inode = inode; snprintf(journal->j_devname, sizeof(journal->j_devname), - "%pg", journal->j_dev); - p = strreplace(journal->j_devname, '/', '!'); - sprintf(p, "-%lu", journal->j_inode->i_ino); + "%pg-%lu", journal->j_dev, journal->j_inode->i_ino); + strreplace(journal->j_devname, '/', '!'); jbd2_stats_proc_init(journal); return journal; diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 620329b7e6ae..7600100ba26f 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -164,7 +164,7 @@ __setup("nfsroot=", nfs_root_setup); static int __init root_nfs_copy(char *dest, const char *src, const size_t destlen) { - if (strlcpy(dest, src, destlen) > destlen) + if (strscpy(dest, src, destlen) == -E2BIG) return -1; return 0; } diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c index d2f6df69f611..1fb8f4df60cb 100644 --- a/fs/vboxsf/super.c +++ b/fs/vboxsf/super.c @@ -176,7 +176,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc) } folder_name->size = size; folder_name->length = size - 1; - strlcpy(folder_name->string.utf8, fc->source, size); + strscpy(folder_name->string.utf8, fc->source, size); err = vboxsf_map_folder(folder_name, &sbi->root); kfree(folder_name); if (err) { diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h index a2aa36b23e25..4d68a58be160 100644 --- a/fs/xfs/libxfs/xfs_btree.h +++ b/fs/xfs/libxfs/xfs_btree.h @@ -301,7 +301,7 @@ struct xfs_btree_cur static inline size_t xfs_btree_cur_sizeof(unsigned int nlevels) { - return struct_size((struct xfs_btree_cur *)NULL, bc_levels, nlevels); + return struct_size_t(struct xfs_btree_cur, bc_levels, nlevels); } /* cursor flags */ diff --git a/fs/xfs/scrub/btree.h b/fs/xfs/scrub/btree.h index 9d7b9ee8bef4..c32b5fad6174 100644 --- a/fs/xfs/scrub/btree.h +++ b/fs/xfs/scrub/btree.h @@ -60,7 +60,7 @@ struct xchk_btree { static inline size_t xchk_btree_sizeof(unsigned int nlevels) { - return struct_size((struct xchk_btree *)NULL, lastkey, nlevels - 1); + return struct_size_t(struct xchk_btree, lastkey, nlevels - 1); } int xchk_btree(struct xfs_scrub *sc, struct xfs_btree_cur *cur, diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h index f51c46f4e3e4..000764ab3985 100644 --- a/include/acpi/actbl3.h +++ b/include/acpi/actbl3.h @@ -86,7 +86,7 @@ struct acpi_table_slic { struct acpi_table_slit { struct acpi_table_header header; /* Common ACPI table header */ u64 locality_count; - u8 entry[1]; /* Real size = localities^2 */ + u8 entry[]; /* Real size = localities^2 */ }; /******************************************************************************* diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h index 84864767a56a..571fa7924f74 100644 --- a/include/linux/compiler_attributes.h +++ b/include/linux/compiler_attributes.h @@ -124,6 +124,19 @@ #endif /* + * Optional: only supported since gcc >= 14 + * Optional: only supported since clang >= 17 + * + * gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896 + * clang: https://reviews.llvm.org/D148381 + */ +#if __has_attribute(__element_count__) +# define __counted_by(member) __attribute__((__element_count__(#member))) +#else +# define __counted_by(member) +#endif + +/* * Optional: only supported since clang >= 14.0 * * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-error-function-attribute diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index c9de1f59ee80..da51a83b2829 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -20,7 +20,7 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning(" ({ \ char *__p = (char *)(p); \ size_t __ret = SIZE_MAX; \ - size_t __p_size = __member_size(p); \ + const size_t __p_size = __member_size(p); \ if (__p_size != SIZE_MAX && \ __builtin_constant_p(*__p)) { \ size_t __p_len = __p_size - 1; \ @@ -142,7 +142,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __FORTIFY_INLINE __diagnose_as(__builtin_strncpy, 1, 2, 3) char *strncpy(char * const POS p, const char *q, __kernel_size_t size) { - size_t p_size = __member_size(p); + const size_t p_size = __member_size(p); if (__compiletime_lessthan(p_size, size)) __write_overflow(); @@ -151,33 +151,6 @@ 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) -{ - size_t p_size = __member_size(p); - - if (p_size == SIZE_MAX) - return __underlying_strcat(p, q); - if (strlcat(p, q, p_size) >= p_size) - fortify_panic(__func__); - return p; -} - extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); /** * strnlen - Return bounded count of characters in a NUL-terminated string @@ -191,8 +164,8 @@ extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(st */ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size_t maxlen) { - size_t p_size = __member_size(p); - size_t p_len = __compiletime_strlen(p); + const size_t p_size = __member_size(p); + const size_t p_len = __compiletime_strlen(p); size_t ret; /* We can take compile-time actions when maxlen is const. */ @@ -233,8 +206,8 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size __FORTIFY_INLINE __diagnose_as(__builtin_strlen, 1) __kernel_size_t __fortify_strlen(const char * const POS p) { + const size_t p_size = __member_size(p); __kernel_size_t ret; - size_t p_size = __member_size(p); /* Give up if we don't know how large p is. */ if (p_size == SIZE_MAX) @@ -267,8 +240,8 @@ extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy); */ __FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, size_t size) { - size_t p_size = __member_size(p); - size_t q_size = __member_size(q); + const size_t p_size = __member_size(p); + const size_t q_size = __member_size(q); size_t q_len; /* Full count of source string length. */ size_t len; /* Count of characters going into destination. */ @@ -299,8 +272,8 @@ extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy); * @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 + * Copy the source string @q, or as much of it as fits, into the destination + * @p 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 @@ -318,10 +291,10 @@ extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy); */ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, size_t size) { - size_t len; /* Use string size rather than possible enclosing struct size. */ - size_t p_size = __member_size(p); - size_t q_size = __member_size(q); + const size_t p_size = __member_size(p); + const size_t q_size = __member_size(q); + size_t len; /* If we cannot get size of p and q default to call strscpy. */ if (p_size == SIZE_MAX && q_size == SIZE_MAX) @@ -371,6 +344,96 @@ __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() to reuse it. */ +extern size_t __real_strlcat(char *p, const char *q, size_t avail) __RENAME(strlcat); +/** + * strlcat - Append a string to an existing string + * + * @p: pointer to %NUL-terminated string to append to + * @q: pointer to %NUL-terminated string to append from + * @avail: Maximum bytes available in @p + * + * Appends %NUL-terminated string @q after the %NUL-terminated + * string at @p, but will not write beyond @avail bytes total, + * potentially truncating the copy from @q. @p will stay + * %NUL-terminated only if a %NUL already existed within + * the @avail bytes of @p. If so, the resulting number of + * bytes copied from @q will be at most "@avail - strlen(@p) - 1". + * + * 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(), seq_buf, or similar. + * + * Returns total bytes that _would_ have been contained by @p + * regardless of truncation, similar to snprintf(). If return + * value is >= @avail, the string has been truncated. + * + */ +__FORTIFY_INLINE +size_t strlcat(char * const POS p, const char * const POS q, size_t avail) +{ + const size_t p_size = __member_size(p); + const size_t q_size = __member_size(q); + size_t p_len, copy_len; + size_t actual, wanted; + + /* Give up immediately if both buffer sizes are unknown. */ + if (p_size == SIZE_MAX && q_size == SIZE_MAX) + return __real_strlcat(p, q, avail); + + p_len = strnlen(p, avail); + copy_len = strlen(q); + wanted = actual = p_len + copy_len; + + /* Cannot append any more: report truncation. */ + if (avail <= p_len) + return wanted; + + /* Give up if string is already overflowed. */ + if (p_size <= p_len) + fortify_panic(__func__); + + if (actual >= avail) { + copy_len = avail - p_len - 1; + actual = p_len + copy_len; + } + + /* Give up if copy will overflow. */ + if (p_size <= actual) + fortify_panic(__func__); + __underlying_memcpy(p + p_len, q, copy_len); + p[actual] = '\0'; + + return wanted; +} + +/* Defined after fortified strlcat() to reuse it. */ +/** + * 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) +{ + const size_t p_size = __member_size(p); + + if (strlcat(p, q, p_size) >= p_size) + fortify_panic(__func__); + return p; +} + /** * strncat - Append a string to an existing string * @@ -394,9 +457,9 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s __FORTIFY_INLINE __diagnose_as(__builtin_strncat, 1, 2, 3) char *strncat(char * const POS p, const char * const POS q, __kernel_size_t count) { + const size_t p_size = __member_size(p); + const size_t q_size = __member_size(q); size_t p_len, copy_len; - size_t p_size = __member_size(p); - size_t q_size = __member_size(q); if (p_size == SIZE_MAX && q_size == SIZE_MAX) return __underlying_strncat(p, q, count); @@ -639,7 +702,7 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan); __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size) { - size_t p_size = __struct_size(p); + const size_t p_size = __struct_size(p); if (__compiletime_lessthan(p_size, size)) __read_overflow(); @@ -651,8 +714,8 @@ __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size) __FORTIFY_INLINE __diagnose_as(__builtin_memcmp, 1, 2, 3) int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t size) { - size_t p_size = __struct_size(p); - size_t q_size = __struct_size(q); + const size_t p_size = __struct_size(p); + const size_t q_size = __struct_size(q); if (__builtin_constant_p(size)) { if (__compiletime_lessthan(p_size, size)) @@ -668,7 +731,7 @@ int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t __FORTIFY_INLINE __diagnose_as(__builtin_memchr, 1, 2, 3) void *memchr(const void * const POS0 p, int c, __kernel_size_t size) { - size_t p_size = __struct_size(p); + const size_t p_size = __struct_size(p); if (__compiletime_lessthan(p_size, size)) __read_overflow(); @@ -680,7 +743,7 @@ void *memchr(const void * const POS0 p, int c, __kernel_size_t size) void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv); __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size) { - size_t p_size = __struct_size(p); + const size_t p_size = __struct_size(p); if (__compiletime_lessthan(p_size, size)) __read_overflow(); @@ -693,7 +756,7 @@ extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kme __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); + const size_t p_size = __struct_size(p); if (__compiletime_lessthan(p_size, size)) __read_overflow(); @@ -720,8 +783,8 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp __FORTIFY_INLINE __diagnose_as(__builtin_strcpy, 1, 2) char *strcpy(char * const POS p, const char * const POS q) { - size_t p_size = __member_size(p); - size_t q_size = __member_size(q); + const size_t p_size = __member_size(p); + const size_t q_size = __member_size(q); size_t size; /* If neither buffer size is known, immediately give up. */ diff --git a/include/linux/overflow.h b/include/linux/overflow.h index 0e33b5cbdb9f..f9b60313eaea 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -283,7 +283,7 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) * @member: Name of the array member. * @count: Number of elements in the array. * - * Calculates size of memory needed for structure @p followed by an + * Calculates size of memory needed for structure of @p followed by an * array of @count number of @member elements. * * Return: number of bytes needed or SIZE_MAX on overflow. @@ -293,4 +293,20 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) sizeof(*(p)) + flex_array_size(p, member, count), \ size_add(sizeof(*(p)), flex_array_size(p, member, count))) +/** + * struct_size_t() - Calculate size of structure with trailing flexible array + * @type: structure type name. + * @member: Name of the array member. + * @count: Number of elements in the array. + * + * Calculates size of memory needed for structure @type followed by an + * array of @count number of @member elements. Prefer using struct_size() + * when possible instead, to keep calculations associated with a specific + * instance variable of type @type. + * + * Return: number of bytes needed or SIZE_MAX on overflow. + */ +#define struct_size_t(type, member, count) \ + struct_size((type *)NULL, member, count) + #endif /* __LINUX_OVERFLOW_H */ diff --git a/include/linux/string.h b/include/linux/string.h index c062c581a98b..dbfc66400050 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -169,7 +169,7 @@ static inline void memcpy_flushcache(void *dst, const void *src, size_t cnt) #endif void *memchr_inv(const void *s, int c, size_t n); -char *strreplace(char *s, char old, char new); +char *strreplace(char *str, char old, char new); extern void kfree_const(const void *x); diff --git a/include/uapi/linux/auto_dev-ioctl.h b/include/uapi/linux/auto_dev-ioctl.h index 62e625356dc8..08be539605fc 100644 --- a/include/uapi/linux/auto_dev-ioctl.h +++ b/include/uapi/linux/auto_dev-ioctl.h @@ -109,7 +109,7 @@ struct autofs_dev_ioctl { struct args_ismountpoint ismountpoint; }; - char path[0]; + char path[]; }; static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in) diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 77747391f49b..ddb91d8edaae 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -716,7 +716,7 @@ static int get_ksymbol_bpf(struct kallsym_iter *iter) { int ret; - strlcpy(iter->module_name, "bpf", MODULE_NAME_LEN); + strscpy(iter->module_name, "bpf", MODULE_NAME_LEN); iter->exported = 0; ret = bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end, &iter->value, &iter->type, @@ -736,7 +736,7 @@ static int get_ksymbol_bpf(struct kallsym_iter *iter) */ static int get_ksymbol_kprobe(struct kallsym_iter *iter) { - strlcpy(iter->module_name, "__builtin__kprobes", MODULE_NAME_LEN); + strscpy(iter->module_name, "__builtin__kprobes", MODULE_NAME_LEN); iter->exported = 0; return kprobe_get_kallsym(iter->pos - iter->pos_bpf_end, &iter->value, &iter->type, diff --git a/kernel/params.c b/kernel/params.c index 6a7548979aa9..07d01f6ce9a2 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -847,7 +847,7 @@ static void __init param_sysfs_builtin(void) name_len = 0; } else { name_len = dot - kp->name + 1; - strlcpy(modname, kp->name, name_len); + strscpy(modname, kp->name, name_len); } kernel_add_sysfs_param(modname, kp, name_len); } diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 91836b727cef..88cbc1181b23 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -1480,7 +1480,7 @@ static int __init boot_override_clocksource(char* str) { mutex_lock(&clocksource_mutex); if (str) - strlcpy(override_name, str, sizeof(override_name)); + strscpy(override_name, str, sizeof(override_name)); mutex_unlock(&clocksource_mutex); return 1; } diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 764668467155..6a77edb51f18 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -5743,7 +5743,7 @@ bool ftrace_filter_param __initdata; static int __init set_ftrace_notrace(char *str) { ftrace_filter_param = true; - strlcpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); + strscpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_notrace=", set_ftrace_notrace); @@ -5751,7 +5751,7 @@ __setup("ftrace_notrace=", set_ftrace_notrace); static int __init set_ftrace_filter(char *str) { ftrace_filter_param = true; - strlcpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); + strscpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_filter=", set_ftrace_filter); @@ -5763,14 +5763,14 @@ static int ftrace_graph_set_hash(struct ftrace_hash *hash, char *buffer); static int __init set_graph_function(char *str) { - strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); + strscpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_graph_filter=", set_graph_function); static int __init set_graph_notrace_function(char *str) { - strlcpy(ftrace_graph_notrace_buf, str, FTRACE_FILTER_SIZE); + strscpy(ftrace_graph_notrace_buf, str, FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_graph_notrace=", set_graph_notrace_function); @@ -6569,8 +6569,8 @@ static int ftrace_get_trampoline_kallsym(unsigned int symnum, continue; *value = op->trampoline; *type = 't'; - strlcpy(name, FTRACE_TRAMPOLINE_SYM, KSYM_NAME_LEN); - strlcpy(module_name, FTRACE_TRAMPOLINE_MOD, MODULE_NAME_LEN); + strscpy(name, FTRACE_TRAMPOLINE_SYM, KSYM_NAME_LEN); + strscpy(module_name, FTRACE_TRAMPOLINE_MOD, MODULE_NAME_LEN); *exported = 0; return 0; } @@ -6933,7 +6933,7 @@ ftrace_func_address_lookup(struct ftrace_mod_map *mod_map, if (off) *off = addr - found_func->ip; if (sym) - strlcpy(sym, found_func->name, KSYM_NAME_LEN); + strscpy(sym, found_func->name, KSYM_NAME_LEN); return found_func->name; } @@ -6987,8 +6987,8 @@ int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value, *value = mod_func->ip; *type = 'T'; - strlcpy(name, mod_func->name, KSYM_NAME_LEN); - strlcpy(module_name, mod_map->mod->name, MODULE_NAME_LEN); + strscpy(name, mod_func->name, KSYM_NAME_LEN); + strscpy(module_name, mod_map->mod->name, MODULE_NAME_LEN); *exported = 1; preempt_enable(); return 0; diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 5d2c5678b66f..074d0b2e19ed 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -199,7 +199,7 @@ static int boot_snapshot_index; static int __init set_cmdline_ftrace(char *str) { - strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); + strscpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); default_bootup_tracer = bootup_tracer_buf; /* We are using ftrace early, expand it */ ring_buffer_expanded = true; @@ -284,7 +284,7 @@ static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata; static int __init set_trace_boot_options(char *str) { - strlcpy(trace_boot_options_buf, str, MAX_TRACER_SIZE); + strscpy(trace_boot_options_buf, str, MAX_TRACER_SIZE); return 1; } __setup("trace_options=", set_trace_boot_options); @@ -294,7 +294,7 @@ static char *trace_boot_clock __initdata; static int __init set_trace_boot_clock(char *str) { - strlcpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE); + strscpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE); trace_boot_clock = trace_boot_clock_buf; return 1; } @@ -2546,7 +2546,7 @@ static void __trace_find_cmdline(int pid, char comm[]) if (map != NO_CMDLINE_MAP) { tpid = savedcmd->map_cmdline_to_pid[map]; if (tpid == pid) { - strlcpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN); + strscpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN); return; } } diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 57e539d47989..5d6ae4eae510 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -2833,7 +2833,7 @@ static __init int setup_trace_triggers(char *str) char *buf; int i; - strlcpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE); + strscpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE); ring_buffer_expanded = true; disable_tracing_selftest("running event triggers"); @@ -3623,7 +3623,7 @@ static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata; static __init int setup_trace_event(char *str) { - strlcpy(bootup_event_buf, str, COMMAND_LINE_SIZE); + strscpy(bootup_event_buf, str, COMMAND_LINE_SIZE); ring_buffer_expanded = true; disable_tracing_selftest("running event tracing"); diff --git a/kernel/trace/trace_events_inject.c b/kernel/trace/trace_events_inject.c index d6b4935a78c0..abe805d471eb 100644 --- a/kernel/trace/trace_events_inject.c +++ b/kernel/trace/trace_events_inject.c @@ -217,7 +217,7 @@ static int parse_entry(char *str, struct trace_event_call *call, void **pentry) char *addr = (char *)(unsigned long) val; if (field->filter_type == FILTER_STATIC_STRING) { - strlcpy(entry + field->offset, addr, field->size); + strscpy(entry + field->offset, addr, field->size); } else if (field->filter_type == FILTER_DYN_STRING || field->filter_type == FILTER_RDYN_STRING) { int str_len = strlen(addr) + 1; @@ -232,7 +232,7 @@ static int parse_entry(char *str, struct trace_event_call *call, void **pentry) } entry = *pentry; - strlcpy(entry + (entry_size - str_len), addr, str_len); + strscpy(entry + (entry_size - str_len), addr, str_len); str_item = (u32 *)(entry + field->offset); if (field->filter_type == FILTER_RDYN_STRING) str_loc -= field->offset + field->size; diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 59cda19a9033..1b3fa7b854aa 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -30,7 +30,7 @@ static char kprobe_boot_events_buf[COMMAND_LINE_SIZE] __initdata; static int __init set_kprobe_boot_events(char *str) { - strlcpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE); + strscpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE); disable_tracing_selftest("running kprobe events"); return 1; diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 2d2616678295..73055ba8d8ef 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -254,7 +254,7 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup, trace_probe_log_err(offset, GROUP_TOO_LONG); return -EINVAL; } - strlcpy(buf, event, slash - event + 1); + strscpy(buf, event, slash - event + 1); if (!is_good_system_name(buf)) { trace_probe_log_err(offset, BAD_GROUP_NAME); return -EINVAL; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 1d5c3bc40113..b9cb205ce3f8 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2675,7 +2675,7 @@ config STACKINIT_KUNIT_TEST config FORTIFY_KUNIT_TEST tristate "Test fortified str*() and mem*() function internals at runtime" if !KUNIT_ALL_TESTS - depends on KUNIT && FORTIFY_SOURCE + depends on KUNIT default KUNIT_ALL_TESTS help Builds unit tests for checking internals of FORTIFY_SOURCE as used @@ -2692,6 +2692,11 @@ config HW_BREAKPOINT_KUNIT_TEST If unsure, say N. +config STRCAT_KUNIT_TEST + tristate "Test strcat() family of functions at runtime" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + config STRSCPY_KUNIT_TEST tristate "Test strscpy*() family of functions at runtime" if !KUNIT_ALL_TESTS depends on KUNIT diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index fd15230a703b..efae7e011956 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -15,7 +15,6 @@ if UBSAN config UBSAN_TRAP bool "On Sanitizer warnings, abort the running kernel code" depends on !COMPILE_TEST - depends on $(cc-option, -fsanitize-undefined-trap-on-error) help Building kernels with Sanitizer features enabled tends to grow the kernel size by around 5%, due to adding all the debugging @@ -27,16 +26,29 @@ config UBSAN_TRAP the system. For some system builders this is an acceptable trade-off. -config CC_HAS_UBSAN_BOUNDS - def_bool $(cc-option,-fsanitize=bounds) +config CC_HAS_UBSAN_BOUNDS_STRICT + def_bool $(cc-option,-fsanitize=bounds-strict) + help + The -fsanitize=bounds-strict option is only available on GCC, + but uses the more strict handling of arrays that includes knowledge + of flexible arrays, which is comparable to Clang's regular + -fsanitize=bounds. config CC_HAS_UBSAN_ARRAY_BOUNDS def_bool $(cc-option,-fsanitize=array-bounds) + help + Under Clang, the -fsanitize=bounds option is actually composed + of two more specific options, -fsanitize=array-bounds and + -fsanitize=local-bounds. However, -fsanitize=local-bounds can + only be used when trap mode is enabled. (See also the help for + CONFIG_LOCAL_BOUNDS.) Explicitly check for -fsanitize=array-bounds + so that we can build up the options needed for UBSAN_BOUNDS + with or without UBSAN_TRAP. config UBSAN_BOUNDS bool "Perform array index bounds checking" default UBSAN - depends on CC_HAS_UBSAN_ARRAY_BOUNDS || CC_HAS_UBSAN_BOUNDS + depends on CC_HAS_UBSAN_ARRAY_BOUNDS || CC_HAS_UBSAN_BOUNDS_STRICT help This option enables detection of directly indexed out of bounds array accesses, where the array size is known at compile time. @@ -44,33 +56,26 @@ config UBSAN_BOUNDS to the {str,mem}*cpy() family of functions (that is addressed by CONFIG_FORTIFY_SOURCE). -config UBSAN_ONLY_BOUNDS - def_bool CC_HAS_UBSAN_BOUNDS && !CC_HAS_UBSAN_ARRAY_BOUNDS - depends on UBSAN_BOUNDS +config UBSAN_BOUNDS_STRICT + def_bool UBSAN_BOUNDS && CC_HAS_UBSAN_BOUNDS_STRICT help - This is a weird case: Clang's -fsanitize=bounds includes - -fsanitize=local-bounds, but it's trapping-only, so for - Clang, we must use -fsanitize=array-bounds when we want - traditional array bounds checking enabled. For GCC, we - want -fsanitize=bounds. + GCC's bounds sanitizer. This option is used to select the + correct options in Makefile.ubsan. config UBSAN_ARRAY_BOUNDS - def_bool CC_HAS_UBSAN_ARRAY_BOUNDS - depends on UBSAN_BOUNDS + def_bool UBSAN_BOUNDS && CC_HAS_UBSAN_ARRAY_BOUNDS + help + Clang's array bounds sanitizer. This option is used to select + the correct options in Makefile.ubsan. config UBSAN_LOCAL_BOUNDS - bool "Perform array local bounds checking" - depends on UBSAN_TRAP - depends on $(cc-option,-fsanitize=local-bounds) - help - This option enables -fsanitize=local-bounds which traps when an - exception/error is detected. Therefore, it may only be enabled - with CONFIG_UBSAN_TRAP. - - Enabling this option detects errors due to accesses through a - pointer that is derived from an object of a statically-known size, - where an added offset (which may not be known statically) is - out-of-bounds. + def_bool UBSAN_ARRAY_BOUNDS && UBSAN_TRAP + help + This option enables Clang's -fsanitize=local-bounds which traps + when an access through a pointer that is derived from an object + of a statically-known size, where an added offset (which may not + be known statically) is out-of-bounds. Since this option is + trap-only, it depends on CONFIG_UBSAN_TRAP. config UBSAN_SHIFT bool "Perform checking for bit-shift overflows" diff --git a/lib/Makefile b/lib/Makefile index cd37ec1d9a2f..0964274b075d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -393,6 +393,7 @@ obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced) CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN) obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o +obj-$(CONFIG_STRCAT_KUNIT_TEST) += strcat_kunit.o obj-$(CONFIG_STRSCPY_KUNIT_TEST) += strscpy_kunit.o obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c index c8c33cbaae9e..524132f33cf0 100644 --- a/lib/fortify_kunit.c +++ b/lib/fortify_kunit.c @@ -25,6 +25,11 @@ static const char array_of_10[] = "this is 10"; static const char *ptr_of_11 = "this is 11!"; static char array_unknown[] = "compiler thinks I might change"; +/* Handle being built without CONFIG_FORTIFY_SOURCE */ +#ifndef __compiletime_strlen +# define __compiletime_strlen __builtin_strlen +#endif + static void known_sizes_test(struct kunit *test) { KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888"), 8); @@ -307,6 +312,14 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc) } while (0) DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc) +static int fortify_test_init(struct kunit *test) +{ + if (!IS_ENABLED(CONFIG_FORTIFY_SOURCE)) + kunit_skip(test, "Not built with CONFIG_FORTIFY_SOURCE=y"); + + return 0; +} + static struct kunit_case fortify_test_cases[] = { KUNIT_CASE(known_sizes_test), KUNIT_CASE(control_flow_split_test), @@ -323,6 +336,7 @@ static struct kunit_case fortify_test_cases[] = { static struct kunit_suite fortify_test_suite = { .name = "fortify", + .init = fortify_test_init, .test_cases = fortify_test_cases, }; diff --git a/lib/kobject.c b/lib/kobject.c index f79a434e1231..16d530f9c174 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -281,8 +281,7 @@ int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, kfree_const(s); if (!t) return -ENOMEM; - strreplace(t, '/', '!'); - s = t; + s = strreplace(t, '/', '!'); } kfree_const(kobj->name); kobj->name = s; diff --git a/lib/overflow_kunit.c b/lib/overflow_kunit.c index dcd3ba102db6..34db0b3aa502 100644 --- a/lib/overflow_kunit.c +++ b/lib/overflow_kunit.c @@ -649,7 +649,7 @@ struct __test_flex_array { static void overflow_size_helpers_test(struct kunit *test) { /* Make sure struct_size() can be used in a constant expression. */ - u8 ce_array[struct_size((struct __test_flex_array *)0, data, 55)]; + u8 ce_array[struct_size_t(struct __test_flex_array, data, 55)]; struct __test_flex_array *obj; int count = 0; int var; diff --git a/lib/strcat_kunit.c b/lib/strcat_kunit.c new file mode 100644 index 000000000000..e21be95514af --- /dev/null +++ b/lib/strcat_kunit.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kernel module for testing 'strcat' family of functions. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <kunit/test.h> +#include <linux/string.h> + +static volatile int unconst; + +static void strcat_test(struct kunit *test) +{ + char dest[8]; + + /* Destination is terminated. */ + memset(dest, 0, sizeof(dest)); + KUNIT_EXPECT_EQ(test, strlen(dest), 0); + /* Empty copy does nothing. */ + KUNIT_EXPECT_TRUE(test, strcat(dest, "") == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* 4 characters copied in, stops at %NUL. */ + KUNIT_EXPECT_TRUE(test, strcat(dest, "four\000123") == dest); + KUNIT_EXPECT_STREQ(test, dest, "four"); + KUNIT_EXPECT_EQ(test, dest[5], '\0'); + /* 2 more characters copied in okay. */ + KUNIT_EXPECT_TRUE(test, strcat(dest, "AB") == dest); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); +} + +static void strncat_test(struct kunit *test) +{ + char dest[8]; + + /* Destination is terminated. */ + memset(dest, 0, sizeof(dest)); + KUNIT_EXPECT_EQ(test, strlen(dest), 0); + /* Empty copy of size 0 does nothing. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "", 0 + unconst) == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* Empty copy of size 1 does nothing too. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "", 1 + unconst) == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* Copy of max 0 characters should do nothing. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "asdf", 0 + unconst) == dest); + KUNIT_EXPECT_STREQ(test, dest, ""); + + /* 4 characters copied in, even if max is 8. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "four\000123", 8 + unconst) == dest); + KUNIT_EXPECT_STREQ(test, dest, "four"); + KUNIT_EXPECT_EQ(test, dest[5], '\0'); + KUNIT_EXPECT_EQ(test, dest[6], '\0'); + /* 2 characters copied in okay, 2 ignored. */ + KUNIT_EXPECT_TRUE(test, strncat(dest, "ABCD", 2 + unconst) == dest); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); +} + +static void strlcat_test(struct kunit *test) +{ + char dest[8] = ""; + int len = sizeof(dest) + unconst; + + /* Destination is terminated. */ + KUNIT_EXPECT_EQ(test, strlen(dest), 0); + /* Empty copy is size 0. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "", len), 0); + KUNIT_EXPECT_STREQ(test, dest, ""); + /* Size 1 should keep buffer terminated, report size of source only. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "four", 1 + unconst), 4); + KUNIT_EXPECT_STREQ(test, dest, ""); + + /* 4 characters copied in. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "four", len), 4); + KUNIT_EXPECT_STREQ(test, dest, "four"); + /* 2 characters copied in okay, gets to 6 total. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "AB", len), 6); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); + /* 2 characters ignored if max size (7) reached. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "CD", 7 + unconst), 8); + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); + /* 1 of 2 characters skipped, now at true max size. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "EFG", len), 9); + KUNIT_EXPECT_STREQ(test, dest, "fourABE"); + /* Everything else ignored, now at full size. */ + KUNIT_EXPECT_EQ(test, strlcat(dest, "1234", len), 11); + KUNIT_EXPECT_STREQ(test, dest, "fourABE"); +} + +static struct kunit_case strcat_test_cases[] = { + KUNIT_CASE(strcat_test), + KUNIT_CASE(strncat_test), + KUNIT_CASE(strlcat_test), + {} +}; + +static struct kunit_suite strcat_test_suite = { + .name = "strcat", + .test_cases = strcat_test_cases, +}; + +kunit_test_suite(strcat_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/lib/string.c b/lib/string.c index 3d55ef890106..be26623953d2 100644 --- a/lib/string.c +++ b/lib/string.c @@ -110,7 +110,7 @@ size_t strlcpy(char *dest, const char *src, size_t size) if (size) { size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); + __builtin_memcpy(dest, src, len); dest[len] = '\0'; } return ret; @@ -260,7 +260,7 @@ size_t strlcat(char *dest, const char *src, size_t count) count -= dsize; if (len >= count) len = count-1; - memcpy(dest, src, len); + __builtin_memcpy(dest, src, len); dest[len] = 0; return res; } diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 230020a2e076..d3b1dd718daf 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c @@ -979,18 +979,22 @@ EXPORT_SYMBOL(__sysfs_match_string); /** * strreplace - Replace all occurrences of character in string. - * @s: The string to operate on. + * @str: The string to operate on. * @old: The character being replaced. * @new: The character @old is replaced with. * - * Returns pointer to the nul byte at the end of @s. + * Replaces the each @old character with a @new one in the given string @str. + * + * Return: pointer to the string @str itself. */ -char *strreplace(char *s, char old, char new) +char *strreplace(char *str, char old, char new) { + char *s = str; + for (; *s; ++s) if (*s == old) *s = new; - return s; + return str; } EXPORT_SYMBOL(strreplace); diff --git a/lib/ubsan.c b/lib/ubsan.c index e2cc4a799312..3f90810f9f42 100644 --- a/lib/ubsan.c +++ b/lib/ubsan.c @@ -425,9 +425,6 @@ EXPORT_SYMBOL(__ubsan_handle_load_invalid_value); void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, unsigned long align, - unsigned long offset); -void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, - unsigned long align, unsigned long offset) { struct alignment_assumption_data *data = _data; diff --git a/lib/ubsan.h b/lib/ubsan.h index cc5cb94895a6..5d99ab81913b 100644 --- a/lib/ubsan.h +++ b/lib/ubsan.h @@ -124,4 +124,15 @@ typedef s64 s_max; typedef u64 u_max; #endif +void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs); +void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr); +void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr); +void __ubsan_handle_out_of_bounds(void *_data, void *index); +void __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs); +void __ubsan_handle_builtin_unreachable(void *_data); +void __ubsan_handle_load_invalid_value(void *_data, void *val); +void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, + unsigned long align, + unsigned long offset); + #endif diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index 031073286236..95aeb31c60e0 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c @@ -40,7 +40,7 @@ MODULE_ALIAS("ip_set_hash:net,iface"); #define IP_SET_HASH_WITH_MULTI #define IP_SET_HASH_WITH_NET0 -#define STRLCPY(a, b) strlcpy(a, b, IFNAMSIZ) +#define STRSCPY(a, b) strscpy(a, b, IFNAMSIZ) /* IPv4 variant */ @@ -182,11 +182,11 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb, if (!eiface) return -EINVAL; - STRLCPY(e.iface, eiface); + STRSCPY(e.iface, eiface); e.physdev = 1; #endif } else { - STRLCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); + STRSCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); } if (strlen(e.iface) == 0) @@ -400,11 +400,11 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb, if (!eiface) return -EINVAL; - STRLCPY(e.iface, eiface); + STRSCPY(e.iface, eiface); e.physdev = 1; #endif } else { - STRLCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); + STRSCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); } if (strlen(e.iface) == 0) diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 7099c603ff0a..4749865c1b2c 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -2,7 +2,7 @@ # Enable available and selected UBSAN features. ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += -fsanitize=alignment -ubsan-cflags-$(CONFIG_UBSAN_ONLY_BOUNDS) += -fsanitize=bounds +ubsan-cflags-$(CONFIG_UBSAN_BOUNDS_STRICT) += -fsanitize=bounds-strict ubsan-cflags-$(CONFIG_UBSAN_ARRAY_BOUNDS) += -fsanitize=array-bounds ubsan-cflags-$(CONFIG_UBSAN_LOCAL_BOUNDS) += -fsanitize=local-bounds ubsan-cflags-$(CONFIG_UBSAN_SHIFT) += -fsanitize=shift diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index b30114d637c4..7bfa4d39d17f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -6997,10 +6997,22 @@ sub process { # } # } +# strcpy uses that should likely be strscpy + if ($line =~ /\bstrcpy\s*\(/) { + WARN("STRCPY", + "Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr); + } + # strlcpy uses that should likely be strscpy if ($line =~ /\bstrlcpy\s*\(/) { WARN("STRLCPY", - "Prefer strscpy over strlcpy - see: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw\@mail.gmail.com/\n" . $herecurr); + "Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr); + } + +# strncpy uses that should likely be strscpy or strscpy_pad + if ($line =~ /\bstrncpy\s*\(/) { + WARN("STRNCPY", + "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr); } # typecasts on min/max could be min_t/max_t @@ -7418,6 +7430,16 @@ sub process { } } +# check for array definition/declarations that should use flexible arrays instead + if ($sline =~ /^[\+ ]\s*\}(?:\s*__packed)?\s*;\s*$/ && + $prevline =~ /^\+\s*(?:\}(?:\s*__packed\s*)?|$Type)\s*$Ident\s*\[\s*(0|1)\s*\]\s*;\s*$/) { + if (ERROR("FLEXIBLE_ARRAY", + "Use C99 flexible arrays - see https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays\n" . $hereprev) && + $1 == '0' && $fix) { + $fixed[$fixlinenr - 1] =~ s/\[\s*0\s*\]/[]/; + } + } + # nested likely/unlikely calls if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { WARN("LIKELY_MISUSE", diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index f990cbb73250..0393940c706a 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -9,6 +9,8 @@ CONFIG_KUNIT=y CONFIG_KUNIT_EXAMPLE_TEST=y CONFIG_KUNIT_ALL_TESTS=y +CONFIG_FORTIFY_SOURCE=y + CONFIG_IIO=y CONFIG_EXT4_FS=y diff --git a/tools/testing/kunit/configs/arch_uml.config b/tools/testing/kunit/configs/arch_uml.config index e824ce43b05a..54ad8972681a 100644 --- a/tools/testing/kunit/configs/arch_uml.config +++ b/tools/testing/kunit/configs/arch_uml.config @@ -3,3 +3,6 @@ # Enable virtio/pci, as a lot of tests require it. CONFIG_VIRTIO_UML=y CONFIG_UML_PCI_OVER_VIRTIO=y + +# Enable FORTIFY_SOURCE for wider checking. +CONFIG_FORTIFY_SOURCE=y |