Merge 2dc26d98cf
("Merge tag 'overflow-v5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux") into android-mainline
Steps on the way to 5.16-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I32df718915dd04028cd2d1b3e299f6ece81afc29
This commit is contained in:
commit
1f3e65794a
@ -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);
|
||||
|
||||
|
@ -2958,7 +2958,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