Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+466 -202
+1 -1
Documentation/filesystems/autofs-mount-control.rst
··· 196 196 struct args_ismountpoint ismountpoint; 197 197 }; 198 198 199 - char path[0]; 199 + char path[]; 200 200 }; 201 201 202 202 The ioctlfd field is a mount point file descriptor of an autofs mount
+1 -1
Documentation/filesystems/autofs.rst
··· 467 467 struct args_ismountpoint ismountpoint; 468 468 }; 469 469 470 - char path[0]; 470 + char path[]; 471 471 }; 472 472 473 473 For the **OPEN_MOUNT** and **IS_MOUNTPOINT** commands, the target
+1
MAINTAINERS
··· 8099 8099 F: include/linux/fortify-string.h 8100 8100 F: lib/fortify_kunit.c 8101 8101 F: lib/memcpy_kunit.c 8102 + F: lib/strcat_kunit.c 8102 8103 F: lib/strscpy_kunit.c 8103 8104 F: lib/test_fortify/* 8104 8105 F: scripts/test_fortify.sh
+6
Makefile
··· 1026 1026 # globally built with -Wcast-function-type. 1027 1027 KBUILD_CFLAGS += $(call cc-option, -Wcast-function-type) 1028 1028 1029 + # To gain proper coverage for CONFIG_UBSAN_BOUNDS and CONFIG_FORTIFY_SOURCE, 1030 + # the kernel uses only C99 flexible arrays for dynamically sized trailing 1031 + # arrays. Enforce this for everything that may examine structure sizes and 1032 + # perform bounds checking. 1033 + KBUILD_CFLAGS += $(call cc-option, -fstrict-flex-arrays=3) 1034 + 1029 1035 # disable stringop warnings in gcc 8+ 1030 1036 KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation) 1031 1037
+3 -3
arch/hexagon/kernel/setup.c
··· 66 66 on_simulator = 0; 67 67 68 68 if (p[0] != '\0') 69 - strlcpy(boot_command_line, p, COMMAND_LINE_SIZE); 69 + strscpy(boot_command_line, p, COMMAND_LINE_SIZE); 70 70 else 71 - strlcpy(boot_command_line, default_command_line, 71 + strscpy(boot_command_line, default_command_line, 72 72 COMMAND_LINE_SIZE); 73 73 74 74 /* ··· 76 76 * are both picked up by the init code. If no reason to 77 77 * make them different, pass the same pointer back. 78 78 */ 79 - strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 79 + strscpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 80 80 *cmdline_p = cmd_line; 81 81 82 82 parse_early_param();
+1 -1
arch/microblaze/kernel/prom.c
··· 20 20 21 21 early_init_dt_scan(params); 22 22 if (!strlen(boot_command_line)) 23 - strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); 23 + strscpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); 24 24 25 25 memblock_allow_resize(); 26 26
+1 -1
arch/riscv/purgatory/Makefile
··· 31 31 $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE 32 32 $(call if_changed_rule,cc_o_c) 33 33 34 - CFLAGS_sha256.o := -D__DISABLE_EXPORTS 34 + CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY 35 35 CFLAGS_string.o := -D__DISABLE_EXPORTS 36 36 CFLAGS_ctype.o := -D__DISABLE_EXPORTS 37 37
+1 -1
arch/s390/purgatory/Makefile
··· 10 10 $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE 11 11 $(call if_changed_rule,cc_o_c) 12 12 13 - CFLAGS_sha256.o := -D__DISABLE_EXPORTS 13 + CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY 14 14 15 15 $(obj)/mem.o: $(srctree)/arch/s390/lib/mem.S FORCE 16 16 $(call if_changed_rule,as_o_S)
+1 -1
arch/sh/drivers/dma/dma-api.c
··· 198 198 if (atomic_xchg(&channel->busy, 1)) 199 199 return -EBUSY; 200 200 201 - strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); 201 + strscpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); 202 202 203 203 if (info->ops->request) { 204 204 result = info->ops->request(channel);
+2 -2
arch/sh/kernel/setup.c
··· 305 305 bss_resource.end = virt_to_phys(__bss_stop)-1; 306 306 307 307 #ifdef CONFIG_CMDLINE_OVERWRITE 308 - strlcpy(command_line, CONFIG_CMDLINE, sizeof(command_line)); 308 + strscpy(command_line, CONFIG_CMDLINE, sizeof(command_line)); 309 309 #else 310 - strlcpy(command_line, COMMAND_LINE, sizeof(command_line)); 310 + strscpy(command_line, COMMAND_LINE, sizeof(command_line)); 311 311 #ifdef CONFIG_CMDLINE_EXTEND 312 312 strlcat(command_line, " ", sizeof(command_line)); 313 313 strlcat(command_line, CONFIG_CMDLINE, sizeof(command_line));
+1 -1
arch/sparc/kernel/ioport.c
··· 191 191 tack += sizeof (struct resource); 192 192 } 193 193 194 - strlcpy(tack, name, XNMLN+1); 194 + strscpy(tack, name, XNMLN+1); 195 195 res->name = tack; 196 196 197 197 va = _sparc_ioremap(res, busno, phys, size);
+1 -1
arch/sparc/kernel/setup_32.c
··· 302 302 303 303 /* Initialize PROM console and command line. */ 304 304 *cmdline_p = prom_getbootargs(); 305 - strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); 305 + strscpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); 306 306 parse_early_param(); 307 307 308 308 boot_flags_init(*cmdline_p);
+1 -1
arch/sparc/kernel/setup_64.c
··· 636 636 { 637 637 /* Initialize PROM console and command line. */ 638 638 *cmdline_p = prom_getbootargs(); 639 - strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); 639 + strscpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); 640 640 parse_early_param(); 641 641 642 642 boot_flags_init(*cmdline_p);
+1 -1
arch/sparc/prom/bootstr_32.c
··· 52 52 * V3 PROM cannot supply as with more than 128 bytes 53 53 * of an argument. But a smart bootstrap loader can. 54 54 */ 55 - strlcpy(barg_buf, *romvec->pv_v2bootargs.bootargs, sizeof(barg_buf)); 55 + strscpy(barg_buf, *romvec->pv_v2bootargs.bootargs, sizeof(barg_buf)); 56 56 break; 57 57 default: 58 58 break;
+1 -1
arch/um/Makefile
··· 149 149 # When cleaning we don't include .config, so we don't include 150 150 # TT or skas makefiles and don't clean skas_ptregs.h. 151 151 CLEAN_FILES += linux x.i gmon.out 152 - MRPROPER_FILES += arch/$(SUBARCH)/include/generated 152 + MRPROPER_FILES += $(HOST_DIR)/include/generated 153 153 154 154 archclean: 155 155 @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
+1
arch/um/include/shared/user.h
··· 52 52 extern int in_aton(char *str); 53 53 extern size_t strlcpy(char *, const char *, size_t); 54 54 extern size_t strlcat(char *, const char *, size_t); 55 + extern size_t strscpy(char *, const char *, size_t); 55 56 56 57 /* Copied from linux/compiler-gcc.h since we can't include it directly */ 57 58 #define barrier() __asm__ __volatile__("": : :"memory")
+1 -1
arch/um/os-Linux/drivers/tuntap_user.c
··· 146 146 } 147 147 memset(&ifr, 0, sizeof(ifr)); 148 148 ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 149 - strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); 149 + strscpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); 150 150 if (ioctl(pri->fd, TUNSETIFF, &ifr) < 0) { 151 151 err = -errno; 152 152 printk(UM_KERN_ERR "TUNSETIFF failed, errno = %d\n",
+1 -1
arch/x86/purgatory/Makefile
··· 12 12 $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE 13 13 $(call if_changed_rule,cc_o_c) 14 14 15 - CFLAGS_sha256.o := -D__DISABLE_EXPORTS 15 + CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY 16 16 17 17 # When profile-guided optimization is enabled, llvm emits two different 18 18 # overlapping text sections, which is not supported by kexec. Remove profile
+1 -1
drivers/gpu/drm/amd/amdgpu/atom.c
··· 1509 1509 str = CSTR(idx); 1510 1510 if (*str != '\0') { 1511 1511 pr_info("ATOM BIOS: %s\n", str); 1512 - strlcpy(ctx->vbios_version, str, sizeof(ctx->vbios_version)); 1512 + strscpy(ctx->vbios_version, str, sizeof(ctx->vbios_version)); 1513 1513 } 1514 1514 1515 1515 atom_rom_header = (struct _ATOM_ROM_HEADER *)CSTR(base);
+1 -1
drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c
··· 794 794 struct i2c_board_info info = { }; 795 795 const char *name = pp_lib_thermal_controller_names[controller->ucType]; 796 796 info.addr = controller->ucI2cAddress >> 1; 797 - strlcpy(info.type, name, sizeof(info.type)); 797 + strscpy(info.type, name, sizeof(info.type)); 798 798 i2c_new_client_device(&adev->pm.i2c_bus->adapter, &info); 799 799 } 800 800 } else {
+1 -1
drivers/gpu/drm/display/drm_dp_helper.c
··· 2103 2103 aux->ddc.owner = THIS_MODULE; 2104 2104 aux->ddc.dev.parent = aux->dev; 2105 2105 2106 - strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), 2106 + strscpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), 2107 2107 sizeof(aux->ddc.name)); 2108 2108 2109 2109 ret = drm_dp_aux_register_devnode(aux);
+1 -1
drivers/gpu/drm/display/drm_dp_mst_topology.c
··· 5702 5702 aux->ddc.dev.parent = parent_dev; 5703 5703 aux->ddc.dev.of_node = parent_dev->of_node; 5704 5704 5705 - strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(parent_dev), 5705 + strscpy(aux->ddc.name, aux->name ? aux->name : dev_name(parent_dev), 5706 5706 sizeof(aux->ddc.name)); 5707 5707 5708 5708 return i2c_add_adapter(&aux->ddc);
+1 -1
drivers/gpu/drm/drm_mipi_dsi.c
··· 223 223 224 224 device_set_node(&dsi->dev, of_fwnode_handle(info->node)); 225 225 dsi->channel = info->channel; 226 - strlcpy(dsi->name, info->type, sizeof(dsi->name)); 226 + strscpy(dsi->name, info->type, sizeof(dsi->name)); 227 227 228 228 ret = mipi_dsi_device_add(dsi); 229 229 if (ret) {
+1 -1
drivers/gpu/drm/i2c/tda998x_drv.c
··· 1951 1951 * offset. 1952 1952 */ 1953 1953 memset(&cec_info, 0, sizeof(cec_info)); 1954 - strlcpy(cec_info.type, "tda9950", sizeof(cec_info.type)); 1954 + strscpy(cec_info.type, "tda9950", sizeof(cec_info.type)); 1955 1955 cec_info.addr = priv->cec_addr; 1956 1956 cec_info.platform_data = &priv->cec_glue; 1957 1957 cec_info.irq = client->irq;
+1 -1
drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
··· 295 295 return ret; 296 296 } 297 297 298 - strlcpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name)); 298 + strscpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name)); 299 299 ddc->adap.owner = THIS_MODULE; 300 300 ddc->adap.class = I2C_CLASS_DDC; 301 301 ddc->adap.algo = &mtk_hdmi_ddc_algorithm;
+2 -2
drivers/gpu/drm/radeon/radeon_atombios.c
··· 2105 2105 const char *name = thermal_controller_names[power_info->info. 2106 2106 ucOverdriveThermalController]; 2107 2107 info.addr = power_info->info.ucOverdriveControllerAddress >> 1; 2108 - strlcpy(info.type, name, sizeof(info.type)); 2108 + strscpy(info.type, name, sizeof(info.type)); 2109 2109 i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); 2110 2110 } 2111 2111 } ··· 2355 2355 struct i2c_board_info info = { }; 2356 2356 const char *name = pp_lib_thermal_controller_names[controller->ucType]; 2357 2357 info.addr = controller->ucI2cAddress >> 1; 2358 - strlcpy(info.type, name, sizeof(info.type)); 2358 + strscpy(info.type, name, sizeof(info.type)); 2359 2359 i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); 2360 2360 } 2361 2361 } else {
+2 -2
drivers/gpu/drm/radeon/radeon_combios.c
··· 2702 2702 struct i2c_board_info info = { }; 2703 2703 const char *name = thermal_controller_names[thermal_controller]; 2704 2704 info.addr = i2c_addr >> 1; 2705 - strlcpy(info.type, name, sizeof(info.type)); 2705 + strscpy(info.type, name, sizeof(info.type)); 2706 2706 i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); 2707 2707 } 2708 2708 } ··· 2719 2719 struct i2c_board_info info = { }; 2720 2720 const char *name = "f75375"; 2721 2721 info.addr = 0x28; 2722 - strlcpy(info.type, name, sizeof(info.type)); 2722 + strscpy(info.type, name, sizeof(info.type)); 2723 2723 i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); 2724 2724 DRM_INFO("Possible %s thermal controller at 0x%02x\n", 2725 2725 name, info.addr);
+1 -1
drivers/gpu/drm/rockchip/inno_hdmi.c
··· 797 797 adap->dev.parent = hdmi->dev; 798 798 adap->dev.of_node = hdmi->dev->of_node; 799 799 adap->algo = &inno_hdmi_algorithm; 800 - strlcpy(adap->name, "Inno HDMI", sizeof(adap->name)); 800 + strscpy(adap->name, "Inno HDMI", sizeof(adap->name)); 801 801 i2c_set_adapdata(adap, hdmi); 802 802 803 803 ret = i2c_add_adapter(adap);
+1 -1
drivers/gpu/drm/rockchip/rk3066_hdmi.c
··· 730 730 adap->dev.parent = hdmi->dev; 731 731 adap->dev.of_node = hdmi->dev->of_node; 732 732 adap->algo = &rk3066_hdmi_algorithm; 733 - strlcpy(adap->name, "RK3066 HDMI", sizeof(adap->name)); 733 + strscpy(adap->name, "RK3066 HDMI", sizeof(adap->name)); 734 734 i2c_set_adapdata(adap, hdmi); 735 735 736 736 ret = i2c_add_adapter(adap);
+1 -1
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c
··· 304 304 adap->owner = THIS_MODULE; 305 305 adap->class = I2C_CLASS_DDC; 306 306 adap->algo = &sun4i_hdmi_i2c_algorithm; 307 - strlcpy(adap->name, "sun4i_hdmi_i2c adapter", sizeof(adap->name)); 307 + strscpy(adap->name, "sun4i_hdmi_i2c adapter", sizeof(adap->name)); 308 308 i2c_set_adapdata(adap, hdmi); 309 309 310 310 ret = i2c_add_adapter(adap);
+2 -2
drivers/md/raid5.c
··· 2433 2433 2434 2434 conf->active_name = 0; 2435 2435 sc = kmem_cache_create(conf->cache_name[conf->active_name], 2436 - sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), 2436 + struct_size_t(struct stripe_head, dev, devs), 2437 2437 0, 0, NULL); 2438 2438 if (!sc) 2439 2439 return 1; ··· 2559 2559 2560 2560 /* Step 1 */ 2561 2561 sc = kmem_cache_create(conf->cache_name[1-conf->active_name], 2562 - sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev), 2562 + struct_size_t(struct stripe_head, dev, newsize), 2563 2563 0, 0, NULL); 2564 2564 if (!sc) 2565 2565 return -ENOMEM;
+1 -1
drivers/md/raid5.h
··· 268 268 unsigned long flags; 269 269 u32 log_checksum; 270 270 unsigned short write_hint; 271 - } dev[1]; /* allocated with extra space depending of RAID geometry */ 271 + } dev[]; /* allocated depending of RAID geometry ("disks" member) */ 272 272 }; 273 273 274 274 /* stripe_head_state - collects and tracks the dynamic state of a stripe_head
+2 -2
drivers/misc/lkdtm/bugs.c
··· 309 309 struct array_bounds_flex_array { 310 310 int one; 311 311 int two; 312 - char data[1]; 312 + char data[]; 313 313 }; 314 314 315 315 struct array_bounds { ··· 341 341 * For the uninstrumented flex array member, also touch 1 byte 342 342 * beyond to verify it is correctly uninstrumented. 343 343 */ 344 - for (i = 0; i < sizeof(not_checked->data) + 1; i++) 344 + for (i = 0; i < 2; i++) 345 345 not_checked->data[i] = 'A'; 346 346 347 347 pr_info("Array access beyond bounds ...\n");
+4 -4
drivers/most/configfs.c
··· 204 204 { 205 205 struct mdev_link *mdev_link = to_mdev_link(item); 206 206 207 - strlcpy(mdev_link->device, page, sizeof(mdev_link->device)); 207 + strscpy(mdev_link->device, page, sizeof(mdev_link->device)); 208 208 strim(mdev_link->device); 209 209 return count; 210 210 } ··· 219 219 { 220 220 struct mdev_link *mdev_link = to_mdev_link(item); 221 221 222 - strlcpy(mdev_link->channel, page, sizeof(mdev_link->channel)); 222 + strscpy(mdev_link->channel, page, sizeof(mdev_link->channel)); 223 223 strim(mdev_link->channel); 224 224 return count; 225 225 } ··· 234 234 { 235 235 struct mdev_link *mdev_link = to_mdev_link(item); 236 236 237 - strlcpy(mdev_link->comp, page, sizeof(mdev_link->comp)); 237 + strscpy(mdev_link->comp, page, sizeof(mdev_link->comp)); 238 238 strim(mdev_link->comp); 239 239 return count; 240 240 } ··· 250 250 { 251 251 struct mdev_link *mdev_link = to_mdev_link(item); 252 252 253 - strlcpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params)); 253 + strscpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params)); 254 254 strim(mdev_link->comp_params); 255 255 return count; 256 256 }
+4 -5
drivers/net/ethernet/intel/ice/ice_ddp.h
··· 185 185 186 186 #define ICE_MAX_ENTRIES_IN_BUF(hd_sz, ent_sz) \ 187 187 ((ICE_PKG_BUF_SIZE - \ 188 - struct_size((struct ice_buf_hdr *)0, section_entry, 1) - (hd_sz)) / \ 188 + struct_size_t(struct ice_buf_hdr, section_entry, 1) - (hd_sz)) / \ 189 189 (ent_sz)) 190 190 191 191 /* ice package section IDs */ ··· 297 297 }; 298 298 299 299 #define ICE_MAX_LABELS_IN_BUF \ 300 - ICE_MAX_ENTRIES_IN_BUF(struct_size((struct ice_label_section *)0, \ 300 + ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_label_section, \ 301 301 label, 1) - \ 302 302 sizeof(struct ice_label), \ 303 303 sizeof(struct ice_label)) ··· 352 352 }; 353 353 354 354 #define ICE_MAX_BST_TCAMS_IN_BUF \ 355 - ICE_MAX_ENTRIES_IN_BUF(struct_size((struct ice_boost_tcam_section *)0, \ 355 + ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_boost_tcam_section, \ 356 356 tcam, 1) - \ 357 357 sizeof(struct ice_boost_tcam_entry), \ 358 358 sizeof(struct ice_boost_tcam_entry)) ··· 372 372 }; 373 373 374 374 #define ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF \ 375 - ICE_MAX_ENTRIES_IN_BUF( \ 376 - struct_size((struct ice_marker_ptype_tcam_section *)0, tcam, \ 375 + ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_marker_ptype_tcam_section, tcam, \ 377 376 1) - \ 378 377 sizeof(struct ice_marker_ptype_tcam_entry), \ 379 378 sizeof(struct ice_marker_ptype_tcam_entry))
+4 -4
drivers/nvme/host/fc.c
··· 2917 2917 2918 2918 ret = nvme_alloc_io_tag_set(&ctrl->ctrl, &ctrl->tag_set, 2919 2919 &nvme_fc_mq_ops, 1, 2920 - struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, 2921 - ctrl->lport->ops->fcprqst_priv_sz)); 2920 + struct_size_t(struct nvme_fcp_op_w_sgl, priv, 2921 + ctrl->lport->ops->fcprqst_priv_sz)); 2922 2922 if (ret) 2923 2923 return ret; 2924 2924 ··· 3536 3536 3537 3537 ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set, 3538 3538 &nvme_fc_admin_mq_ops, 3539 - struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, 3540 - ctrl->lport->ops->fcprqst_priv_sz)); 3539 + struct_size_t(struct nvme_fcp_op_w_sgl, priv, 3540 + ctrl->lport->ops->fcprqst_priv_sz)); 3541 3541 if (ret) 3542 3542 goto fail_ctrl; 3543 3543
+1 -1
drivers/scsi/3w-9xxx.c
··· 617 617 } 618 618 619 619 /* Load rest of compatibility struct */ 620 - strlcpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, 620 + strscpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, 621 621 sizeof(tw_dev->tw_compat_info.driver_version)); 622 622 tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; 623 623 tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
+1 -1
drivers/scsi/aacraid/aachba.c
··· 3289 3289 else 3290 3290 qd.unmapped = 0; 3291 3291 3292 - strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname, 3292 + strscpy(qd.name, fsa_dev_ptr[qd.cnum].devname, 3293 3293 min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1)); 3294 3294 3295 3295 if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
+1 -1
drivers/scsi/bnx2i/bnx2i_init.c
··· 383 383 if (!stats) 384 384 return -ENOMEM; 385 385 386 - strlcpy(stats->version, DRV_MODULE_VERSION, sizeof(stats->version)); 386 + strscpy(stats->version, DRV_MODULE_VERSION, sizeof(stats->version)); 387 387 memcpy(stats->mac_add1 + 2, hba->cnic->mac_addr, ETH_ALEN); 388 388 389 389 stats->max_frame_size = hba->netdev->mtu;
+2 -2
drivers/scsi/hptiop.c
··· 1394 1394 host->cmd_per_lun = le32_to_cpu(iop_config.max_requests); 1395 1395 host->max_cmd_len = 16; 1396 1396 1397 - req_size = struct_size((struct hpt_iop_request_scsi_command *)0, 1398 - sg_list, hba->max_sg_descriptors); 1397 + req_size = struct_size_t(struct hpt_iop_request_scsi_command, 1398 + sg_list, hba->max_sg_descriptors); 1399 1399 if ((req_size & 0x1f) != 0) 1400 1400 req_size = (req_size + 0x1f) & ~0x1f; 1401 1401
+3 -3
drivers/scsi/ibmvscsi/ibmvscsi.c
··· 250 250 251 251 ppartition_name = of_get_property(of_root, "ibm,partition-name", NULL); 252 252 if (ppartition_name) 253 - strlcpy(partition_name, ppartition_name, 253 + strscpy(partition_name, ppartition_name, 254 254 sizeof(partition_name)); 255 255 p_number_ptr = of_get_property(of_root, "ibm,partition-no", NULL); 256 256 if (p_number_ptr) ··· 1282 1282 if (hostdata->client_migrated) 1283 1283 hostdata->caps.flags |= cpu_to_be32(CLIENT_MIGRATED); 1284 1284 1285 - strlcpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev), 1285 + strscpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev), 1286 1286 sizeof(hostdata->caps.name)); 1287 1287 1288 1288 location = of_get_property(of_node, "ibm,loc-code", NULL); 1289 1289 location = location ? location : dev_name(hostdata->dev); 1290 - strlcpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc)); 1290 + strscpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc)); 1291 1291 1292 1292 req->common.type = cpu_to_be32(VIOSRP_CAPABILITIES_TYPE); 1293 1293 req->buffer = cpu_to_be64(hostdata->caps_addr);
+6 -6
drivers/scsi/megaraid/megaraid_sas_base.c
··· 5153 5153 fusion->max_map_sz = ventura_map_sz; 5154 5154 } else { 5155 5155 fusion->old_map_sz = 5156 - struct_size((struct MR_FW_RAID_MAP *)0, ldSpanMap, 5157 - instance->fw_supported_vd_count); 5156 + struct_size_t(struct MR_FW_RAID_MAP, ldSpanMap, 5157 + instance->fw_supported_vd_count); 5158 5158 fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); 5159 5159 5160 5160 fusion->max_map_sz = ··· 5789 5789 struct fusion_context *fusion = instance->ctrl_context; 5790 5790 size_t pd_seq_map_sz; 5791 5791 5792 - pd_seq_map_sz = struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0, seq, 5793 - MAX_PHYSICAL_DEVICES); 5792 + pd_seq_map_sz = struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC, seq, 5793 + MAX_PHYSICAL_DEVICES); 5794 5794 5795 5795 instance->use_seqnum_jbod_fp = 5796 5796 instance->support_seqnum_jbod_fp; ··· 8033 8033 if (instance->adapter_type != MFI_SERIES) { 8034 8034 megasas_release_fusion(instance); 8035 8035 pd_seq_map_sz = 8036 - struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0, 8037 - seq, MAX_PHYSICAL_DEVICES); 8036 + struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC, 8037 + seq, MAX_PHYSICAL_DEVICES); 8038 8038 for (i = 0; i < 2 ; i++) { 8039 8039 if (fusion->ld_map[i]) 8040 8040 dma_free_coherent(&instance->pdev->dev,
+3 -3
drivers/scsi/megaraid/megaraid_sas_fp.c
··· 326 326 else if (instance->supportmax256vd) 327 327 expected_size = sizeof(struct MR_FW_RAID_MAP_EXT); 328 328 else 329 - expected_size = struct_size((struct MR_FW_RAID_MAP *)0, 330 - ldSpanMap, 331 - le16_to_cpu(pDrvRaidMap->ldCount)); 329 + expected_size = struct_size_t(struct MR_FW_RAID_MAP, 330 + ldSpanMap, 331 + le16_to_cpu(pDrvRaidMap->ldCount)); 332 332 333 333 if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) { 334 334 dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x",
+1 -1
drivers/scsi/qedi/qedi_main.c
··· 2593 2593 sp_params.drv_minor = QEDI_DRIVER_MINOR_VER; 2594 2594 sp_params.drv_rev = QEDI_DRIVER_REV_VER; 2595 2595 sp_params.drv_eng = QEDI_DRIVER_ENG_VER; 2596 - strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); 2596 + strscpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); 2597 2597 rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params); 2598 2598 if (rc) { 2599 2599 QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n");
+1 -1
drivers/scsi/smartpqi/smartpqi_init.c
··· 5015 5015 } 5016 5016 5017 5017 #define PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH \ 5018 - struct_size((struct pqi_event_config *)0, descriptors, PQI_MAX_EVENT_DESCRIPTORS) 5018 + struct_size_t(struct pqi_event_config, descriptors, PQI_MAX_EVENT_DESCRIPTORS) 5019 5019 5020 5020 static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info, 5021 5021 bool enable_events)
+1 -1
fs/befs/btree.c
··· 500 500 goto error_alloc; 501 501 } 502 502 503 - strlcpy(keybuf, keystart, keylen + 1); 503 + strscpy(keybuf, keystart, keylen + 1); 504 504 *value = fs64_to_cpu(sb, valarray[cur_key]); 505 505 *keysize = keylen; 506 506
+1 -1
fs/befs/linuxvfs.c
··· 374 374 if (S_ISLNK(inode->i_mode) && !(befs_ino->i_flags & BEFS_LONG_SYMLINK)){ 375 375 inode->i_size = 0; 376 376 inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE; 377 - strlcpy(befs_ino->i_data.symlink, raw_inode->data.symlink, 377 + strscpy(befs_ino->i_data.symlink, raw_inode->data.symlink, 378 378 BEFS_SYMLINK_LEN); 379 379 } else { 380 380 int num_blks;
+2 -2
fs/dlm/config.c
··· 116 116 { 117 117 struct dlm_cluster *cl = config_item_to_cluster(item); 118 118 119 - strlcpy(dlm_config.ci_cluster_name, buf, 119 + strscpy(dlm_config.ci_cluster_name, buf, 120 120 sizeof(dlm_config.ci_cluster_name)); 121 - strlcpy(cl->cl_cluster_name, buf, sizeof(cl->cl_cluster_name)); 121 + strscpy(cl->cl_cluster_name, buf, sizeof(cl->cl_cluster_name)); 122 122 return len; 123 123 } 124 124
+2 -4
fs/jbd2/journal.c
··· 1491 1491 { 1492 1492 journal_t *journal; 1493 1493 sector_t blocknr; 1494 - char *p; 1495 1494 int err = 0; 1496 1495 1497 1496 blocknr = 0; ··· 1514 1515 1515 1516 journal->j_inode = inode; 1516 1517 snprintf(journal->j_devname, sizeof(journal->j_devname), 1517 - "%pg", journal->j_dev); 1518 - p = strreplace(journal->j_devname, '/', '!'); 1519 - sprintf(p, "-%lu", journal->j_inode->i_ino); 1518 + "%pg-%lu", journal->j_dev, journal->j_inode->i_ino); 1519 + strreplace(journal->j_devname, '/', '!'); 1520 1520 jbd2_stats_proc_init(journal); 1521 1521 1522 1522 return journal;
+1 -1
fs/nfs/nfsroot.c
··· 164 164 static int __init root_nfs_copy(char *dest, const char *src, 165 165 const size_t destlen) 166 166 { 167 - if (strlcpy(dest, src, destlen) > destlen) 167 + if (strscpy(dest, src, destlen) == -E2BIG) 168 168 return -1; 169 169 return 0; 170 170 }
+1 -1
fs/vboxsf/super.c
··· 176 176 } 177 177 folder_name->size = size; 178 178 folder_name->length = size - 1; 179 - strlcpy(folder_name->string.utf8, fc->source, size); 179 + strscpy(folder_name->string.utf8, fc->source, size); 180 180 err = vboxsf_map_folder(folder_name, &sbi->root); 181 181 kfree(folder_name); 182 182 if (err) {
+1 -1
fs/xfs/libxfs/xfs_btree.h
··· 301 301 static inline size_t 302 302 xfs_btree_cur_sizeof(unsigned int nlevels) 303 303 { 304 - return struct_size((struct xfs_btree_cur *)NULL, bc_levels, nlevels); 304 + return struct_size_t(struct xfs_btree_cur, bc_levels, nlevels); 305 305 } 306 306 307 307 /* cursor flags */
+1 -1
fs/xfs/scrub/btree.h
··· 60 60 static inline size_t 61 61 xchk_btree_sizeof(unsigned int nlevels) 62 62 { 63 - return struct_size((struct xchk_btree *)NULL, lastkey, nlevels - 1); 63 + return struct_size_t(struct xchk_btree, lastkey, nlevels - 1); 64 64 } 65 65 66 66 int xchk_btree(struct xfs_scrub *sc, struct xfs_btree_cur *cur,
+1 -1
include/acpi/actbl3.h
··· 86 86 struct acpi_table_slit { 87 87 struct acpi_table_header header; /* Common ACPI table header */ 88 88 u64 locality_count; 89 - u8 entry[1]; /* Real size = localities^2 */ 89 + u8 entry[]; /* Real size = localities^2 */ 90 90 }; 91 91 92 92 /*******************************************************************************
+13
include/linux/compiler_attributes.h
··· 124 124 #endif 125 125 126 126 /* 127 + * Optional: only supported since gcc >= 14 128 + * Optional: only supported since clang >= 17 129 + * 130 + * gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896 131 + * clang: https://reviews.llvm.org/D148381 132 + */ 133 + #if __has_attribute(__element_count__) 134 + # define __counted_by(member) __attribute__((__element_count__(#member))) 135 + #else 136 + # define __counted_by(member) 137 + #endif 138 + 139 + /* 127 140 * Optional: only supported since clang >= 14.0 128 141 * 129 142 * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-error-function-attribute
+112 -49
include/linux/fortify-string.h
··· 20 20 ({ \ 21 21 char *__p = (char *)(p); \ 22 22 size_t __ret = SIZE_MAX; \ 23 - size_t __p_size = __member_size(p); \ 23 + const size_t __p_size = __member_size(p); \ 24 24 if (__p_size != SIZE_MAX && \ 25 25 __builtin_constant_p(*__p)) { \ 26 26 size_t __p_len = __p_size - 1; \ ··· 142 142 __FORTIFY_INLINE __diagnose_as(__builtin_strncpy, 1, 2, 3) 143 143 char *strncpy(char * const POS p, const char *q, __kernel_size_t size) 144 144 { 145 - size_t p_size = __member_size(p); 145 + const size_t p_size = __member_size(p); 146 146 147 147 if (__compiletime_lessthan(p_size, size)) 148 148 __write_overflow(); 149 149 if (p_size < size) 150 150 fortify_panic(__func__); 151 151 return __underlying_strncpy(p, q, size); 152 - } 153 - 154 - /** 155 - * strcat - Append a string to an existing string 156 - * 157 - * @p: pointer to NUL-terminated string to append to 158 - * @q: pointer to NUL-terminated source string to append from 159 - * 160 - * Do not use this function. While FORTIFY_SOURCE tries to avoid 161 - * read and write overflows, this is only possible when the 162 - * destination buffer size is known to the compiler. Prefer 163 - * building the string with formatting, via scnprintf() or similar. 164 - * At the very least, use strncat(). 165 - * 166 - * Returns @p. 167 - * 168 - */ 169 - __FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) 170 - char *strcat(char * const POS p, const char *q) 171 - { 172 - size_t p_size = __member_size(p); 173 - 174 - if (p_size == SIZE_MAX) 175 - return __underlying_strcat(p, q); 176 - if (strlcat(p, q, p_size) >= p_size) 177 - fortify_panic(__func__); 178 - return p; 179 152 } 180 153 181 154 extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); ··· 164 191 */ 165 192 __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size_t maxlen) 166 193 { 167 - size_t p_size = __member_size(p); 168 - size_t p_len = __compiletime_strlen(p); 194 + const size_t p_size = __member_size(p); 195 + const size_t p_len = __compiletime_strlen(p); 169 196 size_t ret; 170 197 171 198 /* We can take compile-time actions when maxlen is const. */ ··· 206 233 __FORTIFY_INLINE __diagnose_as(__builtin_strlen, 1) 207 234 __kernel_size_t __fortify_strlen(const char * const POS p) 208 235 { 236 + const size_t p_size = __member_size(p); 209 237 __kernel_size_t ret; 210 - size_t p_size = __member_size(p); 211 238 212 239 /* Give up if we don't know how large p is. */ 213 240 if (p_size == SIZE_MAX) ··· 240 267 */ 241 268 __FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, size_t size) 242 269 { 243 - size_t p_size = __member_size(p); 244 - size_t q_size = __member_size(q); 270 + const size_t p_size = __member_size(p); 271 + const size_t q_size = __member_size(q); 245 272 size_t q_len; /* Full count of source string length. */ 246 273 size_t len; /* Count of characters going into destination. */ 247 274 ··· 272 299 * @q: Where to copy the string from 273 300 * @size: Size of destination buffer 274 301 * 275 - * Copy the source string @p, or as much of it as fits, into the destination 276 - * @q buffer. The behavior is undefined if the string buffers overlap. The 302 + * Copy the source string @q, or as much of it as fits, into the destination 303 + * @p buffer. The behavior is undefined if the string buffers overlap. The 277 304 * destination @p buffer is always NUL terminated, unless it's zero-sized. 278 305 * 279 306 * Preferred to strlcpy() since the API doesn't require reading memory ··· 291 318 */ 292 319 __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, size_t size) 293 320 { 294 - size_t len; 295 321 /* Use string size rather than possible enclosing struct size. */ 296 - size_t p_size = __member_size(p); 297 - size_t q_size = __member_size(q); 322 + const size_t p_size = __member_size(p); 323 + const size_t q_size = __member_size(q); 324 + size_t len; 298 325 299 326 /* If we cannot get size of p and q default to call strscpy. */ 300 327 if (p_size == SIZE_MAX && q_size == SIZE_MAX) ··· 344 371 return __real_strscpy(p, q, len); 345 372 } 346 373 374 + /* Defined after fortified strlen() to reuse it. */ 375 + extern size_t __real_strlcat(char *p, const char *q, size_t avail) __RENAME(strlcat); 376 + /** 377 + * strlcat - Append a string to an existing string 378 + * 379 + * @p: pointer to %NUL-terminated string to append to 380 + * @q: pointer to %NUL-terminated string to append from 381 + * @avail: Maximum bytes available in @p 382 + * 383 + * Appends %NUL-terminated string @q after the %NUL-terminated 384 + * string at @p, but will not write beyond @avail bytes total, 385 + * potentially truncating the copy from @q. @p will stay 386 + * %NUL-terminated only if a %NUL already existed within 387 + * the @avail bytes of @p. If so, the resulting number of 388 + * bytes copied from @q will be at most "@avail - strlen(@p) - 1". 389 + * 390 + * Do not use this function. While FORTIFY_SOURCE tries to avoid 391 + * read and write overflows, this is only possible when the sizes 392 + * of @p and @q are known to the compiler. Prefer building the 393 + * string with formatting, via scnprintf(), seq_buf, or similar. 394 + * 395 + * Returns total bytes that _would_ have been contained by @p 396 + * regardless of truncation, similar to snprintf(). If return 397 + * value is >= @avail, the string has been truncated. 398 + * 399 + */ 400 + __FORTIFY_INLINE 401 + size_t strlcat(char * const POS p, const char * const POS q, size_t avail) 402 + { 403 + const size_t p_size = __member_size(p); 404 + const size_t q_size = __member_size(q); 405 + size_t p_len, copy_len; 406 + size_t actual, wanted; 407 + 408 + /* Give up immediately if both buffer sizes are unknown. */ 409 + if (p_size == SIZE_MAX && q_size == SIZE_MAX) 410 + return __real_strlcat(p, q, avail); 411 + 412 + p_len = strnlen(p, avail); 413 + copy_len = strlen(q); 414 + wanted = actual = p_len + copy_len; 415 + 416 + /* Cannot append any more: report truncation. */ 417 + if (avail <= p_len) 418 + return wanted; 419 + 420 + /* Give up if string is already overflowed. */ 421 + if (p_size <= p_len) 422 + fortify_panic(__func__); 423 + 424 + if (actual >= avail) { 425 + copy_len = avail - p_len - 1; 426 + actual = p_len + copy_len; 427 + } 428 + 429 + /* Give up if copy will overflow. */ 430 + if (p_size <= actual) 431 + fortify_panic(__func__); 432 + __underlying_memcpy(p + p_len, q, copy_len); 433 + p[actual] = '\0'; 434 + 435 + return wanted; 436 + } 437 + 438 + /* Defined after fortified strlcat() to reuse it. */ 439 + /** 440 + * strcat - Append a string to an existing string 441 + * 442 + * @p: pointer to NUL-terminated string to append to 443 + * @q: pointer to NUL-terminated source string to append from 444 + * 445 + * Do not use this function. While FORTIFY_SOURCE tries to avoid 446 + * read and write overflows, this is only possible when the 447 + * destination buffer size is known to the compiler. Prefer 448 + * building the string with formatting, via scnprintf() or similar. 449 + * At the very least, use strncat(). 450 + * 451 + * Returns @p. 452 + * 453 + */ 454 + __FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) 455 + char *strcat(char * const POS p, const char *q) 456 + { 457 + const size_t p_size = __member_size(p); 458 + 459 + if (strlcat(p, q, p_size) >= p_size) 460 + fortify_panic(__func__); 461 + return p; 462 + } 463 + 347 464 /** 348 465 * strncat - Append a string to an existing string 349 466 * ··· 457 394 __FORTIFY_INLINE __diagnose_as(__builtin_strncat, 1, 2, 3) 458 395 char *strncat(char * const POS p, const char * const POS q, __kernel_size_t count) 459 396 { 397 + const size_t p_size = __member_size(p); 398 + const size_t q_size = __member_size(q); 460 399 size_t p_len, copy_len; 461 - size_t p_size = __member_size(p); 462 - size_t q_size = __member_size(q); 463 400 464 401 if (p_size == SIZE_MAX && q_size == SIZE_MAX) 465 402 return __underlying_strncat(p, q, count); ··· 702 639 extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan); 703 640 __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size) 704 641 { 705 - size_t p_size = __struct_size(p); 642 + const size_t p_size = __struct_size(p); 706 643 707 644 if (__compiletime_lessthan(p_size, size)) 708 645 __read_overflow(); ··· 714 651 __FORTIFY_INLINE __diagnose_as(__builtin_memcmp, 1, 2, 3) 715 652 int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t size) 716 653 { 717 - size_t p_size = __struct_size(p); 718 - size_t q_size = __struct_size(q); 654 + const size_t p_size = __struct_size(p); 655 + const size_t q_size = __struct_size(q); 719 656 720 657 if (__builtin_constant_p(size)) { 721 658 if (__compiletime_lessthan(p_size, size)) ··· 731 668 __FORTIFY_INLINE __diagnose_as(__builtin_memchr, 1, 2, 3) 732 669 void *memchr(const void * const POS0 p, int c, __kernel_size_t size) 733 670 { 734 - size_t p_size = __struct_size(p); 671 + const size_t p_size = __struct_size(p); 735 672 736 673 if (__compiletime_lessthan(p_size, size)) 737 674 __read_overflow(); ··· 743 680 void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv); 744 681 __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size) 745 682 { 746 - size_t p_size = __struct_size(p); 683 + const size_t p_size = __struct_size(p); 747 684 748 685 if (__compiletime_lessthan(p_size, size)) 749 686 __read_overflow(); ··· 756 693 __realloc_size(2); 757 694 __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp) 758 695 { 759 - size_t p_size = __struct_size(p); 696 + const size_t p_size = __struct_size(p); 760 697 761 698 if (__compiletime_lessthan(p_size, size)) 762 699 __read_overflow(); ··· 783 720 __FORTIFY_INLINE __diagnose_as(__builtin_strcpy, 1, 2) 784 721 char *strcpy(char * const POS p, const char * const POS q) 785 722 { 786 - size_t p_size = __member_size(p); 787 - size_t q_size = __member_size(q); 723 + const size_t p_size = __member_size(p); 724 + const size_t q_size = __member_size(q); 788 725 size_t size; 789 726 790 727 /* If neither buffer size is known, immediately give up. */
+17 -1
include/linux/overflow.h
··· 283 283 * @member: Name of the array member. 284 284 * @count: Number of elements in the array. 285 285 * 286 - * Calculates size of memory needed for structure @p followed by an 286 + * Calculates size of memory needed for structure of @p followed by an 287 287 * array of @count number of @member elements. 288 288 * 289 289 * Return: number of bytes needed or SIZE_MAX on overflow. ··· 292 292 __builtin_choose_expr(__is_constexpr(count), \ 293 293 sizeof(*(p)) + flex_array_size(p, member, count), \ 294 294 size_add(sizeof(*(p)), flex_array_size(p, member, count))) 295 + 296 + /** 297 + * struct_size_t() - Calculate size of structure with trailing flexible array 298 + * @type: structure type name. 299 + * @member: Name of the array member. 300 + * @count: Number of elements in the array. 301 + * 302 + * Calculates size of memory needed for structure @type followed by an 303 + * array of @count number of @member elements. Prefer using struct_size() 304 + * when possible instead, to keep calculations associated with a specific 305 + * instance variable of type @type. 306 + * 307 + * Return: number of bytes needed or SIZE_MAX on overflow. 308 + */ 309 + #define struct_size_t(type, member, count) \ 310 + struct_size((type *)NULL, member, count) 295 311 296 312 #endif /* __LINUX_OVERFLOW_H */
+1 -1
include/linux/string.h
··· 169 169 #endif 170 170 171 171 void *memchr_inv(const void *s, int c, size_t n); 172 - char *strreplace(char *s, char old, char new); 172 + char *strreplace(char *str, char old, char new); 173 173 174 174 extern void kfree_const(const void *x); 175 175
+1 -1
include/uapi/linux/auto_dev-ioctl.h
··· 109 109 struct args_ismountpoint ismountpoint; 110 110 }; 111 111 112 - char path[0]; 112 + char path[]; 113 113 }; 114 114 115 115 static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in)
+2 -2
kernel/kallsyms.c
··· 716 716 { 717 717 int ret; 718 718 719 - strlcpy(iter->module_name, "bpf", MODULE_NAME_LEN); 719 + strscpy(iter->module_name, "bpf", MODULE_NAME_LEN); 720 720 iter->exported = 0; 721 721 ret = bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end, 722 722 &iter->value, &iter->type, ··· 736 736 */ 737 737 static int get_ksymbol_kprobe(struct kallsym_iter *iter) 738 738 { 739 - strlcpy(iter->module_name, "__builtin__kprobes", MODULE_NAME_LEN); 739 + strscpy(iter->module_name, "__builtin__kprobes", MODULE_NAME_LEN); 740 740 iter->exported = 0; 741 741 return kprobe_get_kallsym(iter->pos - iter->pos_bpf_end, 742 742 &iter->value, &iter->type,
+1 -1
kernel/params.c
··· 847 847 name_len = 0; 848 848 } else { 849 849 name_len = dot - kp->name + 1; 850 - strlcpy(modname, kp->name, name_len); 850 + strscpy(modname, kp->name, name_len); 851 851 } 852 852 kernel_add_sysfs_param(modname, kp, name_len); 853 853 }
+1 -1
kernel/time/clocksource.c
··· 1480 1480 { 1481 1481 mutex_lock(&clocksource_mutex); 1482 1482 if (str) 1483 - strlcpy(override_name, str, sizeof(override_name)); 1483 + strscpy(override_name, str, sizeof(override_name)); 1484 1484 mutex_unlock(&clocksource_mutex); 1485 1485 return 1; 1486 1486 }
+9 -9
kernel/trace/ftrace.c
··· 5743 5743 static int __init set_ftrace_notrace(char *str) 5744 5744 { 5745 5745 ftrace_filter_param = true; 5746 - strlcpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); 5746 + strscpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); 5747 5747 return 1; 5748 5748 } 5749 5749 __setup("ftrace_notrace=", set_ftrace_notrace); ··· 5751 5751 static int __init set_ftrace_filter(char *str) 5752 5752 { 5753 5753 ftrace_filter_param = true; 5754 - strlcpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); 5754 + strscpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); 5755 5755 return 1; 5756 5756 } 5757 5757 __setup("ftrace_filter=", set_ftrace_filter); ··· 5763 5763 5764 5764 static int __init set_graph_function(char *str) 5765 5765 { 5766 - strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); 5766 + strscpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); 5767 5767 return 1; 5768 5768 } 5769 5769 __setup("ftrace_graph_filter=", set_graph_function); 5770 5770 5771 5771 static int __init set_graph_notrace_function(char *str) 5772 5772 { 5773 - strlcpy(ftrace_graph_notrace_buf, str, FTRACE_FILTER_SIZE); 5773 + strscpy(ftrace_graph_notrace_buf, str, FTRACE_FILTER_SIZE); 5774 5774 return 1; 5775 5775 } 5776 5776 __setup("ftrace_graph_notrace=", set_graph_notrace_function); ··· 6569 6569 continue; 6570 6570 *value = op->trampoline; 6571 6571 *type = 't'; 6572 - strlcpy(name, FTRACE_TRAMPOLINE_SYM, KSYM_NAME_LEN); 6573 - strlcpy(module_name, FTRACE_TRAMPOLINE_MOD, MODULE_NAME_LEN); 6572 + strscpy(name, FTRACE_TRAMPOLINE_SYM, KSYM_NAME_LEN); 6573 + strscpy(module_name, FTRACE_TRAMPOLINE_MOD, MODULE_NAME_LEN); 6574 6574 *exported = 0; 6575 6575 return 0; 6576 6576 } ··· 6933 6933 if (off) 6934 6934 *off = addr - found_func->ip; 6935 6935 if (sym) 6936 - strlcpy(sym, found_func->name, KSYM_NAME_LEN); 6936 + strscpy(sym, found_func->name, KSYM_NAME_LEN); 6937 6937 6938 6938 return found_func->name; 6939 6939 } ··· 6987 6987 6988 6988 *value = mod_func->ip; 6989 6989 *type = 'T'; 6990 - strlcpy(name, mod_func->name, KSYM_NAME_LEN); 6991 - strlcpy(module_name, mod_map->mod->name, MODULE_NAME_LEN); 6990 + strscpy(name, mod_func->name, KSYM_NAME_LEN); 6991 + strscpy(module_name, mod_map->mod->name, MODULE_NAME_LEN); 6992 6992 *exported = 1; 6993 6993 preempt_enable(); 6994 6994 return 0;
+4 -4
kernel/trace/trace.c
··· 199 199 200 200 static int __init set_cmdline_ftrace(char *str) 201 201 { 202 - strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); 202 + strscpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); 203 203 default_bootup_tracer = bootup_tracer_buf; 204 204 /* We are using ftrace early, expand it */ 205 205 ring_buffer_expanded = true; ··· 284 284 285 285 static int __init set_trace_boot_options(char *str) 286 286 { 287 - strlcpy(trace_boot_options_buf, str, MAX_TRACER_SIZE); 287 + strscpy(trace_boot_options_buf, str, MAX_TRACER_SIZE); 288 288 return 1; 289 289 } 290 290 __setup("trace_options=", set_trace_boot_options); ··· 294 294 295 295 static int __init set_trace_boot_clock(char *str) 296 296 { 297 - strlcpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE); 297 + strscpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE); 298 298 trace_boot_clock = trace_boot_clock_buf; 299 299 return 1; 300 300 } ··· 2546 2546 if (map != NO_CMDLINE_MAP) { 2547 2547 tpid = savedcmd->map_cmdline_to_pid[map]; 2548 2548 if (tpid == pid) { 2549 - strlcpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN); 2549 + strscpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN); 2550 2550 return; 2551 2551 } 2552 2552 }
+2 -2
kernel/trace/trace_events.c
··· 2833 2833 char *buf; 2834 2834 int i; 2835 2835 2836 - strlcpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE); 2836 + strscpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE); 2837 2837 ring_buffer_expanded = true; 2838 2838 disable_tracing_selftest("running event triggers"); 2839 2839 ··· 3623 3623 3624 3624 static __init int setup_trace_event(char *str) 3625 3625 { 3626 - strlcpy(bootup_event_buf, str, COMMAND_LINE_SIZE); 3626 + strscpy(bootup_event_buf, str, COMMAND_LINE_SIZE); 3627 3627 ring_buffer_expanded = true; 3628 3628 disable_tracing_selftest("running event tracing"); 3629 3629
+2 -2
kernel/trace/trace_events_inject.c
··· 217 217 char *addr = (char *)(unsigned long) val; 218 218 219 219 if (field->filter_type == FILTER_STATIC_STRING) { 220 - strlcpy(entry + field->offset, addr, field->size); 220 + strscpy(entry + field->offset, addr, field->size); 221 221 } else if (field->filter_type == FILTER_DYN_STRING || 222 222 field->filter_type == FILTER_RDYN_STRING) { 223 223 int str_len = strlen(addr) + 1; ··· 232 232 } 233 233 entry = *pentry; 234 234 235 - strlcpy(entry + (entry_size - str_len), addr, str_len); 235 + strscpy(entry + (entry_size - str_len), addr, str_len); 236 236 str_item = (u32 *)(entry + field->offset); 237 237 if (field->filter_type == FILTER_RDYN_STRING) 238 238 str_loc -= field->offset + field->size;
+1 -1
kernel/trace/trace_kprobe.c
··· 30 30 31 31 static int __init set_kprobe_boot_events(char *str) 32 32 { 33 - strlcpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE); 33 + strscpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE); 34 34 disable_tracing_selftest("running kprobe events"); 35 35 36 36 return 1;
+1 -1
kernel/trace/trace_probe.c
··· 254 254 trace_probe_log_err(offset, GROUP_TOO_LONG); 255 255 return -EINVAL; 256 256 } 257 - strlcpy(buf, event, slash - event + 1); 257 + strscpy(buf, event, slash - event + 1); 258 258 if (!is_good_system_name(buf)) { 259 259 trace_probe_log_err(offset, BAD_GROUP_NAME); 260 260 return -EINVAL;
+6 -1
lib/Kconfig.debug
··· 2675 2675 2676 2676 config FORTIFY_KUNIT_TEST 2677 2677 tristate "Test fortified str*() and mem*() function internals at runtime" if !KUNIT_ALL_TESTS 2678 - depends on KUNIT && FORTIFY_SOURCE 2678 + depends on KUNIT 2679 2679 default KUNIT_ALL_TESTS 2680 2680 help 2681 2681 Builds unit tests for checking internals of FORTIFY_SOURCE as used ··· 2691 2691 Tests for hw_breakpoint constraints accounting. 2692 2692 2693 2693 If unsure, say N. 2694 + 2695 + config STRCAT_KUNIT_TEST 2696 + tristate "Test strcat() family of functions at runtime" if !KUNIT_ALL_TESTS 2697 + depends on KUNIT 2698 + default KUNIT_ALL_TESTS 2694 2699 2695 2700 config STRSCPY_KUNIT_TEST 2696 2701 tristate "Test strscpy*() family of functions at runtime" if !KUNIT_ALL_TESTS
+30 -25
lib/Kconfig.ubsan
··· 15 15 config UBSAN_TRAP 16 16 bool "On Sanitizer warnings, abort the running kernel code" 17 17 depends on !COMPILE_TEST 18 - depends on $(cc-option, -fsanitize-undefined-trap-on-error) 19 18 help 20 19 Building kernels with Sanitizer features enabled tends to grow 21 20 the kernel size by around 5%, due to adding all the debugging ··· 26 27 the system. For some system builders this is an acceptable 27 28 trade-off. 28 29 29 - config CC_HAS_UBSAN_BOUNDS 30 - def_bool $(cc-option,-fsanitize=bounds) 30 + config CC_HAS_UBSAN_BOUNDS_STRICT 31 + def_bool $(cc-option,-fsanitize=bounds-strict) 32 + help 33 + The -fsanitize=bounds-strict option is only available on GCC, 34 + but uses the more strict handling of arrays that includes knowledge 35 + of flexible arrays, which is comparable to Clang's regular 36 + -fsanitize=bounds. 31 37 32 38 config CC_HAS_UBSAN_ARRAY_BOUNDS 33 39 def_bool $(cc-option,-fsanitize=array-bounds) 40 + help 41 + Under Clang, the -fsanitize=bounds option is actually composed 42 + of two more specific options, -fsanitize=array-bounds and 43 + -fsanitize=local-bounds. However, -fsanitize=local-bounds can 44 + only be used when trap mode is enabled. (See also the help for 45 + CONFIG_LOCAL_BOUNDS.) Explicitly check for -fsanitize=array-bounds 46 + so that we can build up the options needed for UBSAN_BOUNDS 47 + with or without UBSAN_TRAP. 34 48 35 49 config UBSAN_BOUNDS 36 50 bool "Perform array index bounds checking" 37 51 default UBSAN 38 - depends on CC_HAS_UBSAN_ARRAY_BOUNDS || CC_HAS_UBSAN_BOUNDS 52 + depends on CC_HAS_UBSAN_ARRAY_BOUNDS || CC_HAS_UBSAN_BOUNDS_STRICT 39 53 help 40 54 This option enables detection of directly indexed out of bounds 41 55 array accesses, where the array size is known at compile time. ··· 56 44 to the {str,mem}*cpy() family of functions (that is addressed 57 45 by CONFIG_FORTIFY_SOURCE). 58 46 59 - config UBSAN_ONLY_BOUNDS 60 - def_bool CC_HAS_UBSAN_BOUNDS && !CC_HAS_UBSAN_ARRAY_BOUNDS 61 - depends on UBSAN_BOUNDS 47 + config UBSAN_BOUNDS_STRICT 48 + def_bool UBSAN_BOUNDS && CC_HAS_UBSAN_BOUNDS_STRICT 62 49 help 63 - This is a weird case: Clang's -fsanitize=bounds includes 64 - -fsanitize=local-bounds, but it's trapping-only, so for 65 - Clang, we must use -fsanitize=array-bounds when we want 66 - traditional array bounds checking enabled. For GCC, we 67 - want -fsanitize=bounds. 50 + GCC's bounds sanitizer. This option is used to select the 51 + correct options in Makefile.ubsan. 68 52 69 53 config UBSAN_ARRAY_BOUNDS 70 - def_bool CC_HAS_UBSAN_ARRAY_BOUNDS 71 - depends on UBSAN_BOUNDS 54 + def_bool UBSAN_BOUNDS && CC_HAS_UBSAN_ARRAY_BOUNDS 55 + help 56 + Clang's array bounds sanitizer. This option is used to select 57 + the correct options in Makefile.ubsan. 72 58 73 59 config UBSAN_LOCAL_BOUNDS 74 - bool "Perform array local bounds checking" 75 - depends on UBSAN_TRAP 76 - depends on $(cc-option,-fsanitize=local-bounds) 60 + def_bool UBSAN_ARRAY_BOUNDS && UBSAN_TRAP 77 61 help 78 - This option enables -fsanitize=local-bounds which traps when an 79 - exception/error is detected. Therefore, it may only be enabled 80 - with CONFIG_UBSAN_TRAP. 81 - 82 - Enabling this option detects errors due to accesses through a 83 - pointer that is derived from an object of a statically-known size, 84 - where an added offset (which may not be known statically) is 85 - out-of-bounds. 62 + This option enables Clang's -fsanitize=local-bounds which traps 63 + when an access through a pointer that is derived from an object 64 + of a statically-known size, where an added offset (which may not 65 + be known statically) is out-of-bounds. Since this option is 66 + trap-only, it depends on CONFIG_UBSAN_TRAP. 86 67 87 68 config UBSAN_SHIFT 88 69 bool "Perform checking for bit-shift overflows"
+1
lib/Makefile
··· 393 393 CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced) 394 394 CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN) 395 395 obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o 396 + obj-$(CONFIG_STRCAT_KUNIT_TEST) += strcat_kunit.o 396 397 obj-$(CONFIG_STRSCPY_KUNIT_TEST) += strscpy_kunit.o 397 398 obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o 398 399
+14
lib/fortify_kunit.c
··· 25 25 static const char *ptr_of_11 = "this is 11!"; 26 26 static char array_unknown[] = "compiler thinks I might change"; 27 27 28 + /* Handle being built without CONFIG_FORTIFY_SOURCE */ 29 + #ifndef __compiletime_strlen 30 + # define __compiletime_strlen __builtin_strlen 31 + #endif 32 + 28 33 static void known_sizes_test(struct kunit *test) 29 34 { 30 35 KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888"), 8); ··· 312 307 } while (0) 313 308 DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc) 314 309 310 + static int fortify_test_init(struct kunit *test) 311 + { 312 + if (!IS_ENABLED(CONFIG_FORTIFY_SOURCE)) 313 + kunit_skip(test, "Not built with CONFIG_FORTIFY_SOURCE=y"); 314 + 315 + return 0; 316 + } 317 + 315 318 static struct kunit_case fortify_test_cases[] = { 316 319 KUNIT_CASE(known_sizes_test), 317 320 KUNIT_CASE(control_flow_split_test), ··· 336 323 337 324 static struct kunit_suite fortify_test_suite = { 338 325 .name = "fortify", 326 + .init = fortify_test_init, 339 327 .test_cases = fortify_test_cases, 340 328 }; 341 329
+1 -2
lib/kobject.c
··· 281 281 kfree_const(s); 282 282 if (!t) 283 283 return -ENOMEM; 284 - strreplace(t, '/', '!'); 285 - s = t; 284 + s = strreplace(t, '/', '!'); 286 285 } 287 286 kfree_const(kobj->name); 288 287 kobj->name = s;
+1 -1
lib/overflow_kunit.c
··· 649 649 static void overflow_size_helpers_test(struct kunit *test) 650 650 { 651 651 /* Make sure struct_size() can be used in a constant expression. */ 652 - u8 ce_array[struct_size((struct __test_flex_array *)0, data, 55)]; 652 + u8 ce_array[struct_size_t(struct __test_flex_array, data, 55)]; 653 653 struct __test_flex_array *obj; 654 654 int count = 0; 655 655 int var;
+104
lib/strcat_kunit.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Kernel module for testing 'strcat' family of functions. 4 + */ 5 + 6 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 + 8 + #include <kunit/test.h> 9 + #include <linux/string.h> 10 + 11 + static volatile int unconst; 12 + 13 + static void strcat_test(struct kunit *test) 14 + { 15 + char dest[8]; 16 + 17 + /* Destination is terminated. */ 18 + memset(dest, 0, sizeof(dest)); 19 + KUNIT_EXPECT_EQ(test, strlen(dest), 0); 20 + /* Empty copy does nothing. */ 21 + KUNIT_EXPECT_TRUE(test, strcat(dest, "") == dest); 22 + KUNIT_EXPECT_STREQ(test, dest, ""); 23 + /* 4 characters copied in, stops at %NUL. */ 24 + KUNIT_EXPECT_TRUE(test, strcat(dest, "four\000123") == dest); 25 + KUNIT_EXPECT_STREQ(test, dest, "four"); 26 + KUNIT_EXPECT_EQ(test, dest[5], '\0'); 27 + /* 2 more characters copied in okay. */ 28 + KUNIT_EXPECT_TRUE(test, strcat(dest, "AB") == dest); 29 + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); 30 + } 31 + 32 + static void strncat_test(struct kunit *test) 33 + { 34 + char dest[8]; 35 + 36 + /* Destination is terminated. */ 37 + memset(dest, 0, sizeof(dest)); 38 + KUNIT_EXPECT_EQ(test, strlen(dest), 0); 39 + /* Empty copy of size 0 does nothing. */ 40 + KUNIT_EXPECT_TRUE(test, strncat(dest, "", 0 + unconst) == dest); 41 + KUNIT_EXPECT_STREQ(test, dest, ""); 42 + /* Empty copy of size 1 does nothing too. */ 43 + KUNIT_EXPECT_TRUE(test, strncat(dest, "", 1 + unconst) == dest); 44 + KUNIT_EXPECT_STREQ(test, dest, ""); 45 + /* Copy of max 0 characters should do nothing. */ 46 + KUNIT_EXPECT_TRUE(test, strncat(dest, "asdf", 0 + unconst) == dest); 47 + KUNIT_EXPECT_STREQ(test, dest, ""); 48 + 49 + /* 4 characters copied in, even if max is 8. */ 50 + KUNIT_EXPECT_TRUE(test, strncat(dest, "four\000123", 8 + unconst) == dest); 51 + KUNIT_EXPECT_STREQ(test, dest, "four"); 52 + KUNIT_EXPECT_EQ(test, dest[5], '\0'); 53 + KUNIT_EXPECT_EQ(test, dest[6], '\0'); 54 + /* 2 characters copied in okay, 2 ignored. */ 55 + KUNIT_EXPECT_TRUE(test, strncat(dest, "ABCD", 2 + unconst) == dest); 56 + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); 57 + } 58 + 59 + static void strlcat_test(struct kunit *test) 60 + { 61 + char dest[8] = ""; 62 + int len = sizeof(dest) + unconst; 63 + 64 + /* Destination is terminated. */ 65 + KUNIT_EXPECT_EQ(test, strlen(dest), 0); 66 + /* Empty copy is size 0. */ 67 + KUNIT_EXPECT_EQ(test, strlcat(dest, "", len), 0); 68 + KUNIT_EXPECT_STREQ(test, dest, ""); 69 + /* Size 1 should keep buffer terminated, report size of source only. */ 70 + KUNIT_EXPECT_EQ(test, strlcat(dest, "four", 1 + unconst), 4); 71 + KUNIT_EXPECT_STREQ(test, dest, ""); 72 + 73 + /* 4 characters copied in. */ 74 + KUNIT_EXPECT_EQ(test, strlcat(dest, "four", len), 4); 75 + KUNIT_EXPECT_STREQ(test, dest, "four"); 76 + /* 2 characters copied in okay, gets to 6 total. */ 77 + KUNIT_EXPECT_EQ(test, strlcat(dest, "AB", len), 6); 78 + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); 79 + /* 2 characters ignored if max size (7) reached. */ 80 + KUNIT_EXPECT_EQ(test, strlcat(dest, "CD", 7 + unconst), 8); 81 + KUNIT_EXPECT_STREQ(test, dest, "fourAB"); 82 + /* 1 of 2 characters skipped, now at true max size. */ 83 + KUNIT_EXPECT_EQ(test, strlcat(dest, "EFG", len), 9); 84 + KUNIT_EXPECT_STREQ(test, dest, "fourABE"); 85 + /* Everything else ignored, now at full size. */ 86 + KUNIT_EXPECT_EQ(test, strlcat(dest, "1234", len), 11); 87 + KUNIT_EXPECT_STREQ(test, dest, "fourABE"); 88 + } 89 + 90 + static struct kunit_case strcat_test_cases[] = { 91 + KUNIT_CASE(strcat_test), 92 + KUNIT_CASE(strncat_test), 93 + KUNIT_CASE(strlcat_test), 94 + {} 95 + }; 96 + 97 + static struct kunit_suite strcat_test_suite = { 98 + .name = "strcat", 99 + .test_cases = strcat_test_cases, 100 + }; 101 + 102 + kunit_test_suite(strcat_test_suite); 103 + 104 + MODULE_LICENSE("GPL");
+2 -2
lib/string.c
··· 110 110 111 111 if (size) { 112 112 size_t len = (ret >= size) ? size - 1 : ret; 113 - memcpy(dest, src, len); 113 + __builtin_memcpy(dest, src, len); 114 114 dest[len] = '\0'; 115 115 } 116 116 return ret; ··· 260 260 count -= dsize; 261 261 if (len >= count) 262 262 len = count-1; 263 - memcpy(dest, src, len); 263 + __builtin_memcpy(dest, src, len); 264 264 dest[len] = 0; 265 265 return res; 266 266 }
+8 -4
lib/string_helpers.c
··· 979 979 980 980 /** 981 981 * strreplace - Replace all occurrences of character in string. 982 - * @s: The string to operate on. 982 + * @str: The string to operate on. 983 983 * @old: The character being replaced. 984 984 * @new: The character @old is replaced with. 985 985 * 986 - * Returns pointer to the nul byte at the end of @s. 986 + * Replaces the each @old character with a @new one in the given string @str. 987 + * 988 + * Return: pointer to the string @str itself. 987 989 */ 988 - char *strreplace(char *s, char old, char new) 990 + char *strreplace(char *str, char old, char new) 989 991 { 992 + char *s = str; 993 + 990 994 for (; *s; ++s) 991 995 if (*s == old) 992 996 *s = new; 993 - return s; 997 + return str; 994 998 } 995 999 EXPORT_SYMBOL(strreplace); 996 1000
-3
lib/ubsan.c
··· 425 425 426 426 void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, 427 427 unsigned long align, 428 - unsigned long offset); 429 - void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, 430 - unsigned long align, 431 428 unsigned long offset) 432 429 { 433 430 struct alignment_assumption_data *data = _data;
+11
lib/ubsan.h
··· 124 124 typedef u64 u_max; 125 125 #endif 126 126 127 + void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs); 128 + void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr); 129 + void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr); 130 + void __ubsan_handle_out_of_bounds(void *_data, void *index); 131 + void __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs); 132 + void __ubsan_handle_builtin_unreachable(void *_data); 133 + void __ubsan_handle_load_invalid_value(void *_data, void *val); 134 + void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, 135 + unsigned long align, 136 + unsigned long offset); 137 + 127 138 #endif
+5 -5
net/netfilter/ipset/ip_set_hash_netiface.c
··· 40 40 #define IP_SET_HASH_WITH_MULTI 41 41 #define IP_SET_HASH_WITH_NET0 42 42 43 - #define STRLCPY(a, b) strlcpy(a, b, IFNAMSIZ) 43 + #define STRSCPY(a, b) strscpy(a, b, IFNAMSIZ) 44 44 45 45 /* IPv4 variant */ 46 46 ··· 182 182 183 183 if (!eiface) 184 184 return -EINVAL; 185 - STRLCPY(e.iface, eiface); 185 + STRSCPY(e.iface, eiface); 186 186 e.physdev = 1; 187 187 #endif 188 188 } else { 189 - STRLCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); 189 + STRSCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); 190 190 } 191 191 192 192 if (strlen(e.iface) == 0) ··· 400 400 401 401 if (!eiface) 402 402 return -EINVAL; 403 - STRLCPY(e.iface, eiface); 403 + STRSCPY(e.iface, eiface); 404 404 e.physdev = 1; 405 405 #endif 406 406 } else { 407 - STRLCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); 407 + STRSCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out)); 408 408 } 409 409 410 410 if (strlen(e.iface) == 0)
+1 -1
scripts/Makefile.ubsan
··· 2 2 3 3 # Enable available and selected UBSAN features. 4 4 ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += -fsanitize=alignment 5 - ubsan-cflags-$(CONFIG_UBSAN_ONLY_BOUNDS) += -fsanitize=bounds 5 + ubsan-cflags-$(CONFIG_UBSAN_BOUNDS_STRICT) += -fsanitize=bounds-strict 6 6 ubsan-cflags-$(CONFIG_UBSAN_ARRAY_BOUNDS) += -fsanitize=array-bounds 7 7 ubsan-cflags-$(CONFIG_UBSAN_LOCAL_BOUNDS) += -fsanitize=local-bounds 8 8 ubsan-cflags-$(CONFIG_UBSAN_SHIFT) += -fsanitize=shift
+23 -1
scripts/checkpatch.pl
··· 6997 6997 # } 6998 6998 # } 6999 6999 7000 + # strcpy uses that should likely be strscpy 7001 + if ($line =~ /\bstrcpy\s*\(/) { 7002 + WARN("STRCPY", 7003 + "Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr); 7004 + } 7005 + 7000 7006 # strlcpy uses that should likely be strscpy 7001 7007 if ($line =~ /\bstrlcpy\s*\(/) { 7002 7008 WARN("STRLCPY", 7003 - "Prefer strscpy over strlcpy - see: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw\@mail.gmail.com/\n" . $herecurr); 7009 + "Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr); 7010 + } 7011 + 7012 + # strncpy uses that should likely be strscpy or strscpy_pad 7013 + if ($line =~ /\bstrncpy\s*\(/) { 7014 + WARN("STRNCPY", 7015 + "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr); 7004 7016 } 7005 7017 7006 7018 # typecasts on min/max could be min_t/max_t ··· 7427 7415 "return sysfs_emit(...) formats should include a terminating newline\n" . $herecurr) && 7428 7416 $fix) { 7429 7417 substr($fixed[$fixlinenr], $offset, 0) = '\\n'; 7418 + } 7419 + } 7420 + 7421 + # check for array definition/declarations that should use flexible arrays instead 7422 + if ($sline =~ /^[\+ ]\s*\}(?:\s*__packed)?\s*;\s*$/ && 7423 + $prevline =~ /^\+\s*(?:\}(?:\s*__packed\s*)?|$Type)\s*$Ident\s*\[\s*(0|1)\s*\]\s*;\s*$/) { 7424 + if (ERROR("FLEXIBLE_ARRAY", 7425 + "Use C99 flexible arrays - see https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays\n" . $hereprev) && 7426 + $1 == '0' && $fix) { 7427 + $fixed[$fixlinenr - 1] =~ s/\[\s*0\s*\]/[]/; 7430 7428 } 7431 7429 } 7432 7430
+2
tools/testing/kunit/configs/all_tests.config
··· 9 9 CONFIG_KUNIT_EXAMPLE_TEST=y 10 10 CONFIG_KUNIT_ALL_TESTS=y 11 11 12 + CONFIG_FORTIFY_SOURCE=y 13 + 12 14 CONFIG_IIO=y 13 15 14 16 CONFIG_EXT4_FS=y
+3
tools/testing/kunit/configs/arch_uml.config
··· 3 3 # Enable virtio/pci, as a lot of tests require it. 4 4 CONFIG_VIRTIO_UML=y 5 5 CONFIG_UML_PCI_OVER_VIRTIO=y 6 + 7 + # Enable FORTIFY_SOURCE for wider checking. 8 + CONFIG_FORTIFY_SOURCE=y