overflow updates for v5.16-rc1
The end goal of the current buffer overflow detection work[0] is to gain full compile-time and run-time coverage of all detectable buffer overflows seen via array indexing or memcpy(), memmove(), and memset(). The str*() family of functions already have full coverage. While much of the work for these changes have been on-going for many releases (i.e. 0-element and 1-element array replacements, as well as avoiding false positives and fixing discovered overflows[1]), this series contains the foundational elements of several related buffer overflow detection improvements by providing new common helpers and FORTIFY_SOURCE changes needed to gain the introspection required for compiler visibility into array sizes. Also included are a handful of already Acked instances using the helpers (or related clean-ups), with many more waiting at the ready to be taken via subsystem-specific trees[2]. The new helpers are: - struct_group() for gaining struct member range introspection. - memset_after() and memset_startat() for clearing to the end of structures. - DECLARE_FLEX_ARRAY() for using flex arrays in unions or alone in structs. Also included is the beginning of the refactoring of FORTIFY_SOURCE to support memcpy() introspection, fix missing and regressed coverage under GCC, and to prepare to fix the currently broken Clang support. Finishing this work is part of the larger series[0], but depends on all the false positives and buffer overflow bug fixes to have landed already and those that depend on this series to land. As part of the FORTIFY_SOURCE refactoring, a set of both a compile-time and run-time tests are added for FORTIFY_SOURCE and the mem*()-family functions respectively. The compile time tests have found a legitimate (though corner-case) bug[6] already. Please note that the appearance of "panic" and "BUG" in the FORTIFY_SOURCE refactoring are the result of relocating existing code, and no new use of those code-paths are expected nor desired. Finally, there are two tree-wide conversions for 0-element arrays and flexible array unions to gain sane compiler introspection coverage that result in no known object code differences. After this series (and the changes that have now landed via netdev and usb), we are very close to finally being able to build with -Warray-bounds and -Wzero-length-bounds. However, due corner cases in GCC[3] and Clang[4], I have not included the last two patches that turn on these options, as I don't want to introduce any known warnings to the build. Hopefully these can be solved soon. [0] https://lore.kernel.org/lkml/20210818060533.3569517-1-keescook@chromium.org/ [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=grep&q=FORTIFY_SOURCE [2] https://lore.kernel.org/lkml/202108220107.3E26FE6C9C@keescook/ [3] https://lore.kernel.org/lkml/3ab153ec-2798-da4c-f7b1-81b0ac8b0c5b@roeck-us.net/ [4] https://bugs.llvm.org/show_bug.cgi?id=51682 [5] https://lore.kernel.org/lkml/202109051257.29B29745C0@keescook/ [6] https://lore.kernel.org/lkml/20211020200039.170424-1-keescook@chromium.org/ -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAmGAFWcWHGtlZXNjb29r QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJmKFD/45MJdnvW5MhIEeW5tc5UjfcIPS ae+YvlEX/2ZwgSlTxocFVocE6hz7b6eCiX3dSAChPkPxsSfgeiuhjxsU+4ROnELR 04RqTA/rwT6JXfJcXbDPXfxDL4huUkgktAW3m1sT771AZspeap2GrSwFyttlTqKA +kTiZ3lXJVFcw10uyhfp3Lk6eFJxdf5iOjuEou5kBOQfpNKEOduRL2K15hSowOwB lARiAC+HbmN+E+npvDE7YqK4V7ZQ0/dtB0BlfqgTkn1spQz8N21kBAMpegV5vvIk A+qGHc7q2oyk4M14TRTidQHGQ4juW1Kkvq3NV6KzwQIVD+mIfz0ESn3d4tnp28Hk Y+OXTI1BRFlApQU9qGWv33gkNEozeyqMLDRLKhDYRSFPA9UKkpgXQRzeTzoLKyrQ 4B6n5NnUGcu7I6WWhpyZQcZLDsHGyy0vHzjQGs/NXtb1PzXJ5XIGuPdmx9pVMykk IVKnqRcWyGWahfh3asOnoXvdhi1No4NSHQ/ZHfUM+SrIGYjBMaUisw66qm3Fe8ZU lbO2CFkCsfGSoKNPHf0lUEGlkyxAiDolazOfflDNxdzzlZo2X1l/a7O/yoO4Pqul cdL0eDjiNoQ2YR2TSYPnXq5KSL1RI0tlfS8pH8k1hVhZsQx0wpAQ+qki0S+fLePV PdA9XB82G2tmqKc9cQ== =9xbT -----END PGP SIGNATURE----- Merge tag 'overflow-v5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux Pull overflow updates from Kees Cook: "The end goal of the current buffer overflow detection work[0] is to gain full compile-time and run-time coverage of all detectable buffer overflows seen via array indexing or memcpy(), memmove(), and memset(). The str*() family of functions already have full coverage. While much of the work for these changes have been on-going for many releases (i.e. 0-element and 1-element array replacements, as well as avoiding false positives and fixing discovered overflows[1]), this series contains the foundational elements of several related buffer overflow detection improvements by providing new common helpers and FORTIFY_SOURCE changes needed to gain the introspection required for compiler visibility into array sizes. Also included are a handful of already Acked instances using the helpers (or related clean-ups), with many more waiting at the ready to be taken via subsystem-specific trees[2]. The new helpers are: - struct_group() for gaining struct member range introspection - memset_after() and memset_startat() for clearing to the end of structures - DECLARE_FLEX_ARRAY() for using flex arrays in unions or alone in structs Also included is the beginning of the refactoring of FORTIFY_SOURCE to support memcpy() introspection, fix missing and regressed coverage under GCC, and to prepare to fix the currently broken Clang support. Finishing this work is part of the larger series[0], but depends on all the false positives and buffer overflow bug fixes to have landed already and those that depend on this series to land. As part of the FORTIFY_SOURCE refactoring, a set of both a compile-time and run-time tests are added for FORTIFY_SOURCE and the mem*()-family functions respectively. The compile time tests have found a legitimate (though corner-case) bug[6] already. Please note that the appearance of "panic" and "BUG" in the FORTIFY_SOURCE refactoring are the result of relocating existing code, and no new use of those code-paths are expected nor desired. Finally, there are two tree-wide conversions for 0-element arrays and flexible array unions to gain sane compiler introspection coverage that result in no known object code differences. After this series (and the changes that have now landed via netdev and usb), we are very close to finally being able to build with -Warray-bounds and -Wzero-length-bounds. However, due corner cases in GCC[3] and Clang[4], I have not included the last two patches that turn on these options, as I don't want to introduce any known warnings to the build. Hopefully these can be solved soon" Link: https://lore.kernel.org/lkml/20210818060533.3569517-1-keescook@chromium.org/ [0] Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=grep&q=FORTIFY_SOURCE [1] Link: https://lore.kernel.org/lkml/202108220107.3E26FE6C9C@keescook/ [2] Link: https://lore.kernel.org/lkml/3ab153ec-2798-da4c-f7b1-81b0ac8b0c5b@roeck-us.net/ [3] Link: https://bugs.llvm.org/show_bug.cgi?id=51682 [4] Link: https://lore.kernel.org/lkml/202109051257.29B29745C0@keescook/ [5] Link: https://lore.kernel.org/lkml/20211020200039.170424-1-keescook@chromium.org/ [6] * tag 'overflow-v5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: (30 commits) fortify: strlen: Avoid shadowing previous locals compiler-gcc.h: Define __SANITIZE_ADDRESS__ under hwaddress sanitizer treewide: Replace 0-element memcpy() destinations with flexible arrays treewide: Replace open-coded flex arrays in unions stddef: Introduce DECLARE_FLEX_ARRAY() helper btrfs: Use memset_startat() to clear end of struct string.h: Introduce memset_startat() for wiping trailing members and padding xfrm: Use memset_after() to clear padding string.h: Introduce memset_after() for wiping trailing members/padding lib: Introduce CONFIG_MEMCPY_KUNIT_TEST fortify: Add compile-time FORTIFY_SOURCE tests fortify: Allow strlen() and strnlen() to pass compile-time known lengths fortify: Prepare to improve strnlen() and strlen() warnings fortify: Fix dropped strcpy() compile-time write overflow check fortify: Explicitly disable Clang support fortify: Move remaining fortify helpers into fortify-string.h lib/string: Move helper functions out of string.c compiler_types.h: Remove __compiletime_object_size() cm4000_cs: Use struct_group() to zero struct cm4000_dev region can: flexcan: Use struct_group() to zero struct flexcan_regs regions ...
This commit is contained in:
commit
2dc26d98cf
@ -7341,6 +7341,15 @@ L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/nvidia/*
|
||||
|
||||
FORTIFY_SOURCE
|
||||
M: Kees Cook <keescook@chromium.org>
|
||||
L: linux-hardening@vger.kernel.org
|
||||
S: Supported
|
||||
F: include/linux/fortify-string.h
|
||||
F: lib/test_fortify/*
|
||||
F: scripts/test_fortify.sh
|
||||
K: \b__NO_FORTIFY\b
|
||||
|
||||
FPGA DFL DRIVERS
|
||||
M: Wu Hao <hao.wu@intel.com>
|
||||
R: Tom Rix <trix@redhat.com>
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Small subset of simple string routines
|
||||
*/
|
||||
|
||||
#define __NO_FORTIFY
|
||||
#include <linux/string.h>
|
||||
|
||||
/*
|
||||
|
@ -8,6 +8,9 @@
|
||||
*/
|
||||
|
||||
#define IN_ARCH_STRING_C 1
|
||||
#ifndef __NO_FORTIFY
|
||||
# define __NO_FORTIFY
|
||||
#endif
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
|
@ -14,6 +14,8 @@
|
||||
#undef CONFIG_KASAN
|
||||
#undef CONFIG_KASAN_GENERIC
|
||||
|
||||
#define __NO_FORTIFY
|
||||
|
||||
/* cpu_feature_enabled() cannot be used this early */
|
||||
#define USE_EARLY_PGTABLE_L5
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "misc.h"
|
||||
#include <linux/efi.h>
|
||||
#include <asm/e820/types.h>
|
||||
#include <asm/processor.h>
|
||||
|
@ -11,6 +11,7 @@
|
||||
* strings.
|
||||
*/
|
||||
|
||||
#define __NO_FORTIFY
|
||||
#include <linux/string.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
|
@ -116,8 +116,9 @@ struct cm4000_dev {
|
||||
wait_queue_head_t atrq; /* wait for ATR valid */
|
||||
wait_queue_head_t readq; /* used by write to wake blk.read */
|
||||
|
||||
/* warning: do not move this fields.
|
||||
/* warning: do not move this struct group.
|
||||
* initialising to zero depends on it - see ZERO_DEV below. */
|
||||
struct_group(init,
|
||||
unsigned char atr_csum;
|
||||
unsigned char atr_len_retry;
|
||||
unsigned short atr_len;
|
||||
@ -140,12 +141,10 @@ struct cm4000_dev {
|
||||
|
||||
struct timer_list timer; /* used to keep monitor running */
|
||||
int monitor_running;
|
||||
);
|
||||
};
|
||||
|
||||
#define ZERO_DEV(dev) \
|
||||
memset(&dev->atr_csum,0, \
|
||||
sizeof(struct cm4000_dev) - \
|
||||
offsetof(struct cm4000_dev, atr_csum))
|
||||
#define ZERO_DEV(dev) memset(&((dev)->init), 0, sizeof((dev)->init))
|
||||
|
||||
static struct pcmcia_device *dev_table[CM4000_MAX_DEV];
|
||||
static struct class *cmm_class;
|
||||
|
@ -222,8 +222,10 @@ struct chcr_authenc_ctx {
|
||||
};
|
||||
|
||||
struct __aead_ctx {
|
||||
struct chcr_gcm_ctx gcm[0];
|
||||
struct chcr_authenc_ctx authenc[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct chcr_gcm_ctx, gcm);
|
||||
DECLARE_FLEX_ARRAY(struct chcr_authenc_ctx, authenc);
|
||||
};
|
||||
};
|
||||
|
||||
struct chcr_aead_ctx {
|
||||
@ -245,9 +247,11 @@ struct hmac_ctx {
|
||||
};
|
||||
|
||||
struct __crypto_ctx {
|
||||
struct hmac_ctx hmacctx[0];
|
||||
struct ablk_ctx ablkctx[0];
|
||||
struct chcr_aead_ctx aeadctx[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct hmac_ctx, hmacctx);
|
||||
DECLARE_FLEX_ARRAY(struct ablk_ctx, ablkctx);
|
||||
DECLARE_FLEX_ARRAY(struct chcr_aead_ctx, aeadctx);
|
||||
};
|
||||
};
|
||||
|
||||
struct chcr_context {
|
||||
|
@ -75,52 +75,27 @@ static inline int cxl_hdm_decoder_count(u32 cap_hdr)
|
||||
#define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18
|
||||
#define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20
|
||||
|
||||
#define CXL_COMPONENT_REGS() \
|
||||
void __iomem *hdm_decoder
|
||||
|
||||
#define CXL_DEVICE_REGS() \
|
||||
void __iomem *status; \
|
||||
void __iomem *mbox; \
|
||||
void __iomem *memdev
|
||||
|
||||
/* See note for 'struct cxl_regs' for the rationale of this organization */
|
||||
/*
|
||||
* CXL_COMPONENT_REGS - Common set of CXL Component register block base pointers
|
||||
* @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
|
||||
*/
|
||||
struct cxl_component_regs {
|
||||
CXL_COMPONENT_REGS();
|
||||
};
|
||||
|
||||
/* See note for 'struct cxl_regs' for the rationale of this organization */
|
||||
/*
|
||||
* CXL_DEVICE_REGS - Common set of CXL Device register block base pointers
|
||||
* @status: CXL 2.0 8.2.8.3 Device Status Registers
|
||||
* @mbox: CXL 2.0 8.2.8.4 Mailbox Registers
|
||||
* @memdev: CXL 2.0 8.2.8.5 Memory Device Registers
|
||||
*/
|
||||
struct cxl_device_regs {
|
||||
CXL_DEVICE_REGS();
|
||||
};
|
||||
|
||||
/*
|
||||
* Note, the anonymous union organization allows for per
|
||||
* register-block-type helper routines, without requiring block-type
|
||||
* agnostic code to include the prefix.
|
||||
* Using struct_group() allows for per register-block-type helper routines,
|
||||
* without requiring block-type agnostic code to include the prefix.
|
||||
*/
|
||||
struct cxl_regs {
|
||||
union {
|
||||
struct {
|
||||
CXL_COMPONENT_REGS();
|
||||
};
|
||||
struct cxl_component_regs component;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
CXL_DEVICE_REGS();
|
||||
};
|
||||
struct cxl_device_regs device_regs;
|
||||
};
|
||||
/*
|
||||
* Common set of CXL Component register block base pointers
|
||||
* @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
|
||||
*/
|
||||
struct_group_tagged(cxl_component_regs, component,
|
||||
void __iomem *hdm_decoder;
|
||||
);
|
||||
/*
|
||||
* Common set of CXL Device register block base pointers
|
||||
* @status: CXL 2.0 8.2.8.3 Device Status Registers
|
||||
* @mbox: CXL 2.0 8.2.8.4 Mailbox Registers
|
||||
* @memdev: CXL 2.0 8.2.8.5 Memory Device Registers
|
||||
*/
|
||||
struct_group_tagged(cxl_device_regs, device_regs,
|
||||
void __iomem *status, *mbox, *memdev;
|
||||
);
|
||||
};
|
||||
|
||||
struct cxl_reg_map {
|
||||
|
@ -38,16 +38,18 @@
|
||||
typedef struct drm32_mga_init {
|
||||
int func;
|
||||
u32 sarea_priv_offset;
|
||||
int chipset;
|
||||
int sgram;
|
||||
unsigned int maccess;
|
||||
unsigned int fb_cpp;
|
||||
unsigned int front_offset, front_pitch;
|
||||
unsigned int back_offset, back_pitch;
|
||||
unsigned int depth_cpp;
|
||||
unsigned int depth_offset, depth_pitch;
|
||||
unsigned int texture_offset[MGA_NR_TEX_HEAPS];
|
||||
unsigned int texture_size[MGA_NR_TEX_HEAPS];
|
||||
struct_group(always32bit,
|
||||
int chipset;
|
||||
int sgram;
|
||||
unsigned int maccess;
|
||||
unsigned int fb_cpp;
|
||||
unsigned int front_offset, front_pitch;
|
||||
unsigned int back_offset, back_pitch;
|
||||
unsigned int depth_cpp;
|
||||
unsigned int depth_offset, depth_pitch;
|
||||
unsigned int texture_offset[MGA_NR_TEX_HEAPS];
|
||||
unsigned int texture_size[MGA_NR_TEX_HEAPS];
|
||||
);
|
||||
u32 fb_offset;
|
||||
u32 mmio_offset;
|
||||
u32 status_offset;
|
||||
@ -67,9 +69,8 @@ static int compat_mga_init(struct file *file, unsigned int cmd,
|
||||
|
||||
init.func = init32.func;
|
||||
init.sarea_priv_offset = init32.sarea_priv_offset;
|
||||
memcpy(&init.chipset, &init32.chipset,
|
||||
offsetof(drm_mga_init_t, fb_offset) -
|
||||
offsetof(drm_mga_init_t, chipset));
|
||||
memcpy(&init.always32bit, &init32.always32bit,
|
||||
sizeof(init32.always32bit));
|
||||
init.fb_offset = init32.fb_offset;
|
||||
init.mmio_offset = init32.mmio_offset;
|
||||
init.status_offset = init32.status_offset;
|
||||
|
@ -129,10 +129,12 @@ struct cp2112_xfer_status_report {
|
||||
|
||||
struct cp2112_string_report {
|
||||
u8 dummy; /* force .string to be aligned */
|
||||
u8 report; /* CP2112_*_STRING */
|
||||
u8 length; /* length in bytes of everyting after .report */
|
||||
u8 type; /* USB_DT_STRING */
|
||||
wchar_t string[30]; /* UTF16_LITTLE_ENDIAN string */
|
||||
struct_group_attr(contents, __packed,
|
||||
u8 report; /* CP2112_*_STRING */
|
||||
u8 length; /* length in bytes of everything after .report */
|
||||
u8 type; /* USB_DT_STRING */
|
||||
wchar_t string[30]; /* UTF16_LITTLE_ENDIAN string */
|
||||
);
|
||||
} __packed;
|
||||
|
||||
/* Number of times to request transfer status before giving up waiting for a
|
||||
@ -986,8 +988,8 @@ static ssize_t pstr_show(struct device *kdev,
|
||||
u8 length;
|
||||
int ret;
|
||||
|
||||
ret = cp2112_hid_get(hdev, attr->report, &report.report,
|
||||
sizeof(report) - 1, HID_FEATURE_REPORT);
|
||||
ret = cp2112_hid_get(hdev, attr->report, (u8 *)&report.contents,
|
||||
sizeof(report.contents), HID_FEATURE_REPORT);
|
||||
if (ret < 3) {
|
||||
hid_err(hdev, "error reading %s string: %d\n", kattr->attr.name,
|
||||
ret);
|
||||
|
@ -857,7 +857,7 @@ static int kone_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
memcpy(&kone->last_mouse_event, event,
|
||||
sizeof(struct kone_mouse_event));
|
||||
else
|
||||
memset(&event->tilt, 0, 5);
|
||||
memset(&event->wipe, 0, sizeof(event->wipe));
|
||||
|
||||
kone_keep_values_up_to_date(kone, event);
|
||||
|
||||
|
@ -152,11 +152,13 @@ struct kone_mouse_event {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint8_t wheel; /* up = 1, down = -1 */
|
||||
uint8_t tilt; /* right = 1, left = -1 */
|
||||
uint8_t unknown;
|
||||
uint8_t event;
|
||||
uint8_t value; /* press = 0, release = 1 */
|
||||
uint8_t macro_key; /* 0 to 8 */
|
||||
struct_group(wipe,
|
||||
uint8_t tilt; /* right = 1, left = -1 */
|
||||
uint8_t unknown;
|
||||
uint8_t event;
|
||||
uint8_t value; /* press = 0, release = 1 */
|
||||
uint8_t macro_key; /* 0 to 8 */
|
||||
);
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
enum kone_mouse_events {
|
||||
|
@ -121,8 +121,10 @@ struct ivhd_entry {
|
||||
u8 type;
|
||||
u16 devid;
|
||||
u8 flags;
|
||||
u32 ext;
|
||||
u32 hidh;
|
||||
struct_group(ext_hid,
|
||||
u32 ext;
|
||||
u32 hidh;
|
||||
);
|
||||
u64 cid;
|
||||
u8 uidf;
|
||||
u8 uidl;
|
||||
@ -1377,7 +1379,8 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(hid, (u8 *)(&e->ext), ACPIHID_HID_LEN - 1);
|
||||
BUILD_BUG_ON(sizeof(e->ext_hid) != ACPIHID_HID_LEN - 1);
|
||||
memcpy(hid, &e->ext_hid, ACPIHID_HID_LEN - 1);
|
||||
hid[ACPIHID_HID_LEN - 1] = '\0';
|
||||
|
||||
if (!(*hid)) {
|
||||
|
@ -848,7 +848,8 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
|
||||
cmd->read = cmd->info.devaddr & 0x01;
|
||||
switch(cmd->info.type) {
|
||||
case SMU_I2C_TRANSFER_SIMPLE:
|
||||
memset(&cmd->info.sublen, 0, 4);
|
||||
cmd->info.sublen = 0;
|
||||
memset(cmd->info.subaddr, 0, sizeof(cmd->info.subaddr));
|
||||
break;
|
||||
case SMU_I2C_TRANSFER_COMBINED:
|
||||
cmd->info.devaddr &= 0xfe;
|
||||
|
@ -290,31 +290,33 @@ struct flexcan_regs {
|
||||
u32 dbg1; /* 0x58 */
|
||||
u32 dbg2; /* 0x5c */
|
||||
u32 _reserved3[8]; /* 0x60 */
|
||||
u8 mb[2][512]; /* 0x80 - Not affected by Soft Reset */
|
||||
/* FIFO-mode:
|
||||
* MB
|
||||
* 0x080...0x08f 0 RX message buffer
|
||||
* 0x090...0x0df 1-5 reserved
|
||||
* 0x0e0...0x0ff 6-7 8 entry ID table
|
||||
* (mx25, mx28, mx35, mx53)
|
||||
* 0x0e0...0x2df 6-7..37 8..128 entry ID table
|
||||
* size conf'ed via ctrl2::RFFN
|
||||
* (mx6, vf610)
|
||||
*/
|
||||
u32 _reserved4[256]; /* 0x480 */
|
||||
u32 rximr[64]; /* 0x880 - Not affected by Soft Reset */
|
||||
u32 _reserved5[24]; /* 0x980 */
|
||||
u32 gfwr_mx6; /* 0x9e0 - MX6 */
|
||||
u32 _reserved6[39]; /* 0x9e4 */
|
||||
u32 _rxfir[6]; /* 0xa80 */
|
||||
u32 _reserved8[2]; /* 0xa98 */
|
||||
u32 _rxmgmask; /* 0xaa0 */
|
||||
u32 _rxfgmask; /* 0xaa4 */
|
||||
u32 _rx14mask; /* 0xaa8 */
|
||||
u32 _rx15mask; /* 0xaac */
|
||||
u32 tx_smb[4]; /* 0xab0 */
|
||||
u32 rx_smb0[4]; /* 0xac0 */
|
||||
u32 rx_smb1[4]; /* 0xad0 */
|
||||
struct_group(init,
|
||||
u8 mb[2][512]; /* 0x80 - Not affected by Soft Reset */
|
||||
/* FIFO-mode:
|
||||
* MB
|
||||
* 0x080...0x08f 0 RX message buffer
|
||||
* 0x090...0x0df 1-5 reserved
|
||||
* 0x0e0...0x0ff 6-7 8 entry ID table
|
||||
* (mx25, mx28, mx35, mx53)
|
||||
* 0x0e0...0x2df 6-7..37 8..128 entry ID table
|
||||
* size conf'ed via ctrl2::RFFN
|
||||
* (mx6, vf610)
|
||||
*/
|
||||
u32 _reserved4[256]; /* 0x480 */
|
||||
u32 rximr[64]; /* 0x880 - Not affected by Soft Reset */
|
||||
u32 _reserved5[24]; /* 0x980 */
|
||||
u32 gfwr_mx6; /* 0x9e0 - MX6 */
|
||||
u32 _reserved6[39]; /* 0x9e4 */
|
||||
u32 _rxfir[6]; /* 0xa80 */
|
||||
u32 _reserved8[2]; /* 0xa98 */
|
||||
u32 _rxmgmask; /* 0xaa0 */
|
||||
u32 _rxfgmask; /* 0xaa4 */
|
||||
u32 _rx14mask; /* 0xaa8 */
|
||||
u32 _rx15mask; /* 0xaac */
|
||||
u32 tx_smb[4]; /* 0xab0 */
|
||||
u32 rx_smb0[4]; /* 0xac0 */
|
||||
u32 rx_smb1[4]; /* 0xad0 */
|
||||
);
|
||||
u32 mecr; /* 0xae0 */
|
||||
u32 erriar; /* 0xae4 */
|
||||
u32 erridpr; /* 0xae8 */
|
||||
@ -328,9 +330,11 @@ struct flexcan_regs {
|
||||
u32 fdcbt; /* 0xc04 - Not affected by Soft Reset */
|
||||
u32 fdcrc; /* 0xc08 */
|
||||
u32 _reserved9[199]; /* 0xc0c */
|
||||
u32 tx_smb_fd[18]; /* 0xf28 */
|
||||
u32 rx_smb0_fd[18]; /* 0xf70 */
|
||||
u32 rx_smb1_fd[18]; /* 0xfb8 */
|
||||
struct_group(init_fd,
|
||||
u32 tx_smb_fd[18]; /* 0xf28 */
|
||||
u32 rx_smb0_fd[18]; /* 0xf70 */
|
||||
u32 rx_smb1_fd[18]; /* 0xfb8 */
|
||||
);
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct flexcan_regs) == 0x4 * 18 + 0xfb8);
|
||||
@ -1400,14 +1404,10 @@ static void flexcan_ram_init(struct net_device *dev)
|
||||
reg_ctrl2 |= FLEXCAN_CTRL2_WRMFRZ;
|
||||
priv->write(reg_ctrl2, ®s->ctrl2);
|
||||
|
||||
memset_io(®s->mb[0][0], 0,
|
||||
offsetof(struct flexcan_regs, rx_smb1[3]) -
|
||||
offsetof(struct flexcan_regs, mb[0][0]) + 0x4);
|
||||
memset_io(®s->init, 0, sizeof(regs->init));
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
|
||||
memset_io(®s->tx_smb_fd[0], 0,
|
||||
offsetof(struct flexcan_regs, rx_smb1_fd[17]) -
|
||||
offsetof(struct flexcan_regs, tx_smb_fd[0]) + 0x4);
|
||||
memset_io(®s->init_fd, 0, sizeof(regs->init_fd));
|
||||
|
||||
reg_ctrl2 &= ~FLEXCAN_CTRL2_WRMFRZ;
|
||||
priv->write(reg_ctrl2, ®s->ctrl2);
|
||||
|
@ -192,7 +192,7 @@ struct es581_4_urb_cmd {
|
||||
struct es581_4_rx_cmd_ret rx_cmd_ret;
|
||||
__le64 timestamp;
|
||||
u8 rx_cmd_ret_u8;
|
||||
u8 raw_msg[0];
|
||||
DECLARE_FLEX_ARRAY(u8, raw_msg);
|
||||
} __packed;
|
||||
|
||||
__le16 reserved_for_crc16_do_not_use;
|
||||
|
@ -219,7 +219,7 @@ struct es58x_fd_urb_cmd {
|
||||
struct es58x_fd_tx_ack_msg tx_ack_msg;
|
||||
__le64 timestamp;
|
||||
__le32 rx_cmd_ret_le32;
|
||||
u8 raw_msg[0];
|
||||
DECLARE_FLEX_ARRAY(u8, raw_msg);
|
||||
} __packed;
|
||||
|
||||
__le16 reserved_for_crc16_do_not_use;
|
||||
|
@ -159,10 +159,10 @@ static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
|
||||
}
|
||||
|
||||
data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id);
|
||||
for (i = 0; i < bp->max_tc; i++, data += sizeof(cos2bw) - 4) {
|
||||
for (i = 0; i < bp->max_tc; i++, data += sizeof(cos2bw.cfg)) {
|
||||
int tc;
|
||||
|
||||
memcpy(&cos2bw.queue_id, data, sizeof(cos2bw) - 4);
|
||||
memcpy(&cos2bw.cfg, data, sizeof(cos2bw.cfg));
|
||||
if (i == 0)
|
||||
cos2bw.queue_id = resp->queue_id0;
|
||||
|
||||
|
@ -23,13 +23,15 @@ struct bnxt_dcb {
|
||||
|
||||
struct bnxt_cos2bw_cfg {
|
||||
u8 pad[3];
|
||||
u8 queue_id;
|
||||
__le32 min_bw;
|
||||
__le32 max_bw;
|
||||
struct_group_attr(cfg, __packed,
|
||||
u8 queue_id;
|
||||
__le32 min_bw;
|
||||
__le32 max_bw;
|
||||
#define BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
|
||||
u8 tsa;
|
||||
u8 pri_lvl;
|
||||
u8 bw_weight;
|
||||
u8 tsa;
|
||||
u8 pri_lvl;
|
||||
u8 bw_weight;
|
||||
);
|
||||
u8 unused;
|
||||
};
|
||||
|
||||
|
@ -109,7 +109,7 @@ struct bmi_cmd {
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 len;
|
||||
u8 payload[0];
|
||||
u8 payload[];
|
||||
} write_mem;
|
||||
struct {
|
||||
__le32 addr;
|
||||
@ -138,18 +138,18 @@ struct bmi_cmd {
|
||||
} rompatch_uninstall;
|
||||
struct {
|
||||
__le32 count;
|
||||
__le32 patch_ids[0]; /* length of @count */
|
||||
__le32 patch_ids[]; /* length of @count */
|
||||
} rompatch_activate;
|
||||
struct {
|
||||
__le32 count;
|
||||
__le32 patch_ids[0]; /* length of @count */
|
||||
__le32 patch_ids[]; /* length of @count */
|
||||
} rompatch_deactivate;
|
||||
struct {
|
||||
__le32 addr;
|
||||
} lz_start;
|
||||
struct {
|
||||
__le32 len; /* max BMI_MAX_DATA_SIZE */
|
||||
u8 payload[0]; /* length of @len */
|
||||
u8 payload[]; /* length of @len */
|
||||
} lz_data;
|
||||
struct {
|
||||
u8 name[BMI_NVRAM_SEG_NAME_SZ];
|
||||
@ -160,7 +160,7 @@ struct bmi_cmd {
|
||||
|
||||
union bmi_resp {
|
||||
struct {
|
||||
u8 payload[0];
|
||||
DECLARE_FLEX_ARRAY(u8, payload);
|
||||
} read_mem;
|
||||
struct {
|
||||
__le32 result;
|
||||
|
@ -1674,8 +1674,11 @@ struct htt_tx_fetch_ind {
|
||||
__le32 token;
|
||||
__le16 num_resp_ids;
|
||||
__le16 num_records;
|
||||
__le32 resp_ids[0]; /* ath10k_htt_get_tx_fetch_ind_resp_ids() */
|
||||
struct htt_tx_fetch_record records[];
|
||||
union {
|
||||
/* ath10k_htt_get_tx_fetch_ind_resp_ids() */
|
||||
DECLARE_FLEX_ARRAY(__le32, resp_ids);
|
||||
DECLARE_FLEX_ARRAY(struct htt_tx_fetch_record, records);
|
||||
};
|
||||
} __packed;
|
||||
|
||||
static inline void *
|
||||
|
@ -1408,8 +1408,10 @@ struct il3945_tx_cmd {
|
||||
* MAC header goes here, followed by 2 bytes padding if MAC header
|
||||
* length is 26 or 30 bytes, followed by payload data
|
||||
*/
|
||||
u8 payload[0];
|
||||
struct ieee80211_hdr hdr[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(u8, payload);
|
||||
DECLARE_FLEX_ARRAY(struct ieee80211_hdr, hdr);
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
|
@ -1251,8 +1251,10 @@ struct iwl_tx_cmd {
|
||||
* MAC header goes here, followed by 2 bytes padding if MAC header
|
||||
* length is 26 or 30 bytes, followed by payload data
|
||||
*/
|
||||
u8 payload[0];
|
||||
struct ieee80211_hdr hdr[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(u8, payload);
|
||||
DECLARE_FLEX_ARRAY(struct ieee80211_hdr, hdr);
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
|
@ -239,8 +239,10 @@ struct iwl_tx_cmd {
|
||||
u8 tid_tspec;
|
||||
__le16 pm_frame_timeout;
|
||||
__le16 reserved4;
|
||||
u8 payload[0];
|
||||
struct ieee80211_hdr hdr[0];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(u8, payload);
|
||||
DECLARE_FLEX_ARRAY(struct ieee80211_hdr, hdr);
|
||||
};
|
||||
} __packed; /* TX_CMD_API_S_VER_6 */
|
||||
|
||||
struct iwl_dram_sec_info {
|
||||
@ -713,8 +715,10 @@ struct iwl_mvm_compressed_ba_notif {
|
||||
__le32 tx_rate;
|
||||
__le16 tfd_cnt;
|
||||
__le16 ra_tid_cnt;
|
||||
struct iwl_mvm_compressed_ba_ratid ra_tid[0];
|
||||
struct iwl_mvm_compressed_ba_tfd tfd[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct iwl_mvm_compressed_ba_ratid, ra_tid);
|
||||
DECLARE_FLEX_ARRAY(struct iwl_mvm_compressed_ba_tfd, tfd);
|
||||
};
|
||||
} __packed; /* COMPRESSED_BA_RES_API_S_VER_4 */
|
||||
|
||||
/**
|
||||
|
@ -517,8 +517,10 @@ struct asd_ms_conn_map {
|
||||
u8 num_nodes;
|
||||
u8 usage_model_id;
|
||||
u32 _resvd;
|
||||
struct asd_ms_conn_desc conn_desc[0];
|
||||
struct asd_ms_node_desc node_desc[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct asd_ms_conn_desc, conn_desc);
|
||||
DECLARE_FLEX_ARRAY(struct asd_ms_node_desc, node_desc);
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct asd_ctrla_phy_entry {
|
||||
|
@ -1055,8 +1055,9 @@ static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
|
||||
/* Set up the actual SRP IU */
|
||||
BUILD_BUG_ON(sizeof(evt_struct->iu.srp) != SRP_MAX_IU_LEN);
|
||||
memset(&evt_struct->iu.srp, 0x00, sizeof(evt_struct->iu.srp));
|
||||
srp_cmd = &evt_struct->iu.srp.cmd;
|
||||
memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
|
||||
srp_cmd->opcode = SRP_CMD;
|
||||
memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
|
||||
int_to_scsilun(lun, &srp_cmd->lun);
|
||||
|
@ -366,13 +366,13 @@ struct qla4_work_evt {
|
||||
struct {
|
||||
enum iscsi_host_event_code code;
|
||||
uint32_t data_size;
|
||||
uint8_t data[0];
|
||||
uint8_t data[];
|
||||
} aen;
|
||||
struct {
|
||||
uint32_t status;
|
||||
uint32_t pid;
|
||||
uint32_t data_size;
|
||||
uint8_t data[0];
|
||||
uint8_t data[];
|
||||
} ping;
|
||||
} u;
|
||||
};
|
||||
|
@ -185,7 +185,7 @@ struct ieee_param {
|
||||
struct {
|
||||
u32 len;
|
||||
u8 reserved[32];
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
} wpa_ie;
|
||||
struct {
|
||||
int command;
|
||||
@ -198,7 +198,7 @@ struct ieee_param {
|
||||
u8 idx;
|
||||
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
|
||||
u16 key_len;
|
||||
u8 key[0];
|
||||
u8 key[];
|
||||
} crypt;
|
||||
#ifdef CONFIG_88EU_AP_MODE
|
||||
struct {
|
||||
@ -210,7 +210,7 @@ struct ieee_param {
|
||||
} add_sta;
|
||||
struct {
|
||||
u8 reserved[2];/* for set max_num_sta */
|
||||
u8 buf[0];
|
||||
u8 buf[];
|
||||
} bcn_ie;
|
||||
#endif
|
||||
|
||||
|
@ -78,7 +78,7 @@ struct ieee_param {
|
||||
struct {
|
||||
u32 len;
|
||||
u8 reserved[32];
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
} wpa_ie;
|
||||
struct {
|
||||
int command;
|
||||
@ -91,7 +91,7 @@ struct ieee_param {
|
||||
u8 idx;
|
||||
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
|
||||
u16 key_len;
|
||||
u8 key[0];
|
||||
u8 key[];
|
||||
} crypt;
|
||||
} u;
|
||||
};
|
||||
|
@ -172,7 +172,7 @@ struct ieee_param {
|
||||
struct {
|
||||
u32 len;
|
||||
u8 reserved[32];
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
} wpa_ie;
|
||||
struct{
|
||||
int command;
|
||||
@ -185,7 +185,7 @@ struct ieee_param {
|
||||
u8 idx;
|
||||
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
|
||||
u16 key_len;
|
||||
u8 key[0];
|
||||
u8 key[];
|
||||
} crypt;
|
||||
struct {
|
||||
u16 aid;
|
||||
@ -196,7 +196,7 @@ struct ieee_param {
|
||||
} add_sta;
|
||||
struct {
|
||||
u8 reserved[2];/* for set max_num_sta */
|
||||
u8 buf[0];
|
||||
u8 buf[];
|
||||
} bcn_ie;
|
||||
} u;
|
||||
};
|
||||
|
@ -39,10 +39,8 @@ static void btrfs_read_root_item(struct extent_buffer *eb, int slot,
|
||||
need_reset = 1;
|
||||
}
|
||||
if (need_reset) {
|
||||
memset(&item->generation_v2, 0,
|
||||
sizeof(*item) - offsetof(struct btrfs_root_item,
|
||||
generation_v2));
|
||||
|
||||
/* Clear all members from generation_v2 onwards. */
|
||||
memset_startat(item, 0, generation_v2);
|
||||
generate_random_guid(item->uuid);
|
||||
}
|
||||
}
|
||||
|
@ -409,10 +409,10 @@ struct bplus_header
|
||||
__le16 first_free; /* offset from start of header to
|
||||
first free node in array */
|
||||
union {
|
||||
struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving
|
||||
subtree pointers */
|
||||
struct bplus_leaf_node external[0]; /* (external) 3-word entries giving
|
||||
sector runs */
|
||||
/* (internal) 2-word entries giving subtree pointers */
|
||||
DECLARE_FLEX_ARRAY(struct bplus_internal_node, internal);
|
||||
/* (external) 3-word entries giving sector runs */
|
||||
DECLARE_FLEX_ARRAY(struct bplus_leaf_node, external);
|
||||
} u;
|
||||
};
|
||||
|
||||
|
@ -41,8 +41,6 @@
|
||||
|
||||
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
|
||||
|
||||
#define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
|
||||
|
||||
#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
|
||||
#define __latent_entropy __attribute__((latent_entropy))
|
||||
#endif
|
||||
@ -123,6 +121,14 @@
|
||||
#define __no_sanitize_coverage
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Treat __SANITIZE_HWADDRESS__ the same as __SANITIZE_ADDRESS__ in the kernel,
|
||||
* matching the defines used by Clang.
|
||||
*/
|
||||
#ifdef __SANITIZE_HWADDRESS__
|
||||
#define __SANITIZE_ADDRESS__
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Turn individual warnings and errors on and off locally, depending
|
||||
* on version.
|
||||
|
@ -290,11 +290,6 @@ struct ftrace_likely_data {
|
||||
(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \
|
||||
sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
|
||||
|
||||
/* Compile time object size, -1 for unknown */
|
||||
#ifndef __compiletime_object_size
|
||||
# define __compiletime_object_size(obj) -1
|
||||
#endif
|
||||
|
||||
#ifdef __OPTIMIZE__
|
||||
# define __compiletime_assert(condition, msg, prefix, suffix) \
|
||||
do { \
|
||||
|
@ -586,8 +586,10 @@ struct bpf_prog {
|
||||
struct bpf_prog_aux *aux; /* Auxiliary fields */
|
||||
struct sock_fprog_kern *orig_prog; /* Original BPF program */
|
||||
/* Instructions for interpreter */
|
||||
struct sock_filter insns[0];
|
||||
struct bpf_insn insnsi[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct sock_filter, insns);
|
||||
DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi);
|
||||
};
|
||||
};
|
||||
|
||||
struct sk_filter {
|
||||
|
@ -2,6 +2,27 @@
|
||||
#ifndef _LINUX_FORTIFY_STRING_H_
|
||||
#define _LINUX_FORTIFY_STRING_H_
|
||||
|
||||
#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline))
|
||||
#define __RENAME(x) __asm__(#x)
|
||||
|
||||
void fortify_panic(const char *name) __noreturn __cold;
|
||||
void __read_overflow(void) __compiletime_error("detected read beyond size of object (1st parameter)");
|
||||
void __read_overflow2(void) __compiletime_error("detected read beyond size of object (2nd parameter)");
|
||||
void __write_overflow(void) __compiletime_error("detected write beyond size of object (1st parameter)");
|
||||
|
||||
#define __compiletime_strlen(p) \
|
||||
({ \
|
||||
unsigned char *__p = (unsigned char *)(p); \
|
||||
size_t __ret = (size_t)-1; \
|
||||
size_t __p_size = __builtin_object_size(p, 1); \
|
||||
if (__p_size != (size_t)-1) { \
|
||||
size_t __p_len = __p_size - 1; \
|
||||
if (__builtin_constant_p(__p[__p_len]) && \
|
||||
__p[__p_len] == '\0') \
|
||||
__ret = __builtin_strlen(__p); \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
|
||||
extern void *__underlying_memchr(const void *p, int c, __kernel_size_t size) __RENAME(memchr);
|
||||
@ -49,14 +70,35 @@ __FORTIFY_INLINE char *strcat(char *p, const char *q)
|
||||
return p;
|
||||
}
|
||||
|
||||
extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);
|
||||
__FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen)
|
||||
{
|
||||
size_t p_size = __builtin_object_size(p, 1);
|
||||
size_t p_len = __compiletime_strlen(p);
|
||||
size_t ret;
|
||||
|
||||
/* We can take compile-time actions when maxlen is const. */
|
||||
if (__builtin_constant_p(maxlen) && p_len != (size_t)-1) {
|
||||
/* If p is const, we can use its compile-time-known len. */
|
||||
if (maxlen >= p_size)
|
||||
return p_len;
|
||||
}
|
||||
|
||||
/* Do not check characters beyond the end of p. */
|
||||
ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
|
||||
if (p_size <= ret && maxlen != ret)
|
||||
fortify_panic(__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* defined after fortified strnlen to reuse it. */
|
||||
__FORTIFY_INLINE __kernel_size_t strlen(const char *p)
|
||||
{
|
||||
__kernel_size_t ret;
|
||||
size_t p_size = __builtin_object_size(p, 1);
|
||||
|
||||
/* Work around gcc excess stack consumption issue */
|
||||
if (p_size == (size_t)-1 ||
|
||||
(__builtin_constant_p(p[p_size - 1]) && p[p_size - 1] == '\0'))
|
||||
/* Give up if we don't know how large p is. */
|
||||
if (p_size == (size_t)-1)
|
||||
return __underlying_strlen(p);
|
||||
ret = strnlen(p, p_size);
|
||||
if (p_size <= ret)
|
||||
@ -64,39 +106,31 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p)
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);
|
||||
__FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen)
|
||||
{
|
||||
size_t p_size = __builtin_object_size(p, 1);
|
||||
__kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
|
||||
|
||||
if (p_size <= ret && maxlen != ret)
|
||||
fortify_panic(__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* defined after fortified strlen to reuse it */
|
||||
extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy);
|
||||
__FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)
|
||||
{
|
||||
size_t ret;
|
||||
size_t p_size = __builtin_object_size(p, 1);
|
||||
size_t q_size = __builtin_object_size(q, 1);
|
||||
size_t q_len; /* Full count of source string length. */
|
||||
size_t len; /* Count of characters going into destination. */
|
||||
|
||||
if (p_size == (size_t)-1 && q_size == (size_t)-1)
|
||||
return __real_strlcpy(p, q, size);
|
||||
ret = strlen(q);
|
||||
if (size) {
|
||||
size_t len = (ret >= size) ? size - 1 : ret;
|
||||
|
||||
if (__builtin_constant_p(len) && len >= p_size)
|
||||
q_len = strlen(q);
|
||||
len = (q_len >= size) ? size - 1 : q_len;
|
||||
if (__builtin_constant_p(size) && __builtin_constant_p(q_len) && size) {
|
||||
/* Write size is always larger than destination. */
|
||||
if (len >= p_size)
|
||||
__write_overflow();
|
||||
}
|
||||
if (size) {
|
||||
if (len >= p_size)
|
||||
fortify_panic(__func__);
|
||||
__underlying_memcpy(p, q, len);
|
||||
p[len] = '\0';
|
||||
}
|
||||
return ret;
|
||||
return q_len;
|
||||
}
|
||||
|
||||
/* defined after fortified strnlen to reuse it */
|
||||
@ -280,7 +314,10 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q)
|
||||
if (p_size == (size_t)-1 && q_size == (size_t)-1)
|
||||
return __underlying_strcpy(p, q);
|
||||
size = strlen(q) + 1;
|
||||
/* test here to use the more stringent object size */
|
||||
/* Compile-time check for const size overflow. */
|
||||
if (__builtin_constant_p(size) && p_size < size)
|
||||
__write_overflow();
|
||||
/* Run-time check for dynamic size overflow. */
|
||||
if (p_size < size)
|
||||
fortify_panic(__func__);
|
||||
memcpy(p, q, size);
|
||||
|
@ -1143,7 +1143,7 @@ struct ieee80211_mgmt {
|
||||
__le16 auth_transaction;
|
||||
__le16 status_code;
|
||||
/* possibly followed by Challenge text */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed auth;
|
||||
struct {
|
||||
__le16 reason_code;
|
||||
@ -1152,26 +1152,26 @@ struct ieee80211_mgmt {
|
||||
__le16 capab_info;
|
||||
__le16 listen_interval;
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed assoc_req;
|
||||
struct {
|
||||
__le16 capab_info;
|
||||
__le16 status_code;
|
||||
__le16 aid;
|
||||
/* followed by Supported rates */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed assoc_resp, reassoc_resp;
|
||||
struct {
|
||||
__le16 capab_info;
|
||||
__le16 status_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed s1g_assoc_resp, s1g_reassoc_resp;
|
||||
struct {
|
||||
__le16 capab_info;
|
||||
__le16 listen_interval;
|
||||
u8 current_ap[ETH_ALEN];
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed reassoc_req;
|
||||
struct {
|
||||
__le16 reason_code;
|
||||
@ -1182,11 +1182,11 @@ struct ieee80211_mgmt {
|
||||
__le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params, TIM */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed beacon;
|
||||
struct {
|
||||
/* only variable items: SSID, Supported rates */
|
||||
u8 variable[0];
|
||||
DECLARE_FLEX_ARRAY(u8, variable);
|
||||
} __packed probe_req;
|
||||
struct {
|
||||
__le64 timestamp;
|
||||
@ -1194,7 +1194,7 @@ struct ieee80211_mgmt {
|
||||
__le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed probe_resp;
|
||||
struct {
|
||||
u8 category;
|
||||
@ -1203,16 +1203,16 @@ struct ieee80211_mgmt {
|
||||
u8 action_code;
|
||||
u8 dialog_token;
|
||||
u8 status_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed wme_action;
|
||||
struct{
|
||||
u8 action_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed chan_switch;
|
||||
struct{
|
||||
u8 action_code;
|
||||
struct ieee80211_ext_chansw_ie data;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed ext_chan_switch;
|
||||
struct{
|
||||
u8 action_code;
|
||||
@ -1228,7 +1228,7 @@ struct ieee80211_mgmt {
|
||||
__le16 timeout;
|
||||
__le16 start_seq_num;
|
||||
/* followed by BA Extension */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed addba_req;
|
||||
struct{
|
||||
u8 action_code;
|
||||
@ -1244,11 +1244,11 @@ struct ieee80211_mgmt {
|
||||
} __packed delba;
|
||||
struct {
|
||||
u8 action_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed self_prot;
|
||||
struct{
|
||||
u8 action_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed mesh_action;
|
||||
struct {
|
||||
u8 action;
|
||||
@ -1292,7 +1292,7 @@ struct ieee80211_mgmt {
|
||||
u8 toa[6];
|
||||
__le16 tod_error;
|
||||
__le16 toa_error;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed ftm;
|
||||
struct {
|
||||
u8 action_code;
|
||||
|
@ -20,7 +20,7 @@ enum {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sizeof_field(TYPE, MEMBER)
|
||||
* sizeof_field() - Report the size of a struct field in bytes
|
||||
*
|
||||
* @TYPE: The structure containing the field of interest
|
||||
* @MEMBER: The field to return the size of
|
||||
@ -28,7 +28,7 @@ enum {
|
||||
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
|
||||
|
||||
/**
|
||||
* offsetofend(TYPE, MEMBER)
|
||||
* offsetofend() - Report the offset of a struct field within the struct
|
||||
*
|
||||
* @TYPE: The type of the structure
|
||||
* @MEMBER: The member within the structure to get the end offset of
|
||||
@ -36,4 +36,65 @@ enum {
|
||||
#define offsetofend(TYPE, MEMBER) \
|
||||
(offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
|
||||
|
||||
/**
|
||||
* struct_group() - Wrap a set of declarations in a mirrored struct
|
||||
*
|
||||
* @NAME: The identifier name of the mirrored sub-struct
|
||||
* @MEMBERS: The member declarations for the mirrored structs
|
||||
*
|
||||
* Used to create an anonymous union of two structs with identical
|
||||
* layout and size: one anonymous and one named. The former can be
|
||||
* used normally without sub-struct naming, and the latter can be
|
||||
* used to reason about the start, end, and size of the group of
|
||||
* struct members.
|
||||
*/
|
||||
#define struct_group(NAME, MEMBERS...) \
|
||||
__struct_group(/* no tag */, NAME, /* no attrs */, MEMBERS)
|
||||
|
||||
/**
|
||||
* struct_group_attr() - Create a struct_group() with trailing attributes
|
||||
*
|
||||
* @NAME: The identifier name of the mirrored sub-struct
|
||||
* @ATTRS: Any struct attributes to apply
|
||||
* @MEMBERS: The member declarations for the mirrored structs
|
||||
*
|
||||
* Used to create an anonymous union of two structs with identical
|
||||
* layout and size: one anonymous and one named. The former can be
|
||||
* used normally without sub-struct naming, and the latter can be
|
||||
* used to reason about the start, end, and size of the group of
|
||||
* struct members. Includes structure attributes argument.
|
||||
*/
|
||||
#define struct_group_attr(NAME, ATTRS, MEMBERS...) \
|
||||
__struct_group(/* no tag */, NAME, ATTRS, MEMBERS)
|
||||
|
||||
/**
|
||||
* struct_group_tagged() - Create a struct_group with a reusable tag
|
||||
*
|
||||
* @TAG: The tag name for the named sub-struct
|
||||
* @NAME: The identifier name of the mirrored sub-struct
|
||||
* @MEMBERS: The member declarations for the mirrored structs
|
||||
*
|
||||
* Used to create an anonymous union of two structs with identical
|
||||
* layout and size: one anonymous and one named. The former can be
|
||||
* used normally without sub-struct naming, and the latter can be
|
||||
* used to reason about the start, end, and size of the group of
|
||||
* struct members. Includes struct tag argument for the named copy,
|
||||
* so the specified layout can be reused later.
|
||||
*/
|
||||
#define struct_group_tagged(TAG, NAME, MEMBERS...) \
|
||||
__struct_group(TAG, NAME, /* no attrs */, MEMBERS)
|
||||
|
||||
/**
|
||||
* DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
|
||||
*
|
||||
* @TYPE: The type of each flexible array element
|
||||
* @NAME: The name of the flexible array member
|
||||
*
|
||||
* In order to have a flexible array member in a union or alone in a
|
||||
* struct, it needs to be wrapped in an anonymous struct with at least 1
|
||||
* named member, but that member can be empty.
|
||||
*/
|
||||
#define DECLARE_FLEX_ARRAY(TYPE, NAME) \
|
||||
__DECLARE_FLEX_ARRAY(TYPE, NAME)
|
||||
|
||||
#endif
|
||||
|
@ -249,15 +249,6 @@ static inline const char *kbasename(const char *path)
|
||||
return tail ? tail + 1 : path;
|
||||
}
|
||||
|
||||
#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline))
|
||||
#define __RENAME(x) __asm__(#x)
|
||||
|
||||
void fortify_panic(const char *name) __noreturn __cold;
|
||||
void __read_overflow(void) __compiletime_error("detected read beyond size of object passed as 1st parameter");
|
||||
void __read_overflow2(void) __compiletime_error("detected read beyond size of object passed as 2nd parameter");
|
||||
void __read_overflow3(void) __compiletime_error("detected read beyond size of object passed as 3rd parameter");
|
||||
void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter");
|
||||
|
||||
#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE)
|
||||
#include <linux/fortify-string.h>
|
||||
#endif
|
||||
@ -280,6 +271,41 @@ static inline void memcpy_and_pad(void *dest, size_t dest_len,
|
||||
memcpy(dest, src, dest_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* memset_after - Set a value after a struct member to the end of a struct
|
||||
*
|
||||
* @obj: Address of target struct instance
|
||||
* @v: Byte value to repeatedly write
|
||||
* @member: after which struct member to start writing bytes
|
||||
*
|
||||
* This is good for clearing padding following the given member.
|
||||
*/
|
||||
#define memset_after(obj, v, member) \
|
||||
({ \
|
||||
u8 *__ptr = (u8 *)(obj); \
|
||||
typeof(v) __val = (v); \
|
||||
memset(__ptr + offsetofend(typeof(*(obj)), member), __val, \
|
||||
sizeof(*(obj)) - offsetofend(typeof(*(obj)), member)); \
|
||||
})
|
||||
|
||||
/**
|
||||
* memset_startat - Set a value starting at a member to the end of a struct
|
||||
*
|
||||
* @obj: Address of target struct instance
|
||||
* @v: Byte value to repeatedly write
|
||||
* @member: struct member to start writing at
|
||||
*
|
||||
* Note that if there is padding between the prior member and the target
|
||||
* member, memset_after() should be used to clear the prior padding.
|
||||
*/
|
||||
#define memset_startat(obj, v, member) \
|
||||
({ \
|
||||
u8 *__ptr = (u8 *)(obj); \
|
||||
typeof(v) __val = (v); \
|
||||
memset(__ptr + offsetof(typeof(*(obj)), member), __val, \
|
||||
sizeof(*(obj)) - offsetof(typeof(*(obj)), member)); \
|
||||
})
|
||||
|
||||
/**
|
||||
* str_has_prefix - Test if a string has a given prefix
|
||||
* @str: The string to test
|
||||
|
@ -203,7 +203,7 @@ static inline void copy_overflow(int size, unsigned long count)
|
||||
static __always_inline __must_check bool
|
||||
check_copy_size(const void *addr, size_t bytes, bool is_source)
|
||||
{
|
||||
int sz = __compiletime_object_size(addr);
|
||||
int sz = __builtin_object_size(addr, 0);
|
||||
if (unlikely(sz >= 0 && sz < bytes)) {
|
||||
if (!__builtin_constant_p(bytes))
|
||||
copy_overflow(sz, bytes);
|
||||
|
@ -323,8 +323,10 @@ struct ssp_response_iu {
|
||||
__be32 sense_data_len;
|
||||
__be32 response_data_len;
|
||||
|
||||
u8 resp_data[0];
|
||||
u8 sense_data[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(u8, resp_data);
|
||||
DECLARE_FLEX_ARRAY(u8, sense_data);
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ssp_command_iu {
|
||||
@ -554,8 +556,10 @@ struct ssp_response_iu {
|
||||
__be32 sense_data_len;
|
||||
__be32 response_data_len;
|
||||
|
||||
u8 resp_data[0];
|
||||
u8 sense_data[];
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(u8, resp_data);
|
||||
DECLARE_FLEX_ARRAY(u8, sense_data);
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ssp_command_iu {
|
||||
|
@ -279,20 +279,22 @@ typedef struct drm_mga_init {
|
||||
|
||||
unsigned long sarea_priv_offset;
|
||||
|
||||
int chipset;
|
||||
int sgram;
|
||||
__struct_group(/* no tag */, always32bit, /* no attrs */,
|
||||
int chipset;
|
||||
int sgram;
|
||||
|
||||
unsigned int maccess;
|
||||
unsigned int maccess;
|
||||
|
||||
unsigned int fb_cpp;
|
||||
unsigned int front_offset, front_pitch;
|
||||
unsigned int back_offset, back_pitch;
|
||||
unsigned int fb_cpp;
|
||||
unsigned int front_offset, front_pitch;
|
||||
unsigned int back_offset, back_pitch;
|
||||
|
||||
unsigned int depth_cpp;
|
||||
unsigned int depth_offset, depth_pitch;
|
||||
unsigned int depth_cpp;
|
||||
unsigned int depth_offset, depth_pitch;
|
||||
|
||||
unsigned int texture_offset[MGA_NR_TEX_HEAPS];
|
||||
unsigned int texture_size[MGA_NR_TEX_HEAPS];
|
||||
unsigned int texture_offset[MGA_NR_TEX_HEAPS];
|
||||
unsigned int texture_size[MGA_NR_TEX_HEAPS];
|
||||
);
|
||||
|
||||
unsigned long fb_offset;
|
||||
unsigned long mmio_offset;
|
||||
|
@ -45,13 +45,13 @@ struct dlm_lock_params {
|
||||
void __user *bastaddr;
|
||||
struct dlm_lksb __user *lksb;
|
||||
char lvb[DLM_USER_LVB_LEN];
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct dlm_lspace_params {
|
||||
__u32 flags;
|
||||
__u32 minor;
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct dlm_purge_params {
|
||||
|
@ -4,3 +4,40 @@
|
||||
#ifndef __always_inline
|
||||
#define __always_inline inline
|
||||
#endif
|
||||
|
||||
/**
|
||||
* __struct_group() - Create a mirrored named and anonyomous struct
|
||||
*
|
||||
* @TAG: The tag name for the named sub-struct (usually empty)
|
||||
* @NAME: The identifier name of the mirrored sub-struct
|
||||
* @ATTRS: Any struct attributes (usually empty)
|
||||
* @MEMBERS: The member declarations for the mirrored structs
|
||||
*
|
||||
* Used to create an anonymous union of two structs with identical layout
|
||||
* and size: one anonymous and one named. The former's members can be used
|
||||
* normally without sub-struct naming, and the latter can be used to
|
||||
* reason about the start, end, and size of the group of struct members.
|
||||
* The named struct can also be explicitly tagged for layer reuse, as well
|
||||
* as both having struct attributes appended.
|
||||
*/
|
||||
#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
|
||||
union { \
|
||||
struct { MEMBERS } ATTRS; \
|
||||
struct TAG { MEMBERS } ATTRS NAME; \
|
||||
}
|
||||
|
||||
/**
|
||||
* __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
|
||||
*
|
||||
* @TYPE: The type of each flexible array element
|
||||
* @NAME: The name of the flexible array member
|
||||
*
|
||||
* In order to have a flexible array member in a union or alone in a
|
||||
* struct, it needs to be wrapped in an anonymous struct with at least 1
|
||||
* named member, but that member can be empty.
|
||||
*/
|
||||
#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
|
||||
struct { \
|
||||
struct { } __empty_ ## NAME; \
|
||||
TYPE NAME[]; \
|
||||
}
|
||||
|
@ -141,8 +141,8 @@ struct rxe_dma_info {
|
||||
__u32 sge_offset;
|
||||
__u32 reserved;
|
||||
union {
|
||||
__u8 inline_data[0];
|
||||
struct rxe_sge sge[0];
|
||||
__DECLARE_FLEX_ARRAY(__u8, inline_data);
|
||||
__DECLARE_FLEX_ARRAY(struct rxe_sge, sge);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -240,8 +240,8 @@ struct snd_soc_tplg_vendor_array {
|
||||
struct snd_soc_tplg_private {
|
||||
__le32 size; /* in bytes of private data */
|
||||
union {
|
||||
char data[0];
|
||||
struct snd_soc_tplg_vendor_array array[0];
|
||||
__DECLARE_FLEX_ARRAY(char, data);
|
||||
__DECLARE_FLEX_ARRAY(struct snd_soc_tplg_vendor_array, array);
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
|
2
lib/.gitignore
vendored
2
lib/.gitignore
vendored
@ -4,3 +4,5 @@
|
||||
/gen_crc32table
|
||||
/gen_crc64table
|
||||
/oid_registry_data.c
|
||||
/test_fortify.log
|
||||
/test_fortify/*.log
|
||||
|
@ -2452,6 +2452,17 @@ config RATIONAL_KUNIT_TEST
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MEMCPY_KUNIT_TEST
|
||||
tristate "Test memcpy(), memmove(), and memset() functions at runtime" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
Builds unit tests for memcpy(), memmove(), and memset() functions.
|
||||
For more information on KUnit and unit tests in general please refer
|
||||
to the KUnit documentation in Documentation/dev-tools/kunit/.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config TEST_UDELAY
|
||||
tristate "udelay test driver"
|
||||
help
|
||||
|
34
lib/Makefile
34
lib/Makefile
@ -358,5 +358,39 @@ obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
|
||||
obj-$(CONFIG_BITS_TEST) += test_bits.o
|
||||
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
|
||||
obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o
|
||||
obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
|
||||
|
||||
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
|
||||
|
||||
# FORTIFY_SOURCE compile-time behavior tests
|
||||
TEST_FORTIFY_SRCS = $(wildcard $(srctree)/$(src)/test_fortify/*-*.c)
|
||||
TEST_FORTIFY_LOGS = $(patsubst $(srctree)/$(src)/%.c, %.log, $(TEST_FORTIFY_SRCS))
|
||||
TEST_FORTIFY_LOG = test_fortify.log
|
||||
|
||||
quiet_cmd_test_fortify = TEST $@
|
||||
cmd_test_fortify = $(CONFIG_SHELL) $(srctree)/scripts/test_fortify.sh \
|
||||
$< $@ "$(NM)" $(CC) $(c_flags) \
|
||||
$(call cc-disable-warning,fortify-source)
|
||||
|
||||
targets += $(TEST_FORTIFY_LOGS)
|
||||
clean-files += $(TEST_FORTIFY_LOGS)
|
||||
clean-files += $(addsuffix .o, $(TEST_FORTIFY_LOGS))
|
||||
$(obj)/test_fortify/%.log: $(src)/test_fortify/%.c \
|
||||
$(src)/test_fortify/test_fortify.h \
|
||||
$(srctree)/include/linux/fortify-string.h \
|
||||
$(srctree)/scripts/test_fortify.sh \
|
||||
FORCE
|
||||
$(call if_changed,test_fortify)
|
||||
|
||||
quiet_cmd_gen_fortify_log = GEN $@
|
||||
cmd_gen_fortify_log = cat </dev/null $(filter-out FORCE,$^) 2>/dev/null > $@ || true
|
||||
|
||||
targets += $(TEST_FORTIFY_LOG)
|
||||
clean-files += $(TEST_FORTIFY_LOG)
|
||||
$(obj)/$(TEST_FORTIFY_LOG): $(addprefix $(obj)/, $(TEST_FORTIFY_LOGS)) FORCE
|
||||
$(call if_changed,gen_fortify_log)
|
||||
|
||||
# Fake dependency to trigger the fortify tests.
|
||||
ifeq ($(CONFIG_FORTIFY_SOURCE),y)
|
||||
$(obj)/string.o: $(obj)/$(TEST_FORTIFY_LOG)
|
||||
endif
|
||||
|
289
lib/memcpy_kunit.c
Normal file
289
lib/memcpy_kunit.c
Normal file
@ -0,0 +1,289 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Test cases for memcpy(), memmove(), and memset().
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
struct some_bytes {
|
||||
union {
|
||||
u8 data[32];
|
||||
struct {
|
||||
u32 one;
|
||||
u16 two;
|
||||
u8 three;
|
||||
/* 1 byte hole */
|
||||
u32 four[4];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define check(instance, v) do { \
|
||||
int i; \
|
||||
BUILD_BUG_ON(sizeof(instance.data) != 32); \
|
||||
for (i = 0; i < sizeof(instance.data); i++) { \
|
||||
KUNIT_ASSERT_EQ_MSG(test, instance.data[i], v, \
|
||||
"line %d: '%s' not initialized to 0x%02x @ %d (saw 0x%02x)\n", \
|
||||
__LINE__, #instance, v, i, instance.data[i]); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define compare(name, one, two) do { \
|
||||
int i; \
|
||||
BUILD_BUG_ON(sizeof(one) != sizeof(two)); \
|
||||
for (i = 0; i < sizeof(one); i++) { \
|
||||
KUNIT_EXPECT_EQ_MSG(test, one.data[i], two.data[i], \
|
||||
"line %d: %s.data[%d] (0x%02x) != %s.data[%d] (0x%02x)\n", \
|
||||
__LINE__, #one, i, one.data[i], #two, i, two.data[i]); \
|
||||
} \
|
||||
kunit_info(test, "ok: " TEST_OP "() " name "\n"); \
|
||||
} while (0)
|
||||
|
||||
static void memcpy_test(struct kunit *test)
|
||||
{
|
||||
#define TEST_OP "memcpy"
|
||||
struct some_bytes control = {
|
||||
.data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
},
|
||||
};
|
||||
struct some_bytes zero = { };
|
||||
struct some_bytes middle = {
|
||||
.data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
},
|
||||
};
|
||||
struct some_bytes three = {
|
||||
.data = { 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
},
|
||||
};
|
||||
struct some_bytes dest = { };
|
||||
int count;
|
||||
u8 *ptr;
|
||||
|
||||
/* Verify static initializers. */
|
||||
check(control, 0x20);
|
||||
check(zero, 0);
|
||||
compare("static initializers", dest, zero);
|
||||
|
||||
/* Verify assignment. */
|
||||
dest = control;
|
||||
compare("direct assignment", dest, control);
|
||||
|
||||
/* Verify complete overwrite. */
|
||||
memcpy(dest.data, zero.data, sizeof(dest.data));
|
||||
compare("complete overwrite", dest, zero);
|
||||
|
||||
/* Verify middle overwrite. */
|
||||
dest = control;
|
||||
memcpy(dest.data + 12, zero.data, 7);
|
||||
compare("middle overwrite", dest, middle);
|
||||
|
||||
/* Verify argument side-effects aren't repeated. */
|
||||
dest = control;
|
||||
ptr = dest.data;
|
||||
count = 1;
|
||||
memcpy(ptr++, zero.data, count++);
|
||||
ptr += 8;
|
||||
memcpy(ptr++, zero.data, count++);
|
||||
compare("argument side-effects", dest, three);
|
||||
#undef TEST_OP
|
||||
}
|
||||
|
||||
static void memmove_test(struct kunit *test)
|
||||
{
|
||||
#define TEST_OP "memmove"
|
||||
struct some_bytes control = {
|
||||
.data = { 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
},
|
||||
};
|
||||
struct some_bytes zero = { };
|
||||
struct some_bytes middle = {
|
||||
.data = { 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
},
|
||||
};
|
||||
struct some_bytes five = {
|
||||
.data = { 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
},
|
||||
};
|
||||
struct some_bytes overlap = {
|
||||
.data = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
},
|
||||
};
|
||||
struct some_bytes overlap_expected = {
|
||||
.data = { 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||||
},
|
||||
};
|
||||
struct some_bytes dest = { };
|
||||
int count;
|
||||
u8 *ptr;
|
||||
|
||||
/* Verify static initializers. */
|
||||
check(control, 0x99);
|
||||
check(zero, 0);
|
||||
compare("static initializers", zero, dest);
|
||||
|
||||
/* Verify assignment. */
|
||||
dest = control;
|
||||
compare("direct assignment", dest, control);
|
||||
|
||||
/* Verify complete overwrite. */
|
||||
memmove(dest.data, zero.data, sizeof(dest.data));
|
||||
compare("complete overwrite", dest, zero);
|
||||
|
||||
/* Verify middle overwrite. */
|
||||
dest = control;
|
||||
memmove(dest.data + 12, zero.data, 7);
|
||||
compare("middle overwrite", dest, middle);
|
||||
|
||||
/* Verify argument side-effects aren't repeated. */
|
||||
dest = control;
|
||||
ptr = dest.data;
|
||||
count = 2;
|
||||
memmove(ptr++, zero.data, count++);
|
||||
ptr += 9;
|
||||
memmove(ptr++, zero.data, count++);
|
||||
compare("argument side-effects", dest, five);
|
||||
|
||||
/* Verify overlapping overwrite is correct. */
|
||||
ptr = &overlap.data[2];
|
||||
memmove(ptr, overlap.data, 5);
|
||||
compare("overlapping write", overlap, overlap_expected);
|
||||
#undef TEST_OP
|
||||
}
|
||||
|
||||
static void memset_test(struct kunit *test)
|
||||
{
|
||||
#define TEST_OP "memset"
|
||||
struct some_bytes control = {
|
||||
.data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
},
|
||||
};
|
||||
struct some_bytes complete = {
|
||||
.data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
};
|
||||
struct some_bytes middle = {
|
||||
.data = { 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
|
||||
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
|
||||
0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
},
|
||||
};
|
||||
struct some_bytes three = {
|
||||
.data = { 0x60, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x61, 0x61, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
},
|
||||
};
|
||||
struct some_bytes after = {
|
||||
.data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x72,
|
||||
0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
|
||||
0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
|
||||
0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
|
||||
},
|
||||
};
|
||||
struct some_bytes startat = {
|
||||
.data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
|
||||
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
|
||||
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
|
||||
},
|
||||
};
|
||||
struct some_bytes dest = { };
|
||||
int count, value;
|
||||
u8 *ptr;
|
||||
|
||||
/* Verify static initializers. */
|
||||
check(control, 0x30);
|
||||
check(dest, 0);
|
||||
|
||||
/* Verify assignment. */
|
||||
dest = control;
|
||||
compare("direct assignment", dest, control);
|
||||
|
||||
/* Verify complete overwrite. */
|
||||
memset(dest.data, 0xff, sizeof(dest.data));
|
||||
compare("complete overwrite", dest, complete);
|
||||
|
||||
/* Verify middle overwrite. */
|
||||
dest = control;
|
||||
memset(dest.data + 4, 0x31, 16);
|
||||
compare("middle overwrite", dest, middle);
|
||||
|
||||
/* Verify argument side-effects aren't repeated. */
|
||||
dest = control;
|
||||
ptr = dest.data;
|
||||
value = 0x60;
|
||||
count = 1;
|
||||
memset(ptr++, value++, count++);
|
||||
ptr += 8;
|
||||
memset(ptr++, value++, count++);
|
||||
compare("argument side-effects", dest, three);
|
||||
|
||||
/* Verify memset_after() */
|
||||
dest = control;
|
||||
memset_after(&dest, 0x72, three);
|
||||
compare("memset_after()", dest, after);
|
||||
|
||||
/* Verify memset_startat() */
|
||||
dest = control;
|
||||
memset_startat(&dest, 0x79, four);
|
||||
compare("memset_startat()", dest, startat);
|
||||
#undef TEST_OP
|
||||
}
|
||||
|
||||
static struct kunit_case memcpy_test_cases[] = {
|
||||
KUNIT_CASE(memset_test),
|
||||
KUNIT_CASE(memcpy_test),
|
||||
KUNIT_CASE(memmove_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite memcpy_test_suite = {
|
||||
.name = "memcpy",
|
||||
.test_cases = memcpy_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(memcpy_test_suite);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
210
lib/string.c
210
lib/string.c
@ -6,20 +6,15 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* stupid library routines.. The optimized versions should generally be found
|
||||
* as inline code in <asm-xx/string.h>
|
||||
* This file should be used only for "library" routines that may have
|
||||
* alternative implementations on specific architectures (generally
|
||||
* found in <asm-xx/string.h>), or get overloaded by FORTIFY_SOURCE.
|
||||
* (Specifically, this file is built with __NO_FORTIFY.)
|
||||
*
|
||||
* These are buggy as well..
|
||||
*
|
||||
* * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
|
||||
* - Added strsep() which will replace strtok() soon (because strsep() is
|
||||
* reentrant and should be faster). Use only strsep() in new code, please.
|
||||
*
|
||||
* * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
|
||||
* Matthew Hawkins <matt@mh.dropbear.id.au>
|
||||
* - Kissed strtok() goodbye
|
||||
* Other helper functions should live in string_helpers.c.
|
||||
*/
|
||||
|
||||
#define __NO_FORTIFY
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
@ -238,40 +233,6 @@ ssize_t strscpy(char *dest, const char *src, size_t count)
|
||||
EXPORT_SYMBOL(strscpy);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* strscpy_pad() - Copy a C-string into a sized buffer
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
* @count: Size of destination buffer
|
||||
*
|
||||
* Copy the string, or as much of it as fits, into the dest buffer. The
|
||||
* behavior is undefined if the string buffers overlap. The destination
|
||||
* buffer is always %NUL terminated, unless it's zero-sized.
|
||||
*
|
||||
* If the source string is shorter than the destination buffer, zeros
|
||||
* the tail of the destination buffer.
|
||||
*
|
||||
* For full explanation of why you may want to consider using the
|
||||
* 'strscpy' functions please see the function docstring for strscpy().
|
||||
*
|
||||
* Returns:
|
||||
* * The number of characters copied (not including the trailing %NUL)
|
||||
* * -E2BIG if count is 0 or @src was truncated.
|
||||
*/
|
||||
ssize_t strscpy_pad(char *dest, const char *src, size_t count)
|
||||
{
|
||||
ssize_t written;
|
||||
|
||||
written = strscpy(dest, src, count);
|
||||
if (written < 0 || written == count - 1)
|
||||
return written;
|
||||
|
||||
memset(dest + written + 1, 0, count - written - 1);
|
||||
|
||||
return written;
|
||||
}
|
||||
EXPORT_SYMBOL(strscpy_pad);
|
||||
|
||||
/**
|
||||
* stpcpy - copy a string from src to dest returning a pointer to the new end
|
||||
* of dest, including src's %NUL-terminator. May overrun dest.
|
||||
@ -514,46 +475,6 @@ char *strnchr(const char *s, size_t count, int c)
|
||||
EXPORT_SYMBOL(strnchr);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* skip_spaces - Removes leading whitespace from @str.
|
||||
* @str: The string to be stripped.
|
||||
*
|
||||
* Returns a pointer to the first non-whitespace character in @str.
|
||||
*/
|
||||
char *skip_spaces(const char *str)
|
||||
{
|
||||
while (isspace(*str))
|
||||
++str;
|
||||
return (char *)str;
|
||||
}
|
||||
EXPORT_SYMBOL(skip_spaces);
|
||||
|
||||
/**
|
||||
* strim - Removes leading and trailing whitespace from @s.
|
||||
* @s: The string to be stripped.
|
||||
*
|
||||
* Note that the first trailing whitespace is replaced with a %NUL-terminator
|
||||
* in the given string @s. Returns a pointer to the first non-whitespace
|
||||
* character in @s.
|
||||
*/
|
||||
char *strim(char *s)
|
||||
{
|
||||
size_t size;
|
||||
char *end;
|
||||
|
||||
size = strlen(s);
|
||||
if (!size)
|
||||
return s;
|
||||
|
||||
end = s + size - 1;
|
||||
while (end >= s && isspace(*end))
|
||||
end--;
|
||||
*(end + 1) = '\0';
|
||||
|
||||
return skip_spaces(s);
|
||||
}
|
||||
EXPORT_SYMBOL(strim);
|
||||
|
||||
#ifndef __HAVE_ARCH_STRLEN
|
||||
/**
|
||||
* strlen - Find the length of a string
|
||||
@ -688,101 +609,6 @@ char *strsep(char **s, const char *ct)
|
||||
EXPORT_SYMBOL(strsep);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sysfs_streq - return true if strings are equal, modulo trailing newline
|
||||
* @s1: one string
|
||||
* @s2: another string
|
||||
*
|
||||
* This routine returns true iff two strings are equal, treating both
|
||||
* NUL and newline-then-NUL as equivalent string terminations. It's
|
||||
* geared for use with sysfs input strings, which generally terminate
|
||||
* with newlines but are compared against values without newlines.
|
||||
*/
|
||||
bool sysfs_streq(const char *s1, const char *s2)
|
||||
{
|
||||
while (*s1 && *s1 == *s2) {
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
||||
if (*s1 == *s2)
|
||||
return true;
|
||||
if (!*s1 && *s2 == '\n' && !s2[1])
|
||||
return true;
|
||||
if (*s1 == '\n' && !s1[1] && !*s2)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(sysfs_streq);
|
||||
|
||||
/**
|
||||
* match_string - matches given string in an array
|
||||
* @array: array of strings
|
||||
* @n: number of strings in the array or -1 for NULL terminated arrays
|
||||
* @string: string to match with
|
||||
*
|
||||
* This routine will look for a string in an array of strings up to the
|
||||
* n-th element in the array or until the first NULL element.
|
||||
*
|
||||
* Historically the value of -1 for @n, was used to search in arrays that
|
||||
* are NULL terminated. However, the function does not make a distinction
|
||||
* when finishing the search: either @n elements have been compared OR
|
||||
* the first NULL element was found.
|
||||
*
|
||||
* Return:
|
||||
* index of a @string in the @array if matches, or %-EINVAL otherwise.
|
||||
*/
|
||||
int match_string(const char * const *array, size_t n, const char *string)
|
||||
{
|
||||
int index;
|
||||
const char *item;
|
||||
|
||||
for (index = 0; index < n; index++) {
|
||||
item = array[index];
|
||||
if (!item)
|
||||
break;
|
||||
if (!strcmp(item, string))
|
||||
return index;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(match_string);
|
||||
|
||||
/**
|
||||
* __sysfs_match_string - matches given string in an array
|
||||
* @array: array of strings
|
||||
* @n: number of strings in the array or -1 for NULL terminated arrays
|
||||
* @str: string to match with
|
||||
*
|
||||
* Returns index of @str in the @array or -EINVAL, just like match_string().
|
||||
* Uses sysfs_streq instead of strcmp for matching.
|
||||
*
|
||||
* This routine will look for a string in an array of strings up to the
|
||||
* n-th element in the array or until the first NULL element.
|
||||
*
|
||||
* Historically the value of -1 for @n, was used to search in arrays that
|
||||
* are NULL terminated. However, the function does not make a distinction
|
||||
* when finishing the search: either @n elements have been compared OR
|
||||
* the first NULL element was found.
|
||||
*/
|
||||
int __sysfs_match_string(const char * const *array, size_t n, const char *str)
|
||||
{
|
||||
const char *item;
|
||||
int index;
|
||||
|
||||
for (index = 0; index < n; index++) {
|
||||
item = array[index];
|
||||
if (!item)
|
||||
break;
|
||||
if (sysfs_streq(item, str))
|
||||
return index;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(__sysfs_match_string);
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMSET
|
||||
/**
|
||||
* memset - Fill a region of memory with the given value
|
||||
@ -1141,27 +967,3 @@ void *memchr_inv(const void *start, int c, size_t bytes)
|
||||
return check_bytes8(start, value, bytes % 8);
|
||||
}
|
||||
EXPORT_SYMBOL(memchr_inv);
|
||||
|
||||
/**
|
||||
* strreplace - Replace all occurrences of character in string.
|
||||
* @s: 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.
|
||||
*/
|
||||
char *strreplace(char *s, char old, char new)
|
||||
{
|
||||
for (; *s; ++s)
|
||||
if (*s == old)
|
||||
*s = new;
|
||||
return s;
|
||||
}
|
||||
EXPORT_SYMBOL(strreplace);
|
||||
|
||||
void fortify_panic(const char *name)
|
||||
{
|
||||
pr_emerg("detected buffer overflow in %s\n", name);
|
||||
BUG();
|
||||
}
|
||||
EXPORT_SYMBOL(fortify_panic);
|
||||
|
@ -696,3 +696,198 @@ void kfree_strarray(char **array, size_t n)
|
||||
kfree(array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kfree_strarray);
|
||||
|
||||
/**
|
||||
* strscpy_pad() - Copy a C-string into a sized buffer
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
* @count: Size of destination buffer
|
||||
*
|
||||
* Copy the string, or as much of it as fits, into the dest buffer. The
|
||||
* behavior is undefined if the string buffers overlap. The destination
|
||||
* buffer is always %NUL terminated, unless it's zero-sized.
|
||||
*
|
||||
* If the source string is shorter than the destination buffer, zeros
|
||||
* the tail of the destination buffer.
|
||||
*
|
||||
* For full explanation of why you may want to consider using the
|
||||
* 'strscpy' functions please see the function docstring for strscpy().
|
||||
*
|
||||
* Returns:
|
||||
* * The number of characters copied (not including the trailing %NUL)
|
||||
* * -E2BIG if count is 0 or @src was truncated.
|
||||
*/
|
||||
ssize_t strscpy_pad(char *dest, const char *src, size_t count)
|
||||
{
|
||||
ssize_t written;
|
||||
|
||||
written = strscpy(dest, src, count);
|
||||
if (written < 0 || written == count - 1)
|
||||
return written;
|
||||
|
||||
memset(dest + written + 1, 0, count - written - 1);
|
||||
|
||||
return written;
|
||||
}
|
||||
EXPORT_SYMBOL(strscpy_pad);
|
||||
|
||||
/**
|
||||
* skip_spaces - Removes leading whitespace from @str.
|
||||
* @str: The string to be stripped.
|
||||
*
|
||||
* Returns a pointer to the first non-whitespace character in @str.
|
||||
*/
|
||||
char *skip_spaces(const char *str)
|
||||
{
|
||||
while (isspace(*str))
|
||||
++str;
|
||||
return (char *)str;
|
||||
}
|
||||
EXPORT_SYMBOL(skip_spaces);
|
||||
|
||||
/**
|
||||
* strim - Removes leading and trailing whitespace from @s.
|
||||
* @s: The string to be stripped.
|
||||
*
|
||||
* Note that the first trailing whitespace is replaced with a %NUL-terminator
|
||||
* in the given string @s. Returns a pointer to the first non-whitespace
|
||||
* character in @s.
|
||||
*/
|
||||
char *strim(char *s)
|
||||
{
|
||||
size_t size;
|
||||
char *end;
|
||||
|
||||
size = strlen(s);
|
||||
if (!size)
|
||||
return s;
|
||||
|
||||
end = s + size - 1;
|
||||
while (end >= s && isspace(*end))
|
||||
end--;
|
||||
*(end + 1) = '\0';
|
||||
|
||||
return skip_spaces(s);
|
||||
}
|
||||
EXPORT_SYMBOL(strim);
|
||||
|
||||
/**
|
||||
* sysfs_streq - return true if strings are equal, modulo trailing newline
|
||||
* @s1: one string
|
||||
* @s2: another string
|
||||
*
|
||||
* This routine returns true iff two strings are equal, treating both
|
||||
* NUL and newline-then-NUL as equivalent string terminations. It's
|
||||
* geared for use with sysfs input strings, which generally terminate
|
||||
* with newlines but are compared against values without newlines.
|
||||
*/
|
||||
bool sysfs_streq(const char *s1, const char *s2)
|
||||
{
|
||||
while (*s1 && *s1 == *s2) {
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
||||
if (*s1 == *s2)
|
||||
return true;
|
||||
if (!*s1 && *s2 == '\n' && !s2[1])
|
||||
return true;
|
||||
if (*s1 == '\n' && !s1[1] && !*s2)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(sysfs_streq);
|
||||
|
||||
/**
|
||||
* match_string - matches given string in an array
|
||||
* @array: array of strings
|
||||
* @n: number of strings in the array or -1 for NULL terminated arrays
|
||||
* @string: string to match with
|
||||
*
|
||||
* This routine will look for a string in an array of strings up to the
|
||||
* n-th element in the array or until the first NULL element.
|
||||
*
|
||||
* Historically the value of -1 for @n, was used to search in arrays that
|
||||
* are NULL terminated. However, the function does not make a distinction
|
||||
* when finishing the search: either @n elements have been compared OR
|
||||
* the first NULL element was found.
|
||||
*
|
||||
* Return:
|
||||
* index of a @string in the @array if matches, or %-EINVAL otherwise.
|
||||
*/
|
||||
int match_string(const char * const *array, size_t n, const char *string)
|
||||
{
|
||||
int index;
|
||||
const char *item;
|
||||
|
||||
for (index = 0; index < n; index++) {
|
||||
item = array[index];
|
||||
if (!item)
|
||||
break;
|
||||
if (!strcmp(item, string))
|
||||
return index;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(match_string);
|
||||
|
||||
/**
|
||||
* __sysfs_match_string - matches given string in an array
|
||||
* @array: array of strings
|
||||
* @n: number of strings in the array or -1 for NULL terminated arrays
|
||||
* @str: string to match with
|
||||
*
|
||||
* Returns index of @str in the @array or -EINVAL, just like match_string().
|
||||
* Uses sysfs_streq instead of strcmp for matching.
|
||||
*
|
||||
* This routine will look for a string in an array of strings up to the
|
||||
* n-th element in the array or until the first NULL element.
|
||||
*
|
||||
* Historically the value of -1 for @n, was used to search in arrays that
|
||||
* are NULL terminated. However, the function does not make a distinction
|
||||
* when finishing the search: either @n elements have been compared OR
|
||||
* the first NULL element was found.
|
||||
*/
|
||||
int __sysfs_match_string(const char * const *array, size_t n, const char *str)
|
||||
{
|
||||
const char *item;
|
||||
int index;
|
||||
|
||||
for (index = 0; index < n; index++) {
|
||||
item = array[index];
|
||||
if (!item)
|
||||
break;
|
||||
if (sysfs_streq(item, str))
|
||||
return index;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(__sysfs_match_string);
|
||||
|
||||
/**
|
||||
* strreplace - Replace all occurrences of character in string.
|
||||
* @s: 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.
|
||||
*/
|
||||
char *strreplace(char *s, char old, char new)
|
||||
{
|
||||
for (; *s; ++s)
|
||||
if (*s == old)
|
||||
*s = new;
|
||||
return s;
|
||||
}
|
||||
EXPORT_SYMBOL(strreplace);
|
||||
|
||||
#ifdef CONFIG_FORTIFY_SOURCE
|
||||
void fortify_panic(const char *name)
|
||||
{
|
||||
pr_emerg("detected buffer overflow in %s\n", name);
|
||||
BUG();
|
||||
}
|
||||
EXPORT_SYMBOL(fortify_panic);
|
||||
#endif /* CONFIG_FORTIFY_SOURCE */
|
||||
|
5
lib/test_fortify/read_overflow-memchr.c
Normal file
5
lib/test_fortify/read_overflow-memchr.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memchr(small, 0x7A, sizeof(small) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/read_overflow-memchr_inv.c
Normal file
5
lib/test_fortify/read_overflow-memchr_inv.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memchr_inv(small, 0x7A, sizeof(small) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/read_overflow-memcmp.c
Normal file
5
lib/test_fortify/read_overflow-memcmp.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memcmp(small, large, sizeof(small) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/read_overflow-memscan.c
Normal file
5
lib/test_fortify/read_overflow-memscan.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memscan(small, 0x7A, sizeof(small) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/read_overflow2-memcmp.c
Normal file
5
lib/test_fortify/read_overflow2-memcmp.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memcmp(large, small, sizeof(small) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/read_overflow2-memcpy.c
Normal file
5
lib/test_fortify/read_overflow2-memcpy.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memcpy(large, instance.buf, sizeof(large))
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/read_overflow2-memmove.c
Normal file
5
lib/test_fortify/read_overflow2-memmove.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memmove(large, instance.buf, sizeof(large))
|
||||
|
||||
#include "test_fortify.h"
|
35
lib/test_fortify/test_fortify.h
Normal file
35
lib/test_fortify/test_fortify.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
void do_fortify_tests(void);
|
||||
|
||||
#define __BUF_SMALL 16
|
||||
#define __BUF_LARGE 32
|
||||
struct fortify_object {
|
||||
int a;
|
||||
char buf[__BUF_SMALL];
|
||||
int c;
|
||||
};
|
||||
|
||||
#define LITERAL_SMALL "AAAAAAAAAAAAAAA"
|
||||
#define LITERAL_LARGE "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
const char small_src[__BUF_SMALL] = LITERAL_SMALL;
|
||||
const char large_src[__BUF_LARGE] = LITERAL_LARGE;
|
||||
|
||||
char small[__BUF_SMALL];
|
||||
char large[__BUF_LARGE];
|
||||
struct fortify_object instance;
|
||||
size_t size;
|
||||
|
||||
void do_fortify_tests(void)
|
||||
{
|
||||
/* Normal initializations. */
|
||||
memset(&instance, 0x32, sizeof(instance));
|
||||
memset(small, 0xA5, sizeof(small));
|
||||
memset(large, 0x5A, sizeof(large));
|
||||
|
||||
TEST;
|
||||
}
|
5
lib/test_fortify/write_overflow-memcpy.c
Normal file
5
lib/test_fortify/write_overflow-memcpy.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memcpy(instance.buf, large_src, sizeof(large_src))
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-memmove.c
Normal file
5
lib/test_fortify/write_overflow-memmove.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memmove(instance.buf, large_src, sizeof(large_src))
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-memset.c
Normal file
5
lib/test_fortify/write_overflow-memset.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
memset(instance.buf, 0x5A, sizeof(large_src))
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-strcpy-lit.c
Normal file
5
lib/test_fortify/write_overflow-strcpy-lit.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
strcpy(small, LITERAL_LARGE)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-strcpy.c
Normal file
5
lib/test_fortify/write_overflow-strcpy.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
strcpy(small, large_src)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-strlcpy-src.c
Normal file
5
lib/test_fortify/write_overflow-strlcpy-src.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
strlcpy(small, large_src, sizeof(small) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-strlcpy.c
Normal file
5
lib/test_fortify/write_overflow-strlcpy.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
strlcpy(instance.buf, large_src, sizeof(instance.buf) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-strncpy-src.c
Normal file
5
lib/test_fortify/write_overflow-strncpy-src.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
strncpy(small, large_src, sizeof(small) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-strncpy.c
Normal file
5
lib/test_fortify/write_overflow-strncpy.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
strncpy(instance.buf, large_src, sizeof(instance.buf) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
5
lib/test_fortify/write_overflow-strscpy.c
Normal file
5
lib/test_fortify/write_overflow-strscpy.c
Normal file
@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define TEST \
|
||||
strscpy(instance.buf, large_src, sizeof(instance.buf) + 1)
|
||||
|
||||
#include "test_fortify.h"
|
@ -2486,9 +2486,7 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
|
||||
xdst = dst_alloc(dst_ops, NULL, 1, DST_OBSOLETE_NONE, 0);
|
||||
|
||||
if (likely(xdst)) {
|
||||
struct dst_entry *dst = &xdst->u.dst;
|
||||
|
||||
memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst));
|
||||
memset_after(xdst, 0, u.dst);
|
||||
} else
|
||||
xdst = ERR_PTR(-ENOBUFS);
|
||||
|
||||
|
@ -2955,7 +2955,7 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct
|
||||
copy_to_user_state(x, &ue->state);
|
||||
ue->hard = (c->data.hard != 0) ? 1 : 0;
|
||||
/* clear the padding bytes */
|
||||
memset(&ue->hard + 1, 0, sizeof(*ue) - offsetofend(typeof(*ue), hard));
|
||||
memset_after(ue, 0, hard);
|
||||
|
||||
err = xfrm_mark_put(skb, &x->mark);
|
||||
if (err)
|
||||
|
@ -1245,6 +1245,13 @@ sub dump_struct($$) {
|
||||
$members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
|
||||
$members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
|
||||
$members =~ s/\s*____cacheline_aligned/ /gos;
|
||||
# unwrap struct_group():
|
||||
# - first eat non-declaration parameters and rewrite for final match
|
||||
# - then remove macro, outer parens, and trailing semicolon
|
||||
$members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos;
|
||||
$members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos;
|
||||
$members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos;
|
||||
$members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos;
|
||||
|
||||
my $args = qr{([^,)]+)};
|
||||
# replace DECLARE_BITMAP
|
||||
@ -1256,6 +1263,8 @@ sub dump_struct($$) {
|
||||
$members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos;
|
||||
# replace DECLARE_KFIFO_PTR
|
||||
$members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos;
|
||||
# replace DECLARE_FLEX_ARRAY
|
||||
$members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos;
|
||||
my $declaration = $members;
|
||||
|
||||
# Split nested struct/union elements as newer ones
|
||||
|
62
scripts/test_fortify.sh
Normal file
62
scripts/test_fortify.sh
Normal file
@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
set -e
|
||||
|
||||
# Argument 1: Source file to build.
|
||||
IN="$1"
|
||||
shift
|
||||
# Extract just the filename for error messages below.
|
||||
FILE="${IN##*/}"
|
||||
# Extract the function name for error messages below.
|
||||
FUNC="${FILE#*-}"
|
||||
FUNC="${FUNC%%-*}"
|
||||
FUNC="${FUNC%%.*}"
|
||||
# Extract the symbol to test for in build/symbol test below.
|
||||
WANT="__${FILE%%-*}"
|
||||
|
||||
# Argument 2: Where to write the build log.
|
||||
OUT="$1"
|
||||
shift
|
||||
TMP="${OUT}.tmp"
|
||||
|
||||
# Argument 3: Path to "nm" tool.
|
||||
NM="$1"
|
||||
shift
|
||||
|
||||
# Remaining arguments are: $(CC) $(c_flags)
|
||||
|
||||
# Clean up temporary file at exit.
|
||||
__cleanup() {
|
||||
rm -f "$TMP"
|
||||
}
|
||||
trap __cleanup EXIT
|
||||
|
||||
# Function names in warnings are wrapped in backticks under UTF-8 locales.
|
||||
# Run the commands with LANG=C so that grep output will not change.
|
||||
export LANG=C
|
||||
|
||||
status=
|
||||
# Attempt to build a source that is expected to fail with a specific warning.
|
||||
if "$@" -Werror -c "$IN" -o "$OUT".o 2> "$TMP" ; then
|
||||
# If the build succeeds, either the test has failed or the
|
||||
# warning may only happen at link time (Clang). In that case,
|
||||
# make sure the expected symbol is unresolved in the symbol list.
|
||||
# If so, FORTIFY is working for this case.
|
||||
if ! $NM -A "$OUT".o | grep -m1 "\bU ${WANT}$" >>"$TMP" ; then
|
||||
status="warning: unsafe ${FUNC}() usage lacked '$WANT' symbol in $IN"
|
||||
fi
|
||||
else
|
||||
# If the build failed, check for the warning in the stderr (gcc).
|
||||
if ! grep -q -m1 "error: call to .\b${WANT}\b." "$TMP" ; then
|
||||
status="warning: unsafe ${FUNC}() usage lacked '$WANT' warning in $IN"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$status" ]; then
|
||||
# Report on failure results, including compilation warnings.
|
||||
echo "$status" | tee "$OUT" >&2
|
||||
else
|
||||
# Report on good results, and save any compilation output to log.
|
||||
echo "ok: unsafe ${FUNC}() usage correctly detected with '$WANT' in $IN" >"$OUT"
|
||||
fi
|
||||
cat "$TMP" >>"$OUT"
|
@ -191,6 +191,9 @@ config HARDENED_USERCOPY_PAGESPAN
|
||||
config FORTIFY_SOURCE
|
||||
bool "Harden common str/mem functions against buffer overflows"
|
||||
depends on ARCH_HAS_FORTIFY_SOURCE
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=50322
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=41459
|
||||
depends on !CC_IS_CLANG
|
||||
help
|
||||
Detect overflows of buffers in common string and memory functions
|
||||
where the compiler can determine and validate the buffer sizes.
|
||||
|
Loading…
Reference in New Issue
Block a user