Introduce strict memcpy() bounds checking
Subsystems (62)
cover Introduce strict memcpy() bounds checking
Hi,
This patch series (based on next-20210726) implements stricter (no struct member overflows) bounds checking for memcpy(), memmove(), and memset() under CONFIG_FORTIFY_SOURCE. To quote a later patch in the series:
tl;dr: In order to eliminate a large class of common buffer overflow flaws that continue to persist in the kernel, have memcpy() (under CONFIG_FORTIFY_SOURCE) perform bounds checking of the destination struct member when they have a known size. This would have caught all of the memcpy()-related buffer write overflow flaws identified in at least the last three years.
As this series introduces various helpers and performs several phases of treewide cleanups, I'm expecting to carry this series in my tree, so I'd love to get some Reviews and Acks. Given the size, I've mostly aimed this series at various mailing lists, otherwise the CC size got really big. :)
Specifically, this series is logically split into several steps:
Clean up remaining simple compile-time memcpy() warnings:
media: omap3isp: Extract struct group for memcpy() region
mac80211: Use flex-array for radiotap header bitmap
rpmsg: glink: Replace strncpy() with strscpy_pad()
Introduce struct_group() and apply it treewide to avoid compile-time memcpy() warnings:
stddef: Introduce struct_group() helper macro
skbuff: Switch structure bounds to struct_group()
bnxt_en: Use struct_group_attr() for memcpy() region
staging: rtl8192e: Use struct_group() for memcpy() region
staging: rtl8192u: Use struct_group() for memcpy() region
staging: rtl8723bs: Avoid field-overflowing memcpy()
lib80211: Use struct_group() for memcpy() region
net/mlx5e: Avoid field-overflowing memcpy()
mwl8k: Use struct_group() for memcpy() region
libertas: Use struct_group() for memcpy() region
libertas_tf: Use struct_group() for memcpy() region
ipw2x00: Use struct_group() for memcpy() region
thermal: intel: int340x_thermal: Use struct_group() for memcpy() region iommu/amd: Use struct_group() for memcpy() region
cxgb3: Use struct_group() for memcpy() region
ip: Use struct_group() for memcpy() regions
intersil: Use struct_group() for memcpy() region
cxgb4: Use struct_group() for memcpy() region
bnx2x: Use struct_group() for memcpy() region
drm/amd/pm: Use struct_group() for memcpy() region
staging: wlan-ng: Use struct_group() for memcpy() region drm/mga/mga_ioc32: Use struct_group() for memcpy() region net/mlx5e: Use struct_group() for memcpy() region
HID: cp2112: Use struct_group() for memcpy() region
Prepare fortify for additional hardening:
compiler_types.h: Remove __compiletime_object_size() lib/string: Move helper functions out of string.c
fortify: Move remaining fortify helpers into fortify-string.h
fortify: Explicitly disable Clang support
Add compile-time and run-time tests:
fortify: Add compile-time FORTIFY_SOURCE tests
lib: Introduce CONFIG_TEST_MEMCPY
Enable new compile-time memcpy() and memmove() bounds checking:
fortify: Detect struct member overflows in memcpy() at compile-time
fortify: Detect struct member overflows in memmove() at compile-time
Clean up remaining simple compile-time memset() warnings:
scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp
Introduce memset_after() helper and apply it (and struct_group()) treewide to avoid compile-time memset() warnings:
string.h: Introduce memset_after() for wiping trailing members/padding
xfrm: Use memset_after() to clear padding
mac80211: Use memset_after() to clear tx status
net: 802: Use memset_after() to clear struct fields
net: dccp: Use memset_after() for TP zeroing
net: qede: Use memset_after() for counters
ath11k: Use memset_after() for clearing queue descriptors
iw_cxgb4: Use memset_after() for cpl_t5_pass_accept_rpl
intel_th: msu: Use memset_after() for clearing hw header IB/mthca: Use memset_after() for clearing mpt_entry
btrfs: Use memset_after() to clear end of struct
drbd: Use struct_group() to zero algs
cm4000_cs: Use struct_group() to zero struct cm4000_dev region
KVM: x86: Use struct_group() to zero decode cache
tracing: Use struct_group() to zero struct trace_iterator dm integrity: Use struct_group() to zero struct journal_sector
HID: roccat: Use struct_group() to zero kone_mouse_event
ipv6: Use struct_group() to zero rt6_info
RDMA/mlx5: Use struct_group() to zero struct mlx5_ib_mr
ethtool: stats: Use struct_group() to clear all stats at once
netfilter: conntrack: Use struct_group() to zero struct nf_conn
powerpc: Split memset() to avoid multi-field overflow
Enable new compile-time memset() bounds checking:
fortify: Detect struct member overflows in memset() at compile-time
Enable Clang support and global array-bounds checking:
fortify: Work around Clang inlining bugs
Makefile: Enable -Warray-bounds
Avoid run-time memcpy() bounds check warnings:
netlink: Avoid false-positive memcpy() warning
iwlwifi: dbg_ini: Split memcpy() to avoid multi-field write
Enable run-time memcpy() bounds checking:
fortify: Add run-time WARN for cross-field memcpy()
A future series will clean up for and add run-time memset() bounds checking.
Thanks!
-Kees
Makefile | 1 - arch/s390/lib/string.c | 3 + arch/x86/boot/compressed/misc.c | 3 +- arch/x86/kvm/emulate.c | 3 +- arch/x86/kvm/kvm_emulate.h | 19 +- arch/x86/lib/memcpy_32.c | 1 + arch/x86/lib/string_32.c | 1 + drivers/block/drbd/drbd_main.c | 3 +- drivers/block/drbd/drbd_protocol.h | 6 +- drivers/block/drbd/drbd_receiver.c | 3 +- drivers/char/pcmcia/cm4000_cs.c | 9 +- drivers/gpu/drm/amd/include/atomfirmware.h | 9 +- .../drm/amd/pm/inc/smu11_driver_if_arcturus.h | 3 +- .../drm/amd/pm/inc/smu11_driver_if_navi10.h | 3 +- .../amd/pm/inc/smu13_driver_if_aldebaran.h | 3 +- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 6 +- .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 12 +- .../drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 6 +- drivers/gpu/drm/mga/mga_ioc32.c | 30 +- drivers/hid/hid-cp2112.c | 14 +- drivers/hid/hid-roccat-kone.c | 2 +- drivers/hid/hid-roccat-kone.h | 12 +- drivers/hwtracing/intel_th/msu.c | 4 +- drivers/infiniband/hw/cxgb4/cm.c | 5 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +- drivers/infiniband/hw/mthca/mthca_mr.c | 3 +- drivers/iommu/amd/init.c | 9 +- drivers/macintosh/smu.c | 3 +- drivers/md/dm-integrity.c | 9 +- drivers/media/platform/omap3isp/ispstat.c | 5 +- .../net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 7 +- .../net/ethernet/broadcom/bnx2x/bnx2x_stats.h | 14 +- drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c | 4 +- drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h | 14 +- drivers/net/ethernet/chelsio/cxgb3/sge.c | 9 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 8 +- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 10 +- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 7 +- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 +- .../net/ethernet/mellanox/mlx5/core/en/xdp.c | 4 +- .../net/ethernet/mellanox/mlx5/core/en_tx.c | 2 +- drivers/net/ethernet/qlogic/qede/qede_main.c | 2 +- drivers/net/wireguard/queueing.h | 4 +- drivers/net/wireless/ath/ath11k/hal_rx.c | 13 +- drivers/net/wireless/ath/carl9170/tx.c | 4 +- drivers/net/wireless/intel/ipw2x00/libipw.h | 12 +- .../net/wireless/intel/ipw2x00/libipw_rx.c | 8 +- drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 +- .../net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 3 +- .../net/wireless/intersil/hostap/hostap_hw.c | 5 +- .../wireless/intersil/hostap/hostap_wlan.h | 14 +- drivers/net/wireless/intersil/p54/txrx.c | 4 +- drivers/net/wireless/marvell/libertas/host.h | 10 +- drivers/net/wireless/marvell/libertas/tx.c | 5 +- .../marvell/libertas_tf/libertas_tf.h | 10 +- .../net/wireless/marvell/libertas_tf/main.c | 3 +- drivers/net/wireless/marvell/mwl8k.c | 10 +- drivers/rpmsg/qcom_glink_native.c | 2 +- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 20 +- drivers/staging/rtl8192e/rtllib_crypt_ccmp.c | 3 +- drivers/staging/rtl8192e/rtllib_rx.c | 8 +- .../staging/rtl8192u/ieee80211/ieee80211.h | 24 +- .../rtl8192u/ieee80211/ieee80211_crypt_ccmp.c | 3 +- .../staging/rtl8192u/ieee80211/ieee80211_rx.c | 8 +- drivers/staging/rtl8723bs/core/rtw_mlme.c | 2 +- drivers/staging/rtl8723bs/core/rtw_security.c | 5 +- drivers/staging/rtl8723bs/core/rtw_xmit.c | 5 +- drivers/staging/wlan-ng/hfa384x.h | 16 +- drivers/staging/wlan-ng/hfa384x_usb.c | 4 +- .../intel/int340x_thermal/acpi_thermal_rel.c | 5 +- .../intel/int340x_thermal/acpi_thermal_rel.h | 48 +-- fs/btrfs/root-tree.c | 5 +- include/linux/compiler-gcc.h | 2 - include/linux/compiler_types.h | 4 - include/linux/fortify-string.h | 234 +++++++++++--- include/linux/ieee80211.h | 8 +- include/linux/if_vlan.h | 6 +- include/linux/skbuff.h | 9 +- include/linux/stddef.h | 34 ++ include/linux/string.h | 26 +- include/linux/thread_info.h | 2 +- include/linux/trace_events.h | 26 +- include/net/flow.h | 6 +- include/net/ieee80211_radiotap.h | 24 +- include/net/ip6_fib.h | 30 +- include/net/mac80211.h | 4 +- include/net/netfilter/nf_conntrack.h | 20 +- include/uapi/drm/mga_drm.h | 37 ++- include/uapi/linux/if_ether.h | 12 +- include/uapi/linux/ip.h | 12 +- include/uapi/linux/ipv6.h | 12 +- include/uapi/linux/netlink.h | 1 + include/uapi/linux/omap3isp.h | 44 ++- kernel/trace/trace.c | 4 +- lib/.gitignore | 2 + lib/Kconfig.debug | 3 + lib/Makefile | 32 ++ lib/string.c | 210 +------------ lib/string_helpers.c | 201 ++++++++++++ lib/test_fortify/read_overflow-memchr.c | 5 + lib/test_fortify/read_overflow-memchr_inv.c | 5 + lib/test_fortify/read_overflow-memcmp.c | 5 + lib/test_fortify/read_overflow-memscan.c | 5 + lib/test_fortify/read_overflow2-memcmp.c | 5 + lib/test_fortify/read_overflow2-memcpy.c | 5 + lib/test_fortify/read_overflow2-memmove.c | 5 + .../read_overflow2_field-memcpy.c | 5 + .../read_overflow2_field-memmove.c | 5 + lib/test_fortify/test_fortify.h | 31 ++ lib/test_fortify/write_overflow-memcpy.c | 5 + lib/test_fortify/write_overflow-memmove.c | 5 + lib/test_fortify/write_overflow-memset.c | 5 + lib/test_fortify/write_overflow-strlcpy.c | 5 + lib/test_fortify/write_overflow-strncpy.c | 5 + lib/test_fortify/write_overflow-strscpy.c | 5 + .../write_overflow_field-memcpy.c | 5 + .../write_overflow_field-memmove.c | 5 + .../write_overflow_field-memset.c | 5 + lib/test_memcpy.c | 297 ++++++++++++++++++ net/802/hippi.c | 2 +- net/core/flow_dissector.c | 10 +- net/core/skbuff.c | 14 +- net/dccp/trace.h | 4 +- net/ethtool/stats.c | 15 +- net/ipv4/ip_output.c | 6 +- net/ipv6/route.c | 4 +- net/mac80211/rx.c | 2 +- net/netfilter/nf_conntrack_core.c | 4 +- net/netlink/af_netlink.c | 4 +- net/wireless/lib80211_crypt_ccmp.c | 3 +- net/wireless/radiotap.c | 5 +- net/xfrm/xfrm_policy.c | 4 +- net/xfrm/xfrm_user.c | 2 +- scripts/test_fortify.sh | 64 ++++ security/Kconfig | 3 + 137 files changed, 1484 insertions(+), 633 deletions(-) create mode 100644 lib/test_fortify/read_overflow-memchr.c create mode 100644 lib/test_fortify/read_overflow-memchr_inv.c create mode 100644 lib/test_fortify/read_overflow-memcmp.c create mode 100644 lib/test_fortify/read_overflow-memscan.c create mode 100644 lib/test_fortify/read_overflow2-memcmp.c create mode 100644 lib/test_fortify/read_overflow2-memcpy.c create mode 100644 lib/test_fortify/read_overflow2-memmove.c create mode 100644 lib/test_fortify/read_overflow2_field-memcpy.c create mode 100644 lib/test_fortify/read_overflow2_field-memmove.c create mode 100644 lib/test_fortify/test_fortify.h create mode 100644 lib/test_fortify/write_overflow-memcpy.c create mode 100644 lib/test_fortify/write_overflow-memmove.c create mode 100644 lib/test_fortify/write_overflow-memset.c create mode 100644 lib/test_fortify/write_overflow-strlcpy.c create mode 100644 lib/test_fortify/write_overflow-strncpy.c create mode 100644 lib/test_fortify/write_overflow-strscpy.c create mode 100644 lib/test_fortify/write_overflow_field-memcpy.c create mode 100644 lib/test_fortify/write_overflow_field-memmove.c create mode 100644 lib/test_fortify/write_overflow_field-memset.c create mode 100644 lib/test_memcpy.c create mode 100644 scripts/test_fortify.sh
Signature · 1 line
2.30.2
PATCH 1/64 media: omap3isp: Extract struct group for memcpy() region
In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields. Wrap the target region in a common named structure. This additionally fixes a theoretical misalignment of the copy (since the size of "buf" changes between 64-bit and 32-bit, but this is likely never built for 64-bit).
FWIW, I think this code is totally broken on 64-bit (which appears to not be a "real" build configuration): it would either always fail (with an uninitialized data->buf_size) or would cause corruption in userspace due to the copy_to_user() in the call path against an uninitialized data->buf value:
omap3isp_stat_request_statistics_time32(...)
struct omap3isp_stat_data data64;
...
omap3isp_stat_request_statistics(stat, &data64);int omap3isp_stat_request_statistics(struct ispstat *stat,
struct omap3isp_stat_data *data)
...
buf = isp_stat_buf_get(stat, data);static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat,
struct omap3isp_stat_data *data)
...
if (buf->buf_size > data->buf_size) {
...
return ERR_PTR(-EINVAL);
}
...
rval = copy_to_user(data->buf,
buf->virt_addr,
buf->buf_size);Regardless, additionally initialize data64 to be zero-filled to avoid undefined behavior.
--- drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)
drivers/media/platform/omap3isp/ispstat.c +3 -2
@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };int ret; ret =omap3isp_stat_request_statistics (stat, &data64);
@@ -521,7 +521,8 @@ int omap3isp_stat_request_statistics_time32(struct ispstat *stat, data->ts.tv_sec = data64.ts.tv_sec; data->ts.tv_usec = data64.ts.tv_usec; -memcpy (&data->buf, &data64.buf,sizeof (*data) -sizeof (data->ts)); + data->buf = (uintptr_t )data64.buf; +memcpy (&data->frame, &data64.buf,sizeof (data->frame));return 0 ; }
include/uapi/linux/omap3isp.h +33 -11
66 lines not on this page · raw message
Signature · 1 line
2.30.2
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 59 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields. Wrap the target region in a common named structure. This additionally fixes a theoretical misalignment of the copy (since the size of "buf" changes between 64-bit and 32-bit, but this is likely never built for 64-bit).FWIW, I think this code is totally broken on 64-bit (which appears to not be a "real" build configuration): it would either always fail (with an uninitialized
data->buf_size) or would cause corruption in userspace due to thecopy_to_user()in the call path against an uninitializeddata->bufvalue:
omap3isp_stat_request_statistics_time32(...)struct omap3isp_stat_data data64; ... omap3isp_stat_request_statistics(stat, &data64);int omap3isp_stat_request_statistics(struct ispstat *stat,
struct omap3isp_stat_data *data) ... buf = isp_stat_buf_get(stat, data);static struct
ispstat_buffer*isp_stat_buf_get(struct ispstat *stat,
structomap3isp_stat_data*data)
...if (buf->buf_size > data->buf_size) { ... return ERR_PTR(-EINVAL); } ... rval = copy_to_user(data->buf, buf->virt_addr, buf->buf_size);Regardless, additionally initialize data64 to be zero-filled to avoid undefined behavior.
Fixes 378e3f81cb56 ("media: omap3isp: support 64-bit version of omap3isp_stat_data")Signed-off-by Kees Cook <[email protected]>--- drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };int ret; ret =omap3isp_stat_request_statistics (stat, &data64);
drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics_time32(struct ispstat *stat, · line 525
Quoted 6 lines
drivers/media/platform/omap3isp/ispstat.c +2
-1@@ -521,7 +521,8 @@ int omap3isp_stat_request_statistics_time32(struct ispstat *stat, data->ts.tv_sec = data64.ts.tv_sec; data->ts.tv_usec = data64.ts.tv_usec; -memcpy (&data->buf, &data64.buf,sizeof (*data) -sizeof (data->ts)); + data->buf = (uintptr_t )data64.buf; +memcpy (&data->frame, &data64.buf,sizeof (data->frame));
I think this should be:
memcpy(..., &data64.frame, ...);
instead.
--
Gustavo
Quoted 79 lines
drivers/media/platform/omap3isp/ispstat.c +0
-0return 0 ; }include/uapi/linux/omap3isp.h +33
-11@@ -159,13 +159,25 @@ struct omap3isp_h3a_aewb_config { };/** -* struct omap3isp_stat_data - Statistic data sent to or received from user -* @ts: Timestamp of returned framestats. -* @buf: Pointer to pass to user. +* struct omap3isp_stat_frame - Statistic data without timestamp nor pointer. +* @buf_size: Size of buffer. * @frame_number: Frame number of requested stats. * @cur_frame: Current frame number being processed. * @config_counter: Number of the configuration associated with the data. */ +struct omap3isp_stat_frame { +__u32 buf_size; +__u16 frame_number; +__u16 cur_frame; +__u16 config_counter; +}; + +/** +* struct omap3isp_stat_data - Statistic data sent to or received from user +* @ts: Timestamp of returned framestats. +* @buf: Pointer to pass to user. +* @frame: Statistic data for frame. +*/ struct omap3isp_stat_data { #ifdef __KERNEL__ struct {@@ -176,10 +188,15 @@ struct omap3isp_stat_data {struct timeval ts;#endif void __user *buf; -__u32 buf_size; -__u16 frame_number; -__u16 cur_frame; -__u16 config_counter; +union { +struct { +__u32 buf_size; +__u16 frame_number; +__u16 cur_frame; +__u16 config_counter; + }; +struct omap3isp_stat_frame frame; + }; };#ifdef __KERNEL__@@ -189,10 +206,15 @@ struct omap3isp_stat_data_time32 { __s32 tv_usec; } ts;__u32 buf; -__u32 buf_size; -__u16 frame_number; -__u16 cur_frame; -__u16 config_counter; +union { +struct { +__u32 buf_size; +__u16 frame_number; +__u16 cur_frame; +__u16 config_counter; + }; +struct omap3isp_stat_frame frame; + }; };#endif Signature · 1 line
2.30.2
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 69 lines · Gustavo A. R. Silva
Quoted 59 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields. Wrap the target region in a common named structure. This additionally fixes a theoretical misalignment of the copy (since the size of "buf" changes between 64-bit and 32-bit, but this is likely never built for 64-bit).FWIW, I think this code is totally broken on 64-bit (which appears to not be a "real" build configuration): it would either always fail (with an uninitialized
data->buf_size) or would cause corruption in userspace due to thecopy_to_user()in the call path against an uninitializeddata->bufvalue:
omap3isp_stat_request_statistics_time32(...)struct omap3isp_stat_data data64; ... omap3isp_stat_request_statistics(stat, &data64);int omap3isp_stat_request_statistics(struct ispstat *stat,
struct omap3isp_stat_data *data) ... buf = isp_stat_buf_get(stat, data);static struct
ispstat_buffer*isp_stat_buf_get(struct ispstat *stat,
structomap3isp_stat_data*data)
...if (buf->buf_size > data->buf_size) { ... return ERR_PTR(-EINVAL); } ... rval = copy_to_user(data->buf, buf->virt_addr, buf->buf_size);Regardless, additionally initialize data64 to be zero-filled to avoid undefined behavior.
Fixes 378e3f81cb56 ("media: omap3isp: support 64-bit version of omap3isp_stat_data")Signed-off-by Kees Cook <[email protected]>--- drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };int ret; ret =omap3isp_stat_request_statistics (stat, &data64);drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics_time32(struct ispstat *stat, · line 525
Quoted 6 lines
drivers/media/platform/omap3isp/ispstat.c +2
-1@@ -521,7 +521,8 @@ int omap3isp_stat_request_statistics_time32(struct ispstat *stat, data->ts.tv_sec = data64.ts.tv_sec; data->ts.tv_usec = data64.ts.tv_usec; -memcpy (&data->buf, &data64.buf,sizeof (*data) -sizeof (data->ts)); + data->buf = (uintptr_t )data64.buf; +memcpy (&data->frame, &data64.buf,sizeof (data->frame));I think this should be:
Quoted 3 lines
memcpy(..., &data64.frame, ...);instead.
Whoops; thanks! This is what I get for temporarily silencing the read-overflow warnings. :)
-Kees
Signature · 1 line
Kees Cook
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
In reply to Kees CookQuoted 50 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields. Wrap the target region in a common named structure. This additionally fixes a theoretical misalignment of the copy (since the size of "buf" changes between 64-bit and 32-bit, but this is likely never built for 64-bit).FWIW, I think this code is totally broken on 64-bit (which appears to not be a "real" build configuration): it would either always fail (with an uninitialized
data->buf_size) or would cause corruption in userspace due to thecopy_to_user()in the call path against an uninitializeddata->bufvalue:
omap3isp_stat_request_statistics_time32(...)struct omap3isp_stat_data data64; ... omap3isp_stat_request_statistics(stat, &data64);int omap3isp_stat_request_statistics(struct ispstat *stat,
struct omap3isp_stat_data *data) ... buf = isp_stat_buf_get(stat, data);static struct
ispstat_buffer*isp_stat_buf_get(struct ispstat *stat,
structomap3isp_stat_data*data)
...if (buf->buf_size > data->buf_size) { ... return ERR_PTR(-EINVAL); } ... rval = copy_to_user(data->buf, buf->virt_addr, buf->buf_size);Regardless, additionally initialize data64 to be zero-filled to avoid undefined behavior.
Fixes 378e3f81cb56 ("media: omap3isp: support 64-bit version of omap3isp_stat_data")Signed-off-by Kees Cook <[email protected]>--- drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0
drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };
Should this be { 0 } ?
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.html
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 17 lines · David Sterba
Quoted 9 lines
drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };Should this be { 0 } ?
Quoted 5 lines
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.html
In the kernel we don't care about portability so much. Use the = { } GCC extension. If the first member of the struct is a pointer then Sparse will complain about = { 0 }.
I had a patch to make checkpatch.pl complain about = { 0 }; but my system died and I haven't transfered my postponed messages to the new system...
regards,
dan carpenter
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 22 lines · Dan Carpenter
Quoted 21 lines · David Sterba
Quoted 9 lines
drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };Should this be { 0 } ?
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.html
Quoted 5 lines
Quoted 1 line
In the kernel we don't care about portability so much. Use the = { } GCC extension. If the first member of the struct is a pointer then Sparse will complain about = { 0 }.
+1 for { }. BTW, my understanding is that neither the C standard nor the C++ standard guarantee anything about initialization of padding bytes nor about the initialization of unnamed bitfields for stack variables when using aggregate initialization.
Bart.
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 23 lines · Bart Van Assche
Quoted 22 lines · Dan Carpenter
Quoted 21 lines · David Sterba
Quoted 9 lines
drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };Should this be { 0 } ?
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.html
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
In the kernel we don't care about portability so much. Use the = { } GCC extension. If the first member of the struct is a pointer then Sparse will complain about = { 0 }.
+1 for { }.
Oh, I thought the tendency is is to use { 0 } because that can also intialize the compound members, by a "scalar 0" as it appears in the code.
Greg Kroah-Hartman
maintainerRe: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 30 lines · David Sterba
Quoted 29 lines · Bart Van Assche
Quoted 27 lines · Dan Carpenter
Quoted 17 lines · David Sterba
Quoted 9 lines
drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };Should this be { 0 } ?
Quoted 5 lines
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.htmlIn the kernel we don't care about portability so much. Use the = { } GCC extension. If the first member of the struct is a pointer then Sparse will complain about = { 0 }.
Quoted 6 lines
Quoted 1 line
+1 for { }.
Oh, I thought the tendency is is to use { 0 } because that can also intialize the compound members, by a "scalar 0" as it appears in the code.
Holes in the structure might not be initialized to anything if you do either one of these as well.
Or did we finally prove that is not the case? I can not remember anymore...
greg k-h
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 38 lines · Greg Kroah-Hartman
Quoted 30 lines · David Sterba
Quoted 29 lines · Bart Van Assche
Quoted 27 lines · Dan Carpenter
Quoted 17 lines · David Sterba
Quoted 9 lines
drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };Should this be { 0 } ?
Quoted 5 lines
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.htmlIn the kernel we don't care about portability so much. Use the = { } GCC extension. If the first member of the struct is a pointer then Sparse will complain about = { 0 }.
Quoted 6 lines
Quoted 1 line
+1 for { }.
Oh, I thought the tendency is is to use { 0 } because that can also intialize the compound members, by a "scalar 0" as it appears in the code.
Quoted 5 lines
Holes in the structure might not be initialized to anything if you do either one of these as well.
Or did we finally prove that is not the case? I can not remember anymore...
Yep. The C11 spec says that struct holes are initialized.
https://lore.kernel.org/netdev/[email protected]/
What doesn't initialize struct holes is assignments:
struct foo foo = *bar;
regards,
dan carpenter
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 42 lines · Dan Carpenter
Quoted 41 lines · Greg Kroah-Hartman
Quoted 30 lines · David Sterba
Quoted 29 lines · Bart Van Assche
Quoted 27 lines · Dan Carpenter
Quoted 17 lines · David Sterba
Quoted 9 lines
drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };Should this be { 0 } ?
Quoted 5 lines
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.htmlIn the kernel we don't care about portability so much. Use the = { } GCC extension. If the first member of the struct is a pointer then Sparse will complain about = { 0 }.
Quoted 6 lines
Quoted 1 line
+1 for { }.
Oh, I thought the tendency is is to use { 0 } because that can also intialize the compound members, by a "scalar 0" as it appears in the code.
Holes in the structure might not be initialized to anything if you do either one of these as well.
Quoted 6 lines
Quoted 2 lines
Or did we finally prove that is not the case? I can not remember anymore...
Yep. The C11 spec says that struct holes are initialized.
This is, unfortunately, misleading. The frustrating key word is "partial" in "updated in C11 to require zero'ing padding when doing partial initialization of aggregates". If one initializes _all_ the struct members ... the padding doesn't get initialized. :( (And until recently, _trailing_ padding wasn't getting initialized even when other paddings were.)
I've tried to collect all the different ways the compiler might initialize a variable in this test:
https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/tree/lib/test_stackinit.c?h=for-next/kspp
FWIW, there's no difference between -std=gnu99 and -std=c11, and the test shows that padding is _not_ universally initialized (unless your compiler supports -ftrivial-auto-var-init=zero, which Clang does, and GCC will shortly[1]). Running this with GCC 10.3.0, I see this...
As expected, having no initializer leaves padding (as well as members) uninitialized:
stackinit: small_hole_none FAIL (uninit bytes: 24)
stackinit: big_hole_none FAIL (uninit bytes: 128)
stackinit: trailing_hole_none FAIL (uninit bytes: 32)
Here, "zero" means "= { };" and they get padding initialized:
stackinit: small_hole_zero ok
stackinit: big_hole_zero ok
stackinit: trailing_hole_zero ok
Here, "static_partial" means "= { .one_member = 0 };", and "dynamic_partial" means "= { .one_member = some_variable };". These are similarly initialized:
stackinit: small_hole_static_partial ok
stackinit: big_hole_static_partial ok
stackinit: trailing_hole_static_partial ok
stackinit: small_hole_dynamic_partial ok
stackinit: big_hole_dynamic_partial ok
stackinit: trailing_hole_dynamic_partial ok
But when _all_ members are initialized, the padding is _not_:
stackinit: small_hole_static_all FAIL (uninit bytes: 3)
stackinit: big_hole_static_all FAIL (uninit bytes: 124)
stackinit: trailing_hole_static_all FAIL (uninit bytes: 7)
stackinit: small_hole_dynamic_all FAIL (uninit bytes: 3)
stackinit: big_hole_dynamic_all FAIL (uninit bytes: 124)
stackinit: trailing_hole_dynamic_all FAIL (uninit bytes: 7)
As expected, assigning to members outside of initialization leaves padding uninitialized:
stackinit: small_hole_runtime_partial FAIL (uninit bytes: 23)
stackinit: big_hole_runtime_partial FAIL (uninit bytes: 127)
stackinit: trailing_hole_runtime_partial FAIL (uninit bytes: 24)
stackinit: small_hole_runtime_all FAIL (uninit bytes: 3)
stackinit: big_hole_runtime_all FAIL (uninit bytes: 124)
stackinit: trailing_hole_runtime_all FAIL (uninit bytes: 7)
Quoted 3 lines
What doesn't initialize struct holes is assignments:
struct foo foo = *bar;
Right. Object to object assignments do not clear padding:
stackinit: small_hole_assigned_copy XFAIL (uninit bytes: 3)
stackinit: big_hole_assigned_copy XFAIL (uninit bytes: 124)
stackinit: trailing_hole_assigned_copy XFAIL (uninit bytes: 7)
And whole-object assignments of cast initializers follow the pattern of basic initializers, which makes sense given the behavior of initializers and direct assignment tests above. e.g.:
obj = (type){ .member = ... };stackinit: small_hole_assigned_static_partial ok
stackinit: small_hole_assigned_dynamic_partial ok
stackinit: big_hole_assigned_dynamic_partial ok
stackinit: big_hole_assigned_static_partial ok
stackinit: trailing_hole_assigned_dynamic_partial ok
stackinit: trailing_hole_assigned_static_partial ok
stackinit: small_hole_assigned_static_all FAIL (uninit bytes: 3)
stackinit: small_hole_assigned_dynamic_all FAIL (uninit bytes: 3)
stackinit: big_hole_assigned_static_all FAIL (uninit bytes: 124)
stackinit: big_hole_assigned_dynamic_all FAIL (uninit bytes: 124)
stackinit: trailing_hole_assigned_dynamic_all FAIL (uninit bytes: 7)
stackinit: trailing_hole_assigned_static_all FAIL (uninit bytes: 7)
So, yeah, it's not very stable.
-Kees
[1] https://gcc.gnu.org/pipermail/gcc-patches/2021-July/576341.html
Signature · 1 line
Kees Cook
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 134 lines · Kees Cook
Quoted 42 lines · Dan Carpenter
Quoted 41 lines · Greg Kroah-Hartman
Quoted 30 lines · David Sterba
Quoted 29 lines · Bart Van Assche
Quoted 27 lines · Dan Carpenter
Quoted 17 lines · David Sterba
Quoted 9 lines
drivers/media/platform/omap3isp/ispstat.c | 5 +-- include/uapi/linux/omap3isp.h | 44 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-)drivers/media/platform/omap3isp/ispstat.c +0
-0drivers/media/platform/omap3isp/ispstat.c int omap3isp_stat_request_statistics(struct ispstat *stat, · line 515
Quoted 5 lines
drivers/media/platform/omap3isp/ispstat.c +1
-1@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,int omap3isp_stat_request_statistics_time32 (struct ispstat *stat,struct omap3isp_stat_data_time32 *data) { -struct omap3isp_stat_data data64; +struct omap3isp_stat_data data64 = { };Should this be { 0 } ?
Quoted 5 lines
We've seen patches trying to switch from { 0 } to { } but the answer was that { 0 } is supposed to be used,
http://www.ex-parrot.com/~chris/random/initialise.htmlIn the kernel we don't care about portability so much. Use the = { } GCC extension. If the first member of the struct is a pointer then Sparse will complain about = { 0 }.
Quoted 6 lines
Quoted 1 line
+1 for { }.
Oh, I thought the tendency is is to use { 0 } because that can also intialize the compound members, by a "scalar 0" as it appears in the code.
Holes in the structure might not be initialized to anything if you do either one of these as well.
Quoted 6 lines
Quoted 2 lines
Or did we finally prove that is not the case? I can not remember anymore...
Yep. The C11 spec says that struct holes are initialized.
This is, unfortunately, misleading. The frustrating key word is "partial" in "updated in C11 to require zero'ing padding when doing partial initialization of aggregates". If one initializes _all_ the struct members ... the padding doesn't get initialized. :( (And until recently, _trailing_ padding wasn't getting initialized even when other paddings were.)
I've tried to collect all the different ways the compiler might initialize a variable in this test:
https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/tree/lib/test_stackinit.c?h=for-next/ksppFWIW, there's no difference between -std=gnu99 and -std=c11, and the test shows that padding is _not_ universally initialized (unless your compiler supports -ftrivial-auto-var-init=zero, which Clang does, and GCC will shortly[1]). Running this with GCC 10.3.0, I see this...
As expected, having no initializer leaves padding (as well as members) uninitialized:
stackinit:
small_hole_noneFAIL (uninit bytes: 24)
stackinit:big_hole_noneFAIL (uninit bytes: 128)
stackinit:trailing_hole_noneFAIL (uninit bytes: 32)Here, "zero" means "= { };" and they get padding initialized:
stackinit:
small_hole_zerook
stackinit:big_hole_zerook
stackinit:trailing_hole_zerookHere, "
static_partial" means "= { .one_member = 0 };", and "dynamic_partial" means "= { .one_member =some_variable};". These are similarly initialized:stackinit:
small_hole_static_partialok
stackinit:big_hole_static_partialok
stackinit:trailing_hole_static_partialokstackinit:
small_hole_dynamic_partialok
stackinit:big_hole_dynamic_partialok
stackinit:trailing_hole_dynamic_partialokBut when _all_ members are initialized, the padding is _not_:
stackinit:
small_hole_static_allFAIL (uninit bytes: 3)
stackinit:big_hole_static_allFAIL (uninit bytes: 124)
stackinit:trailing_hole_static_allFAIL (uninit bytes: 7)stackinit:
small_hole_dynamic_allFAIL (uninit bytes: 3)
stackinit:big_hole_dynamic_allFAIL (uninit bytes: 124)
stackinit:trailing_hole_dynamic_allFAIL (uninit bytes: 7)As expected, assigning to members outside of initialization leaves padding uninitialized:
stackinit:
small_hole_runtime_partialFAIL (uninit bytes: 23)
stackinit:big_hole_runtime_partialFAIL (uninit bytes: 127)
stackinit:trailing_hole_runtime_partialFAIL (uninit bytes: 24)stackinit:
small_hole_runtime_allFAIL (uninit bytes: 3)
stackinit:big_hole_runtime_allFAIL (uninit bytes: 124)
stackinit:trailing_hole_runtime_allFAIL (uninit bytes: 7)Quoted 3 lines
What doesn't initialize struct holes is assignments:
struct foo foo = *bar;Right. Object to object assignments do not clear padding:
stackinit:
small_hole_assigned_copyXFAIL (uninit bytes: 3)
stackinit:big_hole_assigned_copyXFAIL (uninit bytes: 124)
stackinit:trailing_hole_assigned_copyXFAIL (uninit bytes: 7)And whole-object assignments of cast initializers follow the pattern of basic initializers, which makes sense given the behavior of initializers and direct assignment tests above. e.g.:
obj = (type){ .member = ... };stackinit:
small_hole_assigned_static_partialok
stackinit:small_hole_assigned_dynamic_partialok
stackinit:big_hole_assigned_dynamic_partialok
stackinit:big_hole_assigned_static_partialok
stackinit:trailing_hole_assigned_dynamic_partialok
stackinit:trailing_hole_assigned_static_partialok
Quoted 8 lines
stackinit:
small_hole_assigned_static_allFAIL (uninit bytes: 3)
stackinit:small_hole_assigned_dynamic_allFAIL (uninit bytes: 3)
stackinit:big_hole_assigned_static_allFAIL (uninit bytes: 124)
stackinit:big_hole_assigned_dynamic_allFAIL (uninit bytes: 124)
stackinit:trailing_hole_assigned_dynamic_allFAIL (uninit bytes: 7)
stackinit:trailing_hole_assigned_static_allFAIL (uninit bytes: 7)So, yeah, it's not very stable.
Then is explicit memset the only reliable way accross all compiler flavors and supported versions?
E.g. for ioctls that get kernel memory (stack, kmalloc), partially initialize it and then call copy_to_user.
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 3 lines · David Sterba
Then is explicit memset the only reliable way accross all compiler flavors and supported versions?
The = { } initializer works. It's only when you start partially initializing the struct that it doesn't initialize holes.
regards,
dan carpenter
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 7 lines · Dan Carpenter
Quoted 3 lines · David Sterba
Then is explicit memset the only reliable way accross all compiler flavors and supported versions?
The = { } initializer works. It's only when you start partially initializing the struct that it doesn't initialize holes.
No, partial works. It's when you _fully_ initialize the struct where the padding doesn't get initialized. *sob*
struct foo {
u8 flag;
/* padding */
void *ptr;
};These are fine:
struct foo ok1 = { };
struct foo ok2 = { .flag = 7 };
struct foo ok3 = { .ptr = NULL };
This is not:
struct foo bad = { .flag = 7, .ptr = NULL };
(But, of course, it depends on padding size, compiler version, and architecture. i.e. things remain unreliable.)
Signature · 1 line
Kees Cook
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 7 lines · Kees Cook
Quoted 5 lines · Dan Carpenter
Quoted 3 lines · David Sterba
Then is explicit memset the only reliable way accross all compiler flavors and supported versions?
Quoted 5 lines
Quoted 2 lines
The = { } initializer works. It's only when you start partially initializing the struct that it doesn't initialize holes.
No, partial works. It's when you _fully_ initialize the struct where the padding doesn't get initialized. *sob*
I'm pretty sure that this has more to do with whether or not the compiler applies SROA then observes uses of the individual members or not.
Quoted 21 lines
struct foo { u8 flag; /* padding */ void *ptr; };These are fine:
struct foo ok1 = { };
struct foo ok2 = { .flag = 7 };
struct foo ok3 = { .ptr = NULL };This is not:
struct foo bad = { .flag = 7, .ptr = NULL };
(But, of course, it depends on padding size, compiler version, and architecture. i.e. things remain unreliable.)
--
Signature · 2 lines
Thanks, ~Nick Desaulniers
Re: [PATCH 01/64] media: omap3isp: Extract struct group for memcpy() region
Quoted 11 lines · Nick Desaulniers
Quoted 10 lines · Kees Cook
Quoted 7 lines · Dan Carpenter
Quoted 3 lines · David Sterba
Then is explicit memset the only reliable way accross all compiler flavors and supported versions?
The = { } initializer works. It's only when you start partially initializing the struct that it doesn't initialize holes.
Quoted 6 lines
Quoted 2 lines
No, partial works. It's when you _fully_ initialize the struct where the padding doesn't get initialized. *sob*
I'm pretty sure that this has more to do with whether or not the compiler applies SROA then observes uses of the individual members or not.
Ultimately, it's just not consistent, so thank goodness for -ftrivial-auto-var-init=zero. :)
Signature · 1 line
Kees Cook
PATCH 2/64 mac80211: Use flex-array for radiotap header bitmap
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
The it_present member of struct ieee80211_radiotap_header is treated as a flexible array (multiple u32s can be conditionally present). In order for memcpy() to reason (or really, not reason) about the size of operations against this struct, use of bytes beyond it_present need to be treated as part of the flexible array. Add a union/struct to contain the new "bitmap" member, for use with trailing presence bitmaps and arguments.
Additionally improve readability in the iterator code which walks through the bitmaps and arguments.
--- include/net/ieee80211_radiotap.h | 24 ++++++++++++++++++++---- net/mac80211/rx.c | 2 +- net/wireless/radiotap.c | 5 ++--- 3 files changed, 23 insertions(+), 8 deletions(-)
include/net/ieee80211_radiotap.h +20 -4
@@ -39,10 +39,26 @@ struct ieee80211_radiotap_header {*/ __le16 it_len; -/** -* @it_present: (first) present word -*/ -__le32 it_present; +union { +/** +* @it_present: (first) present word +*/ +__le32 it_present; + +struct { +/* The compiler makes it difficult to overlap +* a flex-array with an existing singleton, +* so we're forced to add an empty named +* variable here. +*/ +struct { } __unused; + +/** +* @bitmap: all presence bitmaps +*/ +__le32 bitmap[]; + }; + }; } __packed;/* version is always 0 */
net/mac80211/rx.c +1 -1
@@ -328,7 +328,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, rthdr =skb_push (skb, rtap_len);memset (rthdr,0 , rtap_len - rtap.len - rtap.pad); - it_present = &rthdr->it_present; + it_present = rthdr->bitmap;/* radiotap header, set always present flags */ rthdr->it_len =cpu_to_le16 (rtap_len);
net/wireless/radiotap.c +2 -3
@@ -115,10 +115,9 @@ int ieee80211_radiotap_iterator_init( iterator->_max_length =get_unaligned_le16 (&radiotap_header->it_len); iterator->_arg_index =0 ; iterator->_bitmap_shifter =get_unaligned_le32 (&radiotap_header->it_present); - iterator->_arg = (uint8_t *)radiotap_header +sizeof (*radiotap_header); + iterator->_arg = (uint8_t *)&radiotap_header->bitmap[1 ]; iterator->_reset_on_ext =0 ; - iterator->_next_bitmap = &radiotap_header->it_present; - iterator->_next_bitmap++; + iterator->_next_bitmap = &radiotap_header->bitmap[1 ]; iterator->_vns = vns; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns =1 ;
Signature · 1 line
2.30.2
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
Quoted 44 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.The
it_presentmember of structieee80211_radiotap_headeris treated as a flexible array (multiple u32s can be conditionally present). In order formemcpy()to reason (or really, not reason) about the size of operations against this struct, use of bytes beyondit_presentneed to be treated as part of the flexible array. Add a union/struct to contain the new "bitmap" member, for use with trailing presence bitmaps and arguments.Additionally improve readability in the iterator code which walks through the bitmaps and arguments.
Signed-off-by Kees Cook <[email protected]>--- include/net/ieee80211_radiotap.h | 24 ++++++++++++++++++++---- net/mac80211/rx.c | 2 +- net/wireless/radiotap.c | 5 ++--- 3 files changed, 23 insertions(+), 8 deletions(-)include/net/ieee80211_radiotap.h +11
-4@@ -39,10 +39,26 @@ struct ieee80211_radiotap_header {*/ __le16 it_len; -/** -* @it_present: (first) present word -*/ -__le32 it_present; +union { +/** +* @it_present: (first) present word +*/ +__le32 it_present; + +struct { +/* The compiler makes it difficult to overlap +* a flex-array with an existing singleton, +* so we're forced to add an empty named +* variable here.
include/net/ieee80211_radiotap.h struct ieee80211_radiotap_header { · line 62
Quoted 10 lines
include/net/ieee80211_radiotap.h +9
-0+*/ +struct { } __unused; + +/** +* @bitmap: all presence bitmaps +*/ +__le32 bitmap[]; + }; + }; } __packed;
This patch is so confusing...
Btw, after the end of the __le32 data there is a bunch of other le64, u8 and le16 data so the struct is not accurate or complete.
It might be better to re-write this as something like this:
include/net/ieee80211_radiotap.h +4 -1
@@ -42,7 +42,10 @@ struct ieee80211_radiotap_header {/** * @it_present: (first) present word */ -__le32 it_present; +struct { +__le32 it_present; +char buff[]; + } data; } __packed;/* version is always 0 */
net/mac80211/rx.c +12 -12
@@ -328,7 +328,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, rthdr =skb_push (skb, rtap_len);memset (rthdr,0 , rtap_len - rtap.len - rtap.pad); - it_present = &rthdr->it_present; + it_present = (__le32 *)&rthdr->data;/* radiotap header, set always present flags */ rthdr->it_len =cpu_to_le16 (rtap_len);
@@ -372,7 +372,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,ieee80211_calculate_rx_timestamp (local, status, mpdulen,0 ), pos); - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); pos +=8 ; }
@@ -396,7 +396,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos =0 ; }else {int shift =0 ; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_RATE ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_RATE );if (status->bw ==RATE_INFO_BW_10 ) shift =1 ;else if (status->bw ==RATE_INFO_BW_5 )
@@ -432,7 +432,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,if (ieee80211_hw_check (&local->hw,SIGNAL_DBM ) && !(status->flag &RX_FLAG_NO_SIGNAL_VAL )) { *pos = status->signal; - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_DBM_ANTSIGNAL ); pos++; }
@@ -459,7 +459,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,if (status->encoding ==RX_ENC_HT ) {unsigned int stbc; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_MCS ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_MCS ); *pos++ = local->hw.radiotap_mcs_details; *pos =0 ;if (status->enc_flags &RX_ENC_FLAG_SHORT_GI )
@@ -482,7 +482,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 4 byte alignment */ while ((pos - (u8 *)rthdr) &3 ) pos++; - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_AMPDU_STATUS );put_unaligned_le32 (status->ampdu_reference, pos); pos +=4 ;
@@ -510,7 +510,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,if (status->encoding ==RX_ENC_VHT ) {u16 known = local->hw.radiotap_vht_details; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_VHT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_VHT );put_unaligned_le16 (known, pos); pos +=2 ;/* flags */
@@ -553,7 +553,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,u16 accuracy =0 ;u8 flags =IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT ; - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TIMESTAMP );/* ensure 8 byte alignment */
@@ -642,7 +642,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 2 byte alignment */ while ((pos - (u8 *)rthdr) &1 ) pos++; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE );memcpy (pos, &he,sizeof (he)); pos +=sizeof (he); }
@@ -652,13 +652,13 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 2 byte alignment */ while ((pos - (u8 *)rthdr) &1 ) pos++; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE_MU ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE_MU );memcpy (pos, &he_mu,sizeof (he_mu)); pos +=sizeof (he_mu); }if (status->flag &RX_FLAG_NO_PSDU ) { - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_ZERO_LEN_PSDU ); *pos++ = status->zero_length_psdu_type; }
@@ -667,7 +667,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 2 byte alignment */ while ((pos - (u8 *)rthdr) &1 ) pos++; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_LSIG ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_LSIG );memcpy (pos, &lsig,sizeof (lsig)); pos +=sizeof (lsig); }
net/wireless/radiotap.c +2 -3
@@ -114,11 +114,10 @@ int ieee80211_radiotap_iterator_init( iterator->_rtheader = radiotap_header; iterator->_max_length =get_unaligned_le16 (&radiotap_header->it_len); iterator->_arg_index =0 ; - iterator->_bitmap_shifter =get_unaligned_le32 (&radiotap_header->it_present); + iterator->_bitmap_shifter =get_unaligned_le32 (&radiotap_header->data.it_present); iterator->_arg = (uint8_t *)radiotap_header +sizeof (*radiotap_header); iterator->_reset_on_ext =0 ; - iterator->_next_bitmap = &radiotap_header->it_present; - iterator->_next_bitmap++; + iterator->_next_bitmap = (__le32 *)&radiotap_header->data.buff; iterator->_vns = vns; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns =1 ;
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
net/mac80211/rx.c ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, · line 375
Quoted 6 lines · Dan Carpenter
net/mac80211/rx.c +1
-1@@ -372,7 +372,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,ieee80211_calculate_rx_timestamp (local, status, mpdulen,0 ), pos); - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT );
A drive-by comment, not related to the patchset, but rather the ieee80211 driver itself.
Shift expressions with (1 << NUMBER) can be subtly broken once the NUMBER is 31 and the value gets silently cast to a 64bit type. It will become 0xfffffffff80000000.
I've checked the IEEE80211_RADIOTAP_* defintions if this is even remotely possible and yes, IEEE80211_RADIOTAP_EXT == 31. Fortunatelly it seems to be used with used with a 32bit types (eg. _bitmap_shifter) so there are no surprises.
The recommended practice is to always use unsigned types for shifts, so "1U << ..." at least.
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
Quoted 15 lines · David Sterba
net/mac80211/rx.c ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, · line 375
Quoted 6 lines · Dan Carpenter
net/mac80211/rx.c +1
-1@@ -372,7 +372,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,ieee80211_calculate_rx_timestamp (local, status, mpdulen,0 ), pos); - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT );A drive-by comment, not related to the patchset, but rather the ieee80211 driver itself.
Shift expressions with (1 << NUMBER) can be subtly broken once the NUMBER is 31 and the value gets silently cast to a 64bit type. It will become
0xfffffffff80000000.
Quoted 7 lines
I've checked the IEEE80211_RADIOTAP_* defintions if this is even remotely possible and yes,
IEEE80211_RADIOTAP_EXT== 31. Fortunatelly it seems to be used with used with a 32bit types (eg._bitmap_shifter) so there are no surprises.The recommended practice is to always use unsigned types for shifts, so "1U << ..." at least.
Ah, good catch! I think just using BIT() is the right replacement here, yes? I suppose that should be a separate patch.
Signature · 1 line
Kees Cook
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
Quoted 21 lines · Kees Cook
Quoted 20 lines · David Sterba
net/mac80211/rx.c ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, · line 375
Quoted 6 lines · Dan Carpenter
net/mac80211/rx.c +1
-1@@ -372,7 +372,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,ieee80211_calculate_rx_timestamp (local, status, mpdulen,0 ), pos); - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT );A drive-by comment, not related to the patchset, but rather the ieee80211 driver itself.
Shift expressions with (1 << NUMBER) can be subtly broken once the NUMBER is 31 and the value gets silently cast to a 64bit type. It will become
0xfffffffff80000000.I've checked the IEEE80211_RADIOTAP_* defintions if this is even remotely possible and yes,
IEEE80211_RADIOTAP_EXT== 31. Fortunatelly it seems to be used with used with a 32bit types (eg._bitmap_shifter) so there are no surprises.
Quoted 5 lines
Quoted 2 lines
The recommended practice is to always use unsigned types for shifts, so "1U << ..." at least.
Ah, good catch! I think just using
BIT()is the right replacement here, yes? I suppose that should be a separate patch.
I found definition of BIT in vdso/bits.h, that does not sound like a standard header, besides that it shifts 1UL, that may not be necessary everywhere. IIRC there were objections against using the macro at all.
Looking for all the definitions, there are a few that are wrong in the sense they're using the singed type, eg.
https://elixir.bootlin.com/linux/v5.14-rc3/source/arch/arm/mach-davinci/sleep.S#L7
#define BIT(nr) (1 << (nr))
...
#define DEEPSLEEP_SLEEPENABLE_BIT BIT(31)
but that's an assembly file so the C integer promotions don't apply.
https://elixir.bootlin.com/linux/v5.14-rc3/source/drivers/staging/rtl8723bs/include/osdep_service.h#L18
https://elixir.bootlin.com/linux/v5.14-rc3/source/drivers/staging/rtl8723bs/include/wifi.h#L15
https://elixir.bootlin.com/linux/v5.14-rc3/source/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c#L15
#define BIT(x) (1 << (x))
Auditing and cleaning that up is for another series, yeah, I'm just pointing it here if somebody feels like doing the work. It's IMO low hanging fruit but can reveal real bugs.
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
Quoted 25 lines · David Sterba
Quoted 24 lines · Kees Cook
Quoted 22 lines · David Sterba
net/mac80211/rx.c ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, · line 375
Quoted 6 lines · Dan Carpenter
net/mac80211/rx.c +1
-1@@ -372,7 +372,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,ieee80211_calculate_rx_timestamp (local, status, mpdulen,0 ), pos); - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT );A drive-by comment, not related to the patchset, but rather the ieee80211 driver itself.
Shift expressions with (1 << NUMBER) can be subtly broken once the NUMBER is 31 and the value gets silently cast to a 64bit type. It will become
0xfffffffff80000000.I've checked the IEEE80211_RADIOTAP_* defintions if this is even remotely possible and yes,
IEEE80211_RADIOTAP_EXT== 31. Fortunatelly it seems to be used with used with a 32bit types (eg._bitmap_shifter) so there are no surprises.The recommended practice is to always use unsigned types for shifts, so "1U << ..." at least.
Quoted 6 lines
Quoted 2 lines
Ah, good catch! I think just using
BIT()is the right replacement here, yes? I suppose that should be a separate patch.I found definition of BIT in
vdso/bits.h, that does not sound like a standard header, besides that it shifts 1UL, that may not be necessary everywhere. IIRC there were objections against using the macro at all.
3945ff37d2f4 ("linux/bits.h: Extract common header for vDSO") moved it there from linux/bits.h, and linux/bits.h now includes vdso/bits.h, so it is still ever-present. :)
Signature · 1 line
Kees Cook
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
In reply to Dan CarpenterQuoted 49 lines · Dan Carpenter
Quoted 48 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.The
it_presentmember of structieee80211_radiotap_headeris treated as a flexible array (multiple u32s can be conditionally present). In order formemcpy()to reason (or really, not reason) about the size of operations against this struct, use of bytes beyondit_presentneed to be treated as part of the flexible array. Add a union/struct to contain the new "bitmap" member, for use with trailing presence bitmaps and arguments.Additionally improve readability in the iterator code which walks through the bitmaps and arguments.
Signed-off-by Kees Cook <[email protected]>--- include/net/ieee80211_radiotap.h | 24 ++++++++++++++++++++---- net/mac80211/rx.c | 2 +- net/wireless/radiotap.c | 5 ++--- 3 files changed, 23 insertions(+), 8 deletions(-)include/net/ieee80211_radiotap.h +15
-4@@ -39,10 +39,26 @@ struct ieee80211_radiotap_header {*/ __le16 it_len; -/** -* @it_present: (first) present word -*/ -__le32 it_present; +union { +/** +* @it_present: (first) present word +*/ +__le32 it_present; + +struct { +/* The compiler makes it difficult to overlap +* a flex-array with an existing singleton, +* so we're forced to add an empty named +* variable here. +*/ +struct { } __unused; + +/**
Quoted 8 lines
include/net/ieee80211_radiotap.h struct ieee80211_radiotap_header { · line 62
Quoted 6 lines
include/net/ieee80211_radiotap.h +5
-0+* @bitmap: all presence bitmaps +*/ +__le32 bitmap[]; + }; + }; } __packed;This patch is so confusing...
Yeah, I agree. I tried a few ways, and was unhappy with all of them. :P
Quoted 11 lines
Btw, after the end of the
__le32data there is a bunch of other le64, u8 and le16 data so the struct is not accurate or complete.It might be better to re-write this as something like this:
include/net/ieee80211_radiotap.h +0
-0
include/net/ieee80211_radiotap.h struct ieee80211_radiotap_header { · line 49
Quoted 9 lines
include/net/ieee80211_radiotap.h +4
-1@@ -42,7 +42,10 @@ struct ieee80211_radiotap_header {/** * @it_present: (first) present word */ -__le32 it_present; +struct { +__le32 it_present; +char buff[]; + } data; } __packed;
Hm, yes, I can try this. I attempted something similar without the "only a struct" part; I was trying to avoid the identifier churn, but I guess seeing it again, it's not _that_ bad. :P
net/mac80211/rx.c ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, · line 331
Quoted 12 lines
include/net/ieee80211_radiotap.h +0
-0/* version is always 0 */ net/mac80211/rx.c +1
-1@@ -328,7 +328,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, rthdr =skb_push (skb, rtap_len);memset (rthdr,0 , rtap_len - rtap.len - rtap.pad); - it_present = &rthdr->it_present; + it_present = (__le32 *)&rthdr->data;
Hm, interesting way to avoid angering the compiler during the later it_present++ updates. This is subtle ... a passer-by may not understand why this isn't just "it_present = &rthdr->data.it_present".
I think this is okay with a comment added. I'll give this a spin. Thanks!
-Kees
Quoted 118 lines
net/mac80211/rx.c +11
-11/* radiotap header, set always present flags */ rthdr->it_len =cpu_to_le16 (rtap_len);@@ -372,7 +372,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,ieee80211_calculate_rx_timestamp (local, status, mpdulen,0 ), pos); - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TSFT ); pos +=8 ; }@@ -396,7 +396,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos =0 ; }else {int shift =0 ; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_RATE ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_RATE );if (status->bw ==RATE_INFO_BW_10 ) shift =1 ;else if (status->bw ==RATE_INFO_BW_5 )@@ -432,7 +432,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,if (ieee80211_hw_check (&local->hw,SIGNAL_DBM ) && !(status->flag &RX_FLAG_NO_SIGNAL_VAL )) { *pos = status->signal; - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_DBM_ANTSIGNAL ); pos++; }@@ -459,7 +459,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,if (status->encoding ==RX_ENC_HT ) {unsigned int stbc; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_MCS ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_MCS ); *pos++ = local->hw.radiotap_mcs_details; *pos =0 ;if (status->enc_flags &RX_ENC_FLAG_SHORT_GI )@@ -482,7 +482,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 4 byte alignment */ while ((pos - (u8 *)rthdr) &3 ) pos++; - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_AMPDU_STATUS );put_unaligned_le32 (status->ampdu_reference, pos); pos +=4 ;@@ -510,7 +510,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,if (status->encoding ==RX_ENC_VHT ) {u16 known = local->hw.radiotap_vht_details; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_VHT ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_VHT );put_unaligned_le16 (known, pos); pos +=2 ;/* flags */ @@ -553,7 +553,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,u16 accuracy =0 ;u8 flags =IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT ; - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_TIMESTAMP );/* ensure 8 byte alignment */ @@ -642,7 +642,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 2 byte alignment */ while ((pos - (u8 *)rthdr) &1 ) pos++; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE );memcpy (pos, &he,sizeof (he)); pos +=sizeof (he); }@@ -652,13 +652,13 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 2 byte alignment */ while ((pos - (u8 *)rthdr) &1 ) pos++; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE_MU ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_HE_MU );memcpy (pos, &he_mu,sizeof (he_mu)); pos +=sizeof (he_mu); }if (status->flag &RX_FLAG_NO_PSDU ) { - rthdr->it_present |= + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_ZERO_LEN_PSDU ); *pos++ = status->zero_length_psdu_type; }@@ -667,7 +667,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,/* ensure 2 byte alignment */ while ((pos - (u8 *)rthdr) &1 ) pos++; - rthdr->it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_LSIG ); + rthdr->data.it_present |=cpu_to_le32 (1 <<IEEE80211_RADIOTAP_LSIG );memcpy (pos, &lsig,sizeof (lsig)); pos +=sizeof (lsig); }net/wireless/radiotap.c +2
-3@@ -114,11 +114,10 @@ int ieee80211_radiotap_iterator_init( iterator->_rtheader = radiotap_header; iterator->_max_length =get_unaligned_le16 (&radiotap_header->it_len); iterator->_arg_index =0 ; - iterator->_bitmap_shifter =get_unaligned_le32 (&radiotap_header->it_present); + iterator->_bitmap_shifter =get_unaligned_le32 (&radiotap_header->data.it_present); iterator->_arg = (uint8_t *)radiotap_header +sizeof (*radiotap_header); iterator->_reset_on_ext =0 ; - iterator->_next_bitmap = &radiotap_header->it_present; - iterator->_next_bitmap++; + iterator->_next_bitmap = (__le32 *)&radiotap_header->data.buff; iterator->_vns = vns; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns =1 ;
Signature · 1 line
Kees Cook
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
In reply to Dan CarpenterQuoted 49 lines · Dan Carpenter
Quoted 48 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.The
it_presentmember of structieee80211_radiotap_headeris treated as a flexible array (multiple u32s can be conditionally present). In order formemcpy()to reason (or really, not reason) about the size of operations against this struct, use of bytes beyondit_presentneed to be treated as part of the flexible array. Add a union/struct to contain the new "bitmap" member, for use with trailing presence bitmaps and arguments.Additionally improve readability in the iterator code which walks through the bitmaps and arguments.
Signed-off-by Kees Cook <[email protected]>--- include/net/ieee80211_radiotap.h | 24 ++++++++++++++++++++---- net/mac80211/rx.c | 2 +- net/wireless/radiotap.c | 5 ++--- 3 files changed, 23 insertions(+), 8 deletions(-)include/net/ieee80211_radiotap.h +15
-4@@ -39,10 +39,26 @@ struct ieee80211_radiotap_header {*/ __le16 it_len; -/** -* @it_present: (first) present word -*/ -__le32 it_present; +union { +/** +* @it_present: (first) present word +*/ +__le32 it_present; + +struct { +/* The compiler makes it difficult to overlap +* a flex-array with an existing singleton, +* so we're forced to add an empty named +* variable here. +*/ +struct { } __unused; + +/**
Quoted 8 lines
include/net/ieee80211_radiotap.h struct ieee80211_radiotap_header { · line 62
Quoted 6 lines
include/net/ieee80211_radiotap.h +5
-0+* @bitmap: all presence bitmaps +*/ +__le32 bitmap[]; + }; + }; } __packed;This patch is so confusing...
Right, unfortunately your patch doesn't work under the strict memcpy(). :(
Here are the constraints I navigated to come to the original patch I sent:
* I need to directly reference a flexible array for the it_present pointer because pos is based on it, and the compiler thinks pos walks off the end of the struct:
In function 'fortify_memcpy_chk', inlined from 'ieee80211_add_rx_radiotap_header' at net/mac80211/rx.c:652:3: ./include/linux/fortify-string.h:285:4: warning: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribute-warning] 285 | __write_overflow_field(); | ^~~~~~~~~~~~~~~~~~~~~~~~
* It's churn/fragile to change the sizeof(), so I can't just do:
- __le32 it_present; + __le32 it_bitmap[];
* I want to use a union:
- __le32 it_present;
+ union {
+ __le32 it_present;
+ __le32 it_bitmap[];
+ };
* ... but I can't actually use a union because of compiler constraints
on flexible array members:
./include/net/ieee80211_radiotap.h:50:10: error: flexible array member in union
50 | __le32 it_optional[];
| ^~~~~~~~~~~* So I came to the horrible thing I original sent. :P
If I could escape the __le32 *it_present incrementing, I could use a simple change:
__le32 it_present; + __le32 it_optional[];
Quoted 2 lines
Btw, after the end of the
__le32data there is a bunch of other le64, u8 and le16 data so the struct is not accurate or complete.
Hm, docs seem to indicate that the packet format is multiples of u32? *shrug*
Hmpf.
-Kees
Signature · 1 line
Kees Cook
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
In reply to Dan CarpenterQuoted 40 lines · Dan Carpenter
Quoted 16 lines · Kees Cook
[...]
(quoted diff) +11
-4- /** - * @it_present: (first) present word - */ - __le32 it_present; + union { + /** + * @it_present: (first) present word + */ + __le32 it_present; + + struct { + /* The compiler makes it difficult to overlap + * a flex-array with an existing singleton, + * so we're forced to add an empty named + * variable here.Review
Quoted 10 lines
(quoted diff) +9
-0+ */ + struct { } __unused; + + /** + * @bitmap: all presence bitmaps + */ + __le32 bitmap[]; + }; + }; } __packed;This patch is so confusing...
Btw, after the end of the
__le32data there is a bunch of other le64, u8 and le16 data so the struct is not accurate or complete.It might be better to re-write this as something like this:
include/net/ieee80211_radiotap.h +0
-0
include/net/ieee80211_radiotap.h struct ieee80211_radiotap_header { · line 49
Quoted 9 lines
include/net/ieee80211_radiotap.h +4
-1@@ -42,7 +42,10 @@ struct ieee80211_radiotap_header {/** * @it_present: (first) present word */ -__le32 it_present; +struct { +__le32 it_present; +char buff[]; + } data; } __packed;
Ah-ha, got it:
include/net/ieee80211_radiotap.h +4 -0
@@ -43,6 +43,10 @@ struct ieee80211_radiotap_header {* @it_present: (first) present word */ __le32 it_present; +/** +* @it_optional: all remaining presence bitmaps +*/ +__le32 it_optional[]; } __packed;/* version is always 0 */
net/mac80211/rx.c +7 -1
@@ -359,7 +359,13 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,put_unaligned_le32 (it_present_val, it_present); - pos = (void *)(it_present +1 ); +/* +* This references through an offset into it_optional[] rather +* than via it_present otherwise later uses of pos will cause +* the compiler to think we have walked past the end of the +* struct member. +*/ + pos = (void *)&rthdr->it_optional[it_present - rthdr->it_optional];/* the order of the following fields is important */
net/wireless/radiotap.c +2 -3
@@ -115,10 +115,9 @@ int ieee80211_radiotap_iterator_init( iterator->_max_length =get_unaligned_le16 (&radiotap_header->it_len); iterator->_arg_index =0 ; iterator->_bitmap_shifter =get_unaligned_le32 (&radiotap_header->it_present); - iterator->_arg = (uint8_t *)radiotap_header +sizeof (*radiotap_header); + iterator->_arg = (uint8_t *)radiotap_header->it_optional; iterator->_reset_on_ext =0 ; - iterator->_next_bitmap = &radiotap_header->it_present; - iterator->_next_bitmap++; + iterator->_next_bitmap = radiotap_header->it_optional; iterator->_vns = vns; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns =1 ;
Signature · 1 line
Kees Cook
Re: [PATCH 02/64] mac80211: Use flex-array for radiotap header bitmap
Quoted 3 lines · Kees Cook
Ah-ha, got it:
Thanks, Kees! Nice!
regards,
dan carpenter
PATCH 3/64 rpmsg: glink: Replace strncpy() with strscpy_pad()
In reply to Kees CookThe use of strncpy() is considered deprecated for NUL-terminated strings[1]. Replace strncpy() with strscpy_pad() (as it seems this case expects the NUL padding to fill the allocation following the flexible array). This additionally silences a warning seen when building under -Warray-bounds:
./include/linux/fortify-string.h:38:30: warning: '__builtin_strncpy' offset 24 from the object at '__mptr' is out of the bounds of referenced subobject 'data' with type 'u8[]' {aka 'unsigned char[]'} at offset 24 [-Warray-bounds]
38 | #define __underlying_strncpy __builtin_strncpy
| ^./include/linux/fortify-string.h:50:9: note: in expansion of macro '__underlying_strncpy'
50 | return __underlying_strncpy(p, q, size);
| ^~~~~~~~~~~~~~~~~~~~
drivers/rpmsg/qcom_glink_native.c: In function 'qcom_glink_work':
drivers/rpmsg/qcom_glink_native.c:36:5: note: subobject 'data' declared here
36 | u8 data[];
| ^~~~[1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings
--- drivers/rpmsg/qcom_glink_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/rpmsg/qcom_glink_native.c +1 -1
@@ -1440,7 +1440,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, } rpdev->ept = &channel->ept; -strncpy (rpdev->id.name, name,RPMSG_NAME_SIZE ); +strscpy_pad (rpdev->id.name, name,RPMSG_NAME_SIZE ); rpdev->src =RPMSG_ADDR_ANY ; rpdev->dst =RPMSG_ADDR_ANY ; rpdev->ops = &glink_device_ops;
Signature · 1 line
2.30.2
Re: [PATCH 03/64] rpmsg: glink: Replace strncpy() with strscpy_pad()
Quoted 17 lines · Kees Cook
The use of
strncpy()is considered deprecated for NUL-terminated strings[1]. Replacestrncpy()withstrscpy_pad()(as it seems this case expects the NUL padding to fill the allocation following the flexible array). This additionally silences a warning seen when building under -Warray-bounds:
./include/linux/fortify-string.h:38:30: warning: '__builtin_strncpy' offset 24 from the object at '__mptr' is out of the bounds of referenced subobject 'data' with type 'u8[]' {aka 'unsigned char[]'} at offset 24 [-Warray-bounds]
38 | #define__underlying_strncpy__builtin_strncpy
| ^./include/linux/fortify-string.h:50:9: note: in expansion of macro '__underlying_strncpy'50 | return __underlying_strncpy(p, q, size); | ^~~~~~~~~~~~~~~~~~~~ drivers/rpmsg/qcom_glink_native.c: In function 'qcom_glink_work': drivers/rpmsg/qcom_glink_native.c:36:5: note: subobject 'data' declared here 36 | u8 data[]; | ^~~~
Quoted 3 lines
[1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings
Signed-off-by Kees Cook <[email protected]>
Thanks
--
Gustavo
Quoted 20 lines
--- drivers/rpmsg/qcom_glink_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/rpmsg/qcom_glink_native.c +1
-1@@ -1440,7 +1440,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, } rpdev->ept = &channel->ept; -strncpy (rpdev->id.name, name,RPMSG_NAME_SIZE ); +strscpy_pad (rpdev->id.name, name,RPMSG_NAME_SIZE ); rpdev->src =RPMSG_ADDR_ANY ; rpdev->dst =RPMSG_ADDR_ANY ; rpdev->ops = &glink_device_ops;Signature · 1 line
2.30.2
PATCH 4/64 stddef: Introduce struct_group() helper macro
In reply to Kees CookKernel code has a regular need to describe groups of members within a structure usually when they need to be copied or initialized separately from the rest of the surrounding structure. The generally accepted design pattern in C is to use a named sub-struct:
struct foo {
int one;
struct {
int two;
int three;
} thing;
int four;
};This would allow for traditional references and sizing:
memcpy(&dst.thing, &src.thing, sizeof(dst.thing));
However, doing this would mean that referencing struct members enclosed by such named structs would always require including the sub-struct name in identifiers:
do_something(dst.thing.three);
This has tended to be quite inflexible, especially when such groupings need to be added to established code which causes huge naming churn. Three workarounds exist in the kernel for this problem, and each have other negative properties.
To avoid the naming churn, there is a design pattern of adding macro aliases for the named struct:
#define f_three thing.three
This ends up polluting the global namespace, and makes it difficult to search for identifiers.
Another common work-around in kernel code avoids the pollution by avoiding the named struct entirely, instead identifying the group's boundaries using either a pair of empty anonymous structs of a pair of zero-element arrays:
struct foo {
int one;
struct { } start;
int two;
int three;
struct { } finish;
int four;
};
struct foo {
int one;
int start[0];
int two;
int three;
int finish[0];
int four;
};This allows code to avoid needing to use a sub-struct name for member references within the surrounding structure, but loses the benefits of being able to actually use such a struct, making it rather fragile. Using these requires open-coded calculation of sizes and offsets. The efforts made to avoid common mistakes include lots of comments, or adding various BUILD_BUG_ON()s. Such code is left with no way for the compiler to reason about the boundaries (e.g. the "start" object looks like it's 0 bytes in length and is not structurally associated with "finish"), making bounds checking depend on open-coded calculations:
if (length > offsetof(struct foo, finish) - offsetof(struct foo, start)) return -EINVAL; memcpy(&dst.start, &src.start, length);
However, the vast majority of places in the kernel that operate on groups of members do so without any identification of the grouping, relying either on comments or implicit knowledge of the struct contents, which is even harder for the compiler to reason about, and results in even more fragile manual sizing, usually depending on member locations outside of the region (e.g. to copy "two" and "three", use the start of "four" to find the size):
BUILD_BUG_ON((offsetof(struct foo, four) < offsetof(struct foo, two)) || (offsetof(struct foo, four) < offsetof(struct foo, three)); if (length > offsetof(struct foo, four) - offsetof(struct foo, two)) return -EINVAL; memcpy(&dst.two, &src.two, length);
And both of the prior two idioms additionally appear to write beyond the end of the referenced struct member, forcing the compiler to ignore any attempt to perform bounds checking.
In order to have a regular programmatic way to describe a struct region that can be used for references and sizing, can be examined for bounds checking, avoids forcing the use of intermediate identifiers, and avoids polluting the global namespace, introduce the struct_group() macro. This macro wraps the member declarations to create an anonymous union of an anonymous struct (no intermediate name) and a named struct (for references and sizing):
struct foo {
int one;
struct_group(thing,
int two,
int three,
);
int four;
};
if (length > sizeof(src.thing))
return -EINVAL;
memcpy(&dst.thing, &src.thing, length);
do_something(dst.three);There are some rare cases where the resulting struct_group() needs attributes added, so struct_group_attr() is also introduced to allow for specifying struct attributes (e.g. __align(x) or __packed).
--- include/linux/stddef.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
include/linux/stddef.h +34 -0
@@ -36,4 +36,38 @@ enum {#define offsetofend (TYPE ,MEMBER ) \ (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) +/** +* struct_group_attr(NAME, ATTRS, MEMBERS) +* +* 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. +* +* @NAME: The name of the mirrored sub-struct +* @ATTRS: Any struct attributes (normally empty) +* @MEMBERS: The member declarations for the mirrored structs +*/ +#define struct_group_attr (NAME ,ATTRS ,MEMBERS ) \ + union { \ + struct { MEMBERS } ATTRS; \ + struct { MEMBERS } ATTRS NAME; \ + } + +/** +* struct_group(NAME, MEMBERS) +* +* 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. +* +* @NAME: The name of the mirrored sub-struct +* @MEMBERS: The member declarations for the mirrored structs +*/ +#define struct_group(NAME, MEMBERS) \ + struct_group_attr(NAME, /* no attrs */, MEMBERS) +#endif
Signature · 1 line
2.30.2
Re: [PATCH 04/64] stddef: Introduce struct_group() helper macro
Quoted 117 lines · Kees Cook
Kernel code has a regular need to describe groups of members within a structure usually when they need to be copied or initialized separately from the rest of the surrounding structure. The generally accepted design pattern in C is to use a named sub-struct:
struct foo { int one; struct { int two; int three; } thing; int four; };This would allow for traditional references and sizing:
memcpy(&dst.thing, &src.thing, sizeof(dst.thing));However, doing this would mean that referencing struct members enclosed by such named structs would always require including the sub-struct name in identifiers:
do_something(dst.thing.three);This has tended to be quite inflexible, especially when such groupings need to be added to established code which causes huge naming churn. Three workarounds exist in the kernel for this problem, and each have other negative properties.
To avoid the naming churn, there is a design pattern of adding macro aliases for the named struct:
#define f_three thing.threeThis ends up polluting the global namespace, and makes it difficult to search for identifiers.
Another common work-around in kernel code avoids the pollution by avoiding the named struct entirely, instead identifying the group's boundaries using either a pair of empty anonymous structs of a pair of zero-element arrays:
struct foo { int one; struct { } start; int two; int three; struct { } finish; int four; }; struct foo { int one; int start[0]; int two; int three; int finish[0]; int four; };This allows code to avoid needing to use a sub-struct name for member references within the surrounding structure, but loses the benefits of being able to actually use such a struct, making it rather fragile. Using these requires open-coded calculation of sizes and offsets. The efforts made to avoid common mistakes include lots of comments, or adding various BUILD_BUG_ON()s. Such code is left with no way for the compiler to reason about the boundaries (e.g. the "start" object looks like it's 0 bytes in length and is not structurally associated with "finish"), making bounds checking depend on open-coded calculations:
if (length > offsetof(struct foo, finish) - offsetof(struct foo, start)) return -EINVAL; memcpy(&dst.start, &src.start, length);However, the vast majority of places in the kernel that operate on groups of members do so without any identification of the grouping, relying either on comments or implicit knowledge of the struct contents, which is even harder for the compiler to reason about, and results in even more fragile manual sizing, usually depending on member locations outside of the region (e.g. to copy "two" and "three", use the start of "four" to find the size):
BUILD_BUG_ON((offsetof(struct foo, four) < offsetof(struct foo, two)) || (offsetof(struct foo, four) < offsetof(struct foo, three)); if (length > offsetof(struct foo, four) - offsetof(struct foo, two)) return -EINVAL; memcpy(&dst.two, &src.two, length);And both of the prior two idioms additionally appear to write beyond the end of the referenced struct member, forcing the compiler to ignore any attempt to perform bounds checking.
In order to have a regular programmatic way to describe a struct region that can be used for references and sizing, can be examined for bounds checking, avoids forcing the use of intermediate identifiers, and avoids polluting the global namespace, introduce the
struct_group()macro. This macro wraps the member declarations to create an anonymous union of an anonymous struct (no intermediate name) and a named struct (for references and sizing):struct foo { int one; struct_group(thing, int two, int three, ); int four; }; if (length > sizeof(src.thing)) return -EINVAL; memcpy(&dst.thing, &src.thing, length); do_something(dst.three);
Quoted 7 lines
There are some rare cases where the resulting
struct_group()needs attributes added, sostruct_group_attr()is also introduced to allow for specifying struct attributes (e.g.__align(x)or__packed).Co-developed-by Keith Packard <[email protected]>Signed-off-by Keith Packard <[email protected]>Signed-off-by Kees Cook <[email protected]>
Love it! :)
Thanks
--
Gustavo
Quoted 50 lines
--- include/linux/stddef.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)include/linux/stddef.h +34
-0@@ -36,4 +36,38 @@ enum {#define offsetofend (TYPE ,MEMBER ) \ (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) +/** +* struct_group_attr(NAME, ATTRS, MEMBERS) +* +* 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. +* +* @NAME: The name of the mirrored sub-struct +* @ATTRS: Any struct attributes (normally empty) +* @MEMBERS: The member declarations for the mirrored structs +*/ +#define struct_group_attr (NAME ,ATTRS ,MEMBERS ) \ + union { \ + struct { MEMBERS } ATTRS; \ + struct { MEMBERS } ATTRS NAME; \ + } + +/** +* struct_group(NAME, MEMBERS) +* +* 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. +* +* @NAME: The name of the mirrored sub-struct +* @MEMBERS: The member declarations for the mirrored structs +*/ +#define struct_group(NAME, MEMBERS) \ + struct_group_attr(NAME, /* no attrs */, MEMBERS) +#endif Signature · 1 line
2.30.2
Re: [PATCH 04/64] stddef: Introduce struct_group() helper macro
In reply to Kees CookQuoted 8 lines · Kees Cook
In order to have a regular programmatic way to describe a struct region that can be used for references and sizing, can be examined for bounds checking, avoids forcing the use of intermediate identifiers, and avoids polluting the global namespace, introduce the
struct_group()macro. This macro wraps the member declarations to create an anonymous union of an anonymous struct (no intermediate name) and a named struct (for references and sizing):
Quoted 8 lines
struct foo {
int one;
struct_group(thing,
int two,
int three,
);
int four;
};That example won't compile, the commas after two and three should be semicolons.
And your implementation relies on MEMBERS not containing any comma tokens, but as
int a, b, c, d;
is a valid way to declare multiple members, consider making MEMBERS variadic
#define struct_group(NAME, MEMBERS...)
to have it slurp up every subsequent argument and make that work.
Quoted 6 lines
Co-developed-by Keith Packard <[email protected]>Signed-off-by Keith Packard <[email protected]>Signed-off-by Kees Cook <[email protected]>--- include/linux/stddef.h | 34 ++++++++++++++++++++++++++++++++++
Bikeshedding a bit, but do we need to add 34 lines that need to be preprocessed to virtually each and every translation unit [as opposed to adding a struct_group.h header]? Oh well, you need it for struct skbuff.h, so it would be pulled in by a lot regardless :(
Rasmus
Re: [PATCH 04/64] stddef: Introduce struct_group() helper macro
Quoted 19 lines · Rasmus Villemoes
Quoted 8 lines · Kees Cook
In order to have a regular programmatic way to describe a struct region that can be used for references and sizing, can be examined for bounds checking, avoids forcing the use of intermediate identifiers, and avoids polluting the global namespace, introduce the
struct_group()macro. This macro wraps the member declarations to create an anonymous union of an anonymous struct (no intermediate name) and a named struct (for references and sizing):Quoted 8 lines
struct foo { int one; struct_group(thing, int two, int three, ); int four; };
Quoted 2 lines
That example won't compile, the commas after two and three should be semicolons.
Oops, yes, thanks. This is why I shouldn't write code that doesn't first go through a compiler. ;)
Quoted 11 lines
And your implementation relies on MEMBERS not containing any comma tokens, but as
int a, b, c, d;
is a valid way to declare multiple members, consider making MEMBERS variadic
#define
struct_group(NAME, MEMBERS...)to have it slurp up every subsequent argument and make that work.
Ah! Perfect, thank you. I totally forgot I could do it that way.
Quoted 8 lines
Quoted 7 lines
Co-developed-by Keith Packard <[email protected]>Signed-off-by Keith Packard <[email protected]>Signed-off-by Kees Cook <[email protected]>--- include/linux/stddef.h | 34 ++++++++++++++++++++++++++++++++++
Quoted 4 lines
Bikeshedding a bit, but do we need to add 34 lines that need to be preprocessed to virtually each and every translation unit [as opposed to adding a
struct_group.hheader]? Oh well, you need it for structskbuff.h, so it would be pulled in by a lot regardless :(
My instinct is to make these kinds of helpers "always available" (like sizeof_field(), etc), but I have no strong opinion on where it should live. If the consensus is to move it, I certainly can! :)
-Kees
Signature · 1 line
Kees Cook
Re: [PATCH 04/64] stddef: Introduce struct_group() helper macro
Quoted 31 lines · Kees Cook
Quoted 19 lines · Rasmus Villemoes
Quoted 8 lines · Kees Cook
In order to have a regular programmatic way to describe a struct region that can be used for references and sizing, can be examined for bounds checking, avoids forcing the use of intermediate identifiers, and avoids polluting the global namespace, introduce the
struct_group()macro. This macro wraps the member declarations to create an anonymous union of an anonymous struct (no intermediate name) and a named struct (for references and sizing):Quoted 8 lines
struct foo {
int one;
struct_group(thing,
int two,
int three,
);
int four;
};Quoted 2 lines
That example won't compile, the commas after two and three should be semicolons.
Oops, yes, thanks. This is why I shouldn't write code that doesn't first go through a compiler. ;)
Quoted 5 lines
And your implementation relies on MEMBERS not containing any comma tokens, but as
int a, b, c, d;
Quoted 8 lines
Quoted 6 lines
is a valid way to declare multiple members, consider making MEMBERS variadic
#define
struct_group(NAME, MEMBERS...)to have it slurp up every subsequent argument and make that work.
Ah! Perfect, thank you. I totally forgot I could do it that way.
This is great Kees. It just so happens it would clean-up what we are already doing in drivers/cxl/cxl.h for anonymous + named register block pointers. However in the cxl case it also needs the named structure to be typed. Any appetite for a typed version of this?
Here is a rough idea of the cleanup it would induce in drivers/cxl/:
drivers/cxl/cxl.h +6 -39
@@ -75,52 +75,19 @@ 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. -*/ struct cxl_regs { -union { -struct { - CXL_COMPONENT_REGS(); - }; -struct cxl_component_regs component; - }; -union { -struct { - CXL_DEVICE_REGS(); - }; -struct cxl_device_regs device_regs; - }; + struct_group_typed(cxl_component_regs, component, + void __iomem *hdm_decoder; + ); + struct_group_typed(cxl_device_regs, device_regs, + void __iomem *status, *mbox, *memdev; + ); };struct cxl_reg_map {
include/linux/stddef.h +11 -2
@@ -49,12 +49,18 @@ enum {* @ATTRS: Any struct attributes (normally empty) * @MEMBERS: The member declarations for the mirrored structs */ -#define struct_group_attr (NAME ,ATTRS ,MEMBERS ) \ +#define struct_group_attr(NAME, ATTRS, MEMBERS...) \ union { \ struct { MEMBERS } ATTRS; \ struct { MEMBERS } ATTRS NAME; \ } +#define struct_group_attr_typed(TYPE, NAME, ATTRS, MEMBERS...) \ + union { \ + struct { MEMBERS } ATTRS; \ + struct TYPE { MEMBERS } ATTRS NAME; \ + } +/** * struct_group(NAME, MEMBERS) *
@@ -67,7 +73,10 @@ enum {* @NAME: The name of the mirrored sub-struct * @MEMBERS: The member declarations for the mirrored structs */ -#define struct_group(NAME, MEMBERS) \ +#define struct_group(NAME, MEMBERS...) \ struct_group_attr(NAME, /* no attrs */, MEMBERS) +#define struct_group_typed(TYPE, NAME, MEMBERS...) \ + struct_group_attr_typed(TYPE, NAME, /* no attrs */, MEMBERS) +#endif
Re: [PATCH 04/64] stddef: Introduce struct_group() helper macro
Quoted 37 lines · Dan J
Quoted 36 lines · Kees Cook
Quoted 19 lines · Rasmus Villemoes
Quoted 8 lines · Kees Cook
In order to have a regular programmatic way to describe a struct region that can be used for references and sizing, can be examined for bounds checking, avoids forcing the use of intermediate identifiers, and avoids polluting the global namespace, introduce the
struct_group()macro. This macro wraps the member declarations to create an anonymous union of an anonymous struct (no intermediate name) and a named struct (for references and sizing):Quoted 8 lines
struct foo {
int one;
struct_group(thing,
int two,
int three,
);
int four;
};Quoted 2 lines
That example won't compile, the commas after two and three should be semicolons.
Oops, yes, thanks. This is why I shouldn't write code that doesn't first go through a compiler. ;)
Quoted 10 lines
And your implementation relies on MEMBERS not containing any comma tokens, but as
int a, b, c, d;
is a valid way to declare multiple members, consider making MEMBERS variadic
#define
struct_group(NAME, MEMBERS...)
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
to have it slurp up every subsequent argument and make that work.
Ah! Perfect, thank you. I totally forgot I could do it that way.
This is great Kees. It just so happens it would clean-up what we are already doing in
drivers/cxl/cxl.hfor anonymous + named register block pointers. However in the cxl case it also needs the named structure to be typed. Any appetite for a typed version of this?
Oh cool! Yeah, totally I can expand it. Thanks for the suggestion!
Quoted 92 lines
Here is a rough idea of the cleanup it would induce in
drivers/cxl/:drivers/cxl/cxl.h +6
-39@@ -75,52 +75,19 @@ 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. -*/ struct cxl_regs { -union { -struct { - CXL_COMPONENT_REGS(); - }; -struct cxl_component_regs component; - }; -union { -struct { - CXL_DEVICE_REGS(); - }; -struct cxl_device_regs device_regs; - }; + struct_group_typed(cxl_component_regs, component, + void __iomem *hdm_decoder; + ); + struct_group_typed(cxl_device_regs, device_regs, + void __iomem *status, *mbox, *memdev; + ); };struct cxl_reg_map {include/linux/stddef.h +7
-1@@ -49,12 +49,18 @@ enum {* @ATTRS: Any struct attributes (normally empty) * @MEMBERS: The member declarations for the mirrored structs */ -#define struct_group_attr (NAME ,ATTRS ,MEMBERS ) \ +#define struct_group_attr(NAME, ATTRS, MEMBERS...) \ union { \ struct { MEMBERS } ATTRS; \ struct { MEMBERS } ATTRS NAME; \ } +#define struct_group_attr_typed(TYPE, NAME, ATTRS, MEMBERS...) \ + union { \ + struct { MEMBERS } ATTRS; \ + struct TYPE { MEMBERS } ATTRS NAME; \ + } +/** * struct_group(NAME, MEMBERS) * @@ -67,7 +73,10 @@ enum {* @NAME: The name of the mirrored sub-struct
include/linux/stddef.h enum { · line 82
Quoted 10 lines
include/linux/stddef.h +4
-1* @MEMBERS: The member declarations for the mirrored structs */ -#define struct_group(NAME, MEMBERS) \ +#define struct_group(NAME, MEMBERS...) \ struct_group_attr(NAME, /* no attrs */, MEMBERS) +#define struct_group_typed(TYPE, NAME, MEMBERS...) \ + struct_group_attr_typed(TYPE, NAME, /* no attrs */, MEMBERS) +#endif
Awesome! My instinct is to expose the resulting API as:
__struct_group(type, name, attrs, members...)
struct_group(name, members...)struct_group_attr(name, attrs, members...)struct_group_typed(type, name, members...)
Signature · 1 line
Kees Cook
Re: [PATCH 04/64] stddef: Introduce struct_group() helper macro
Quoted 21 lines · On Sat, Jul 31, 2021, 04:59 Kees Cook <[email protected]> wrote:
Quoted 7 lines · Dan J
On Wed, 2021-07-28 at 14:59 -0700, Kees Cook wrote:
/**
*struct_group(NAME, MEMBERS)
*include/linux/stddef.h +0
-0@@ -67,7 +73,10 @@ enum {* @NAME: The name of the mirrored sub-struct include/linux/stddef.h enum { · line 82
Quoted 10 lines
include/linux/stddef.h +4
-1* @MEMBERS: The member declarations for the mirrored structs */ -#define struct_group(NAME, MEMBERS) \ +#define struct_group(NAME, MEMBERS...) \ struct_group_attr(NAME, /* no attrs */, MEMBERS) +#define struct_group_typed(TYPE, NAME, MEMBERS...) \ + struct_group_attr_typed(TYPE, NAME, /* no attrs */, MEMBERS) +#endif Awesome! My instinct is to expose the resulting API as:
Quoted 6 lines
__struct_group(type, name, attrs, members...)
struct_group(name, members...)struct_group_attr(name, attrs, members...)struct_group_typed(type, name, members...)
Bikeshed: can we use proper nomenclature please. s/type/tag/, s/typed/tagged.
Rasmus
Re: [PATCH 04/64] stddef: Introduce struct_group() helper macro
Quoted 23 lines · Rasmus Villemoes
Quoted 21 lines · On Sat, Jul 31, 2021, 04:59 Kees Cook <[email protected]> wrote:
Quoted 7 lines · Dan J
On Wed, 2021-07-28 at 14:59 -0700, Kees Cook wrote:
/**
*struct_group(NAME, MEMBERS)
*include/linux/stddef.h +0
-0@@ -67,7 +73,10 @@ enum {* @NAME: The name of the mirrored sub-struct include/linux/stddef.h enum { · line 82
Quoted 10 lines
include/linux/stddef.h +4
-1* @MEMBERS: The member declarations for the mirrored structs */ -#define struct_group(NAME, MEMBERS) \ +#define struct_group(NAME, MEMBERS...) \ struct_group_attr(NAME, /* no attrs */, MEMBERS) +#define struct_group_typed(TYPE, NAME, MEMBERS...) \ + struct_group_attr_typed(TYPE, NAME, /* no attrs */, MEMBERS) +#endif Awesome! My instinct is to expose the resulting API as:
Quoted 8 lines
Quoted 5 lines
__struct_group(type, name, attrs, members...)
struct_group(name, members...)struct_group_attr(name, attrs, members...)struct_group_typed(type, name, members...)Bikeshed: can we use proper nomenclature please. s/type/tag/, s/typed/tagged.
Ah! Thank you. I went looking for the spec on what these are called and couldn't find it. "struct $tag" is the type, then, yes? So IIUC now:
| type | members | name
| tag
struct foo { int bar; } baz;Signature · 1 line
Kees Cook
PATCH 5/64 skbuff: Switch structure bounds to struct_group()
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Replace the existing empty member position markers "headers_start" and "headers_end" with a struct_group(). This will allow memcpy() and sizeof() to more easily reason about sizes, and improve readability.
"pahole" shows no size nor member offset changes to struct sk_buff. "objdump -d" shows no no meaningful object code changes (i.e. only source line number induced differences and optimizations.)
--- drivers/net/wireguard/queueing.h | 4 +--- include/linux/skbuff.h | 9 ++++----- net/core/skbuff.c | 14 +++++--------- 3 files changed, 10 insertions(+), 17 deletions(-)
drivers/net/wireguard/queueing.h +1 -3
@@ -79,9 +79,7 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)u8 sw_hash = skb->sw_hash;u32 hash = skb->hash;skb_scrub_packet (skb, true); -memset (&skb->headers_start,0 , - offsetof(struct sk_buff , headers_end) - - offsetof(struct sk_buff , headers_start)); +memset (&skb->headers,0 ,sizeof (skb->headers));if (encapsulating) { skb->l4_hash = l4_hash; skb->sw_hash = sw_hash;
include/linux/skbuff.h +4 -5
@@ -800,11 +800,10 @@ struct sk_buff {__u8 active_extensions;#endif -/* fields enclosed in headers_start/headers_end are copied +/* Fields enclosed in headers group are copied * using a single memcpy() in __copy_skb_header() */ -/* private: */ -__u32 headers_start[0 ]; + struct_group(headers,/* public: */ /* if you move pkt_type around you also must adapt those constants */
@@ -920,8 +919,8 @@ struct sk_buff {u64 kcov_handle;#endif -/* private: */ -__u32 headers_end[0 ]; + ); /* end headers group */ +/* public: */ /* These elements must be at the end, see alloc_skb() for details. */
net/core/skbuff.c +5 -9
@@ -987,12 +987,10 @@ void napi_consume_skb(struct sk_buff *skb, int budget) }EXPORT_SYMBOL (napi_consume_skb); -/* Make sure a field is enclosed inside headers_start/headers_end section */ +/* Make sure a field is contained by headers group */ #define CHECK_SKB_FIELD (field) \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ - offsetof(struct sk_buff, headers_start)); \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) > \ - offsetof(struct sk_buff, headers_end)); \ + BUILD_BUG_ON(offsetof(struct sk_buff, field) != \ + offsetof(struct sk_buff, headers.field)); \static void __copy_skb_header (struct sk_buff *new,const struct sk_buff *old) {
@@ -1004,14 +1002,12 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)__skb_ext_copy (new, old);__nf_copy (new, old, false); -/* Note : this field could be in headers_start/headers_end section +/* Note : this field could be in the headers group. * It is not yet because we do not want to have a 16 bit hole */ new->queue_mapping = old->queue_mapping; -memcpy (&new->headers_start, &old->headers_start, - offsetof(struct sk_buff , headers_end) - - offsetof(struct sk_buff , headers_start)); +memcpy (&new->headers, &old->headers,sizeof (new->headers));CHECK_SKB_FIELD (protocol);CHECK_SKB_FIELD (csum);CHECK_SKB_FIELD (hash);
Signature · 1 line
2.30.2
Re: [PATCH 05/64] skbuff: Switch structure bounds to struct_group()
Quoted 8 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Replace the existing empty member position markers "
headers_start" and "headers_end" with astruct_group(). This will allowmemcpy()andsizeof()to more easily reason about sizes, and improve readability.
Quoted 5 lines
"pahole" shows no size nor member offset changes to struct
sk_buff. "objdump -d" shows no no meaningful object code changes (i.e. only source line number induced differences and optimizations.)Signed-off-by Kees Cook <[email protected]>
Thanks
--
Gustavo
Quoted 90 lines
--- drivers/net/wireguard/queueing.h | 4 +--- include/linux/skbuff.h | 9 ++++----- net/core/skbuff.c | 14 +++++--------- 3 files changed, 10 insertions(+), 17 deletions(-)drivers/net/wireguard/queueing.h +1
-3@@ -79,9 +79,7 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)u8 sw_hash = skb->sw_hash;u32 hash = skb->hash;skb_scrub_packet (skb, true); -memset (&skb->headers_start,0 , - offsetof(struct sk_buff , headers_end) - - offsetof(struct sk_buff , headers_start)); +memset (&skb->headers,0 ,sizeof (skb->headers));if (encapsulating) { skb->l4_hash = l4_hash; skb->sw_hash = sw_hash;include/linux/skbuff.h +4
-5@@ -800,11 +800,10 @@ struct sk_buff {__u8 active_extensions;#endif -/* fields enclosed in headers_start/headers_end are copied +/* Fields enclosed in headers group are copied * using a single memcpy() in __copy_skb_header() */ -/* private: */ -__u32 headers_start[0 ]; + struct_group(headers,/* public: */ /* if you move pkt_type around you also must adapt those constants */ @@ -920,8 +919,8 @@ struct sk_buff {u64 kcov_handle;#endif -/* private: */ -__u32 headers_end[0 ]; + ); /* end headers group */ +/* public: */ /* These elements must be at the end, see alloc_skb() for details. */ net/core/skbuff.c +5
-9@@ -987,12 +987,10 @@ void napi_consume_skb(struct sk_buff *skb, int budget) }EXPORT_SYMBOL (napi_consume_skb); -/* Make sure a field is enclosed inside headers_start/headers_end section */ +/* Make sure a field is contained by headers group */ #define CHECK_SKB_FIELD (field) \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ - offsetof(struct sk_buff, headers_start)); \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) > \ - offsetof(struct sk_buff, headers_end)); \ + BUILD_BUG_ON(offsetof(struct sk_buff, field) != \ + offsetof(struct sk_buff, headers.field)); \static void __copy_skb_header (struct sk_buff *new,const struct sk_buff *old) {@@ -1004,14 +1002,12 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)__skb_ext_copy (new, old);__nf_copy (new, old, false); -/* Note : this field could be in headers_start/headers_end section +/* Note : this field could be in the headers group. * It is not yet because we do not want to have a 16 bit hole */ new->queue_mapping = old->queue_mapping; -memcpy (&new->headers_start, &old->headers_start, - offsetof(struct sk_buff , headers_end) - - offsetof(struct sk_buff , headers_start)); +memcpy (&new->headers, &old->headers,sizeof (new->headers));CHECK_SKB_FIELD (protocol);CHECK_SKB_FIELD (csum);CHECK_SKB_FIELD (hash);Signature · 1 line
2.30.2
PATCH 6/64 bnxt_en: Use struct_group_attr() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() around members queue_id, min_bw, max_bw, tsa, pri_lvl, and bw_weight so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of queue_id.
"pahole" shows no size nor member offset changes to struct bnxt_cos2bw_cfg. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
--- drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c | 4 ++-- drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c +2 -2
@@ -148,10 +148,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;
drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h +8 -6
@@ -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; };
Signature · 1 line
2.30.2
Re: [PATCH 06/64] bnxt_en: Use struct_group_attr() for memcpy() region
Quoted 10 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()around membersqueue_id,min_bw,max_bw, tsa,pri_lvl, andbw_weightso they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end ofqueue_id.
Quoted 5 lines
"pahole" shows no size nor member offset changes to struct
bnxt_cos2bw_cfg. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).Signed-off-by Kees Cook <[email protected]>
Thanks.
Re: [PATCH 06/64] bnxt_en: Use struct_group_attr() for memcpy() region
In reply to Kees CookQuoted 9 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()around membersqueue_id,min_bw,max_bw, tsa,pri_lvl, andbw_weightso they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end ofqueue_id.
Quoted 5 lines
"pahole" shows no size nor member offset changes to struct
bnxt_cos2bw_cfg. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).Signed-off-by Kees Cook <[email protected]>
Thanks
--
Gustavo
Quoted 51 lines
--- drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c | 4 ++-- drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-)drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c +2
-2@@ -148,10 +148,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;drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h +8
-6@@ -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; };Signature · 1 line
2.30.2
PATCH 7/64 staging: rtl8192e: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() around members addr1, addr2, and addr3 in struct rtllib_hdr_4addr, and members qui, qui_type, qui_subtype, version, and ac_info in struct rtllib_qos_information_element, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of addr1 and qui.
"pahole" shows no size nor member offset changes to struct rtllib_hdr_4addr nor struct rtllib_qos_information_element. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
--- drivers/staging/rtl8192e/rtllib.h | 20 ++++++++++++-------- drivers/staging/rtl8192e/rtllib_crypt_ccmp.c | 3 ++- drivers/staging/rtl8192e/rtllib_rx.c | 8 ++++---- 3 files changed, 18 insertions(+), 13 deletions(-)
drivers/staging/rtl8192e/rtllib.h +12 -8
@@ -759,9 +759,11 @@ struct rtllib_hdr_3addr {struct rtllib_hdr_4addr {__le16 frame_ctl;__le16 duration_id; -u8 addr1[ETH_ALEN ]; -u8 addr2[ETH_ALEN ]; -u8 addr3[ETH_ALEN ]; + struct_group(addrs, + u8 addr1[ETH_ALEN]; +u8 addr2[ETH_ALEN ]; +u8 addr3[ETH_ALEN ]; + );__le16 seq_ctl;u8 addr4[ETH_ALEN ];u8 payload[];
@@ -921,11 +923,13 @@ union frameqos {struct rtllib_qos_information_element {u8 elementID;u8 length; -u8 qui[QOS_OUI_LEN ]; -u8 qui_type; -u8 qui_subtype; -u8 version; -u8 ac_info; + struct_group(data, + u8 qui[QOS_OUI_LEN]; +u8 qui_type; +u8 qui_subtype; +u8 version; +u8 ac_info; + ); } __packed;struct rtllib_qos_ac_parameter {
drivers/staging/rtl8192e/rtllib_crypt_ccmp.c +2 -1
@@ -133,7 +133,8 @@ static int ccmp_init_iv_and_aad(struct rtllib_hdr_4addr *hdr, pos = (u8 *) hdr; aad[0 ] = pos[0 ] &0x8f ; aad[1 ] = pos[1 ] &0xc7 ; -memcpy (aad +2 , hdr->addr1,3 *ETH_ALEN ); +BUILD_BUG_ON (sizeof (hdr->addrs) != (3 *ETH_ALEN )); +memcpy (aad +2 , &hdr->addrs,3 *ETH_ALEN ); pos = (u8 *) &hdr->seq_ctl; aad[20 ] = pos[0 ] &0x0f ; aad[21 ] =0 ;/* all bits masked */
drivers/staging/rtl8192e/rtllib_rx.c +4 -4
@@ -1576,13 +1576,13 @@ static int rtllib_read_qos_param_element(struct rtllib_qos_parameter_info *info_element) {int ret =0 ; -u16 size =sizeof (struct rtllib_qos_parameter_info ) -2 ; +u16 size =sizeof (element_param->info_element.data);if ((info_element ==NULL ) || (element_param ==NULL ))return -1 ;if (info_element->id ==QOS_ELEMENT_ID && info_element->len == size) { -memcpy (element_param->info_element.qui, info_element->data, +memcpy (&element_param->info_element.data, info_element->data, info_element->len); element_param->info_element.elementID = info_element->id; element_param->info_element.length = info_element->len;
@@ -1601,7 +1601,7 @@ static int rtllib_read_qos_info_element(struct rtllib_qos_information_element *info_element) {int ret =0 ; -u16 size =sizeof (struct rtllib_qos_information_element ) -2 ; +u16 size =sizeof (element_info->data);if (element_info ==NULL )return -1 ;
@@ -1610,7 +1610,7 @@ static int rtllib_read_qos_info_element(struct rtllib_qos_information_elementif ((info_element->id ==QOS_ELEMENT_ID ) && (info_element->len == size)) { -memcpy (element_info->qui, info_element->data, +memcpy (&element_info->data, info_element->data, info_element->len); element_info->elementID = info_element->id; element_info->length = info_element->len;
Signature · 1 line
2.30.2
Re: [PATCH 07/64] staging: rtl8192e: Use struct_group() for memcpy() region
Quoted 11 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()around members addr1, addr2, and addr3 in structrtllib_hdr_4addr, and members qui,qui_type,qui_subtype, version, andac_infoin structrtllib_qos_information_element, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of addr1 and qui.
Quoted 6 lines
"pahole" shows no size nor member offset changes to struct
rtllib_hdr_4addrnor structrtllib_qos_information_element. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).Signed-off-by Kees Cook<[email protected]>
Looks good.
Larry
Re: [PATCH 07/64] staging: rtl8192e: Use struct_group() for memcpy() region
In reply to Kees CookQuoted 16 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()around members addr1, addr2, and addr3 in structrtllib_hdr_4addr, and members qui,qui_type,qui_subtype, version, andac_infoin structrtllib_qos_information_element, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of addr1 and qui."pahole" shows no size nor member offset changes to struct
rtllib_hdr_4addrnor structrtllib_qos_information_element. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
Quoted 6 lines
Signed-off-by Kees Cook <[email protected]>--- drivers/staging/rtl8192e/rtllib.h | 20 ++++++++++++-------- drivers/staging/rtl8192e/rtllib_crypt_ccmp.c | 3 ++- drivers/staging/rtl8192e/rtllib_rx.c | 8 ++++---- 3 files changed, 18 insertions(+), 13 deletions(-)
PATCH 8/64 staging: rtl8192u: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() around members addr1, addr2, and addr3 in struct rtl_80211_hdr_4addr, and members qui, qui_type, qui_subtype, version, and ac_info in struct ieee80211_qos_information_element, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of addr1 and qui. Additionally replace zero sized arrays with flexible arrays in struct ieee_param.
"pahole" shows no size nor member offset changes to struct rtl_80211_hdr_4addr nor struct ieee80211_qos_information_element. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
--- .../staging/rtl8192u/ieee80211/ieee80211.h | 24 +++++++++++-------- .../rtl8192u/ieee80211/ieee80211_crypt_ccmp.c | 3 ++- .../staging/rtl8192u/ieee80211/ieee80211_rx.c | 8 +++---- 3 files changed, 20 insertions(+), 15 deletions(-)
drivers/staging/rtl8192u/ieee80211/ieee80211.h +14 -10
@@ -303,7 +303,7 @@ struct ieee_param {struct {u32 len;u8 reserved[32 ]; -u8 data[0 ]; +u8 data[]; } wpa_ie;struct {int command;
@@ -316,7 +316,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; };
@@ -917,9 +917,11 @@ struct rtl_80211_hdr_3addr {struct rtl_80211_hdr_4addr {__le16 frame_ctl;__le16 duration_id; -u8 addr1[ETH_ALEN ]; -u8 addr2[ETH_ALEN ]; -u8 addr3[ETH_ALEN ]; + struct_group(addrs, + u8 addr1[ETH_ALEN]; +u8 addr2[ETH_ALEN ]; +u8 addr3[ETH_ALEN ]; + );__le16 seq_ctl;u8 addr4[ETH_ALEN ];u8 payload[];
@@ -1100,11 +1102,13 @@ typedef union _frameqos {struct ieee80211_qos_information_element {u8 elementID;u8 length; -u8 qui[QOS_OUI_LEN ]; -u8 qui_type; -u8 qui_subtype; -u8 version; -u8 ac_info; + struct_group(data, + u8 qui[QOS_OUI_LEN]; +u8 qui_type; +u8 qui_subtype; +u8 version; +u8 ac_info; + ); } __packed;struct ieee80211_qos_ac_parameter {
drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c +2 -1
@@ -141,7 +141,8 @@ static int ccmp_init_iv_and_aad(struct rtl_80211_hdr_4addr *hdr, pos = (u8 *)hdr; aad[0 ] = pos[0 ] &0x8f ; aad[1 ] = pos[1 ] &0xc7 ; -memcpy (aad +2 , hdr->addr1,3 *ETH_ALEN ); +BUILD_BUG_ON (sizeof (hdr->addrs) !=3 *ETH_ALEN ); +memcpy (aad +2 , &hdr->addrs,3 *ETH_ALEN ); pos = (u8 *)&hdr->seq_ctl; aad[20 ] = pos[0 ] &0x0f ; aad[21 ] =0 ;/* all bits masked */
drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +4 -4
@@ -1332,13 +1332,13 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info *info_element) {int ret =0 ; -u16 size =sizeof (struct ieee80211_qos_parameter_info ) -2 ; +u16 size =sizeof (element_param->info_element.data);if (!info_element || !element_param)return -1 ;if (info_element->id ==QOS_ELEMENT_ID && info_element->len == size) { -memcpy (element_param->info_element.qui, info_element->data, +memcpy (&element_param->info_element.data, info_element->data, info_element->len); element_param->info_element.elementID = info_element->id; element_param->info_element.length = info_element->len;
@@ -1358,7 +1358,7 @@ static int ieee80211_read_qos_info_element( struct ieee80211_info_element *info_element) {int ret =0 ; -u16 size =sizeof (struct ieee80211_qos_information_element ) -2 ; +u16 size =sizeof (element_info->data);if (!element_info)return -1 ;
@@ -1366,7 +1366,7 @@ static int ieee80211_read_qos_info_element(return -1 ;if ((info_element->id ==QOS_ELEMENT_ID ) && (info_element->len == size)) { -memcpy (element_info->qui, info_element->data, +memcpy (&element_info->data, info_element->data, info_element->len); element_info->elementID = info_element->id; element_info->length = info_element->len;
Signature · 1 line
2.30.2
Re: [PATCH 08/64] staging: rtl8192u: Use struct_group() for memcpy() region
Quoted 12 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()around members addr1, addr2, and addr3 in structrtl_80211_hdr_4addr, and members qui,qui_type,qui_subtype, version, andac_infoin structieee80211_qos_information_element, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of addr1 and qui. Additionally replace zero sized arrays with flexible arrays in structieee_param.
Quoted 6 lines
"pahole" shows no size nor member offset changes to struct
rtl_80211_hdr_4addrnor structieee80211_qos_information_element. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).Signed-off-by Kees Cook <[email protected]>
PATCH 9/64 staging: rtl8723bs: Avoid field-overflowing memcpy()
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Adjust memcpy() destination to be the named structure itself, rather than the first member, allowing memcpy() to correctly reason about the size.
"objdump -d" shows no object code changes.
--- drivers/staging/rtl8723bs/core/rtw_mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/rtl8723bs/core/rtw_mlme.c +1 -1
@@ -2390,7 +2390,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ }/* fill default supported_mcs_set */ -memcpy (ht_capie.mcs.rx_mask, pmlmeext->default_supported_mcs_set,16 ); +memcpy (&ht_capie.mcs, pmlmeext->default_supported_mcs_set,16 );/* update default supported_mcs_set */ rtw_hal_get_hwreg (padapter,HW_VAR_RF_TYPE , (u8 *)(&rf_type));
Signature · 1 line
2.30.2
Re: [PATCH 09/64] staging: rtl8723bs: Avoid field-overflowing memcpy()
Quoted 7 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Adjust
memcpy()destination to be the named structure itself, rather than the first member, allowingmemcpy()to correctly reason about the size.
Quoted 6 lines
"objdump -d" shows no object code changes.
Signed-off-by Kees Cook <[email protected]>--- drivers/staging/rtl8723bs/core/rtw_mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
PATCH 10/64 lib80211: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() around members addr1, addr2, and addr3 in struct ieee80211_hdr so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of addr1.
"pahole" shows no size nor member offset changes to struct ieee80211_hdr. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
--- drivers/staging/rtl8723bs/core/rtw_security.c | 5 +++-- drivers/staging/rtl8723bs/core/rtw_xmit.c | 5 +++-- include/linux/ieee80211.h | 8 +++++--- net/wireless/lib80211_crypt_ccmp.c | 3 ++- 4 files changed, 13 insertions(+), 8 deletions(-)
drivers/staging/rtl8723bs/core/rtw_security.c +3 -2
@@ -1421,8 +1421,9 @@ u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe)ClearRetry (BIP_AAD );ClearPwrMgt (BIP_AAD );ClearMData (BIP_AAD ); -/* conscruct AAD, copy address 1 to address 3 */ -memcpy (BIP_AAD +2 , pwlanhdr->addr1,18 ); +/* conscruct AAD, copy address 1 through address 3 */ +BUILD_BUG_ON (sizeof (pwlanhdr->addrs) !=3 *ETH_ALEN ); +memcpy (BIP_AAD +2 , &pwlanhdr->addrs,3 *ETH_ALEN );if (omac1_aes_128 (padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey ,BIP_AAD , ori_len, mic))
drivers/staging/rtl8723bs/core/rtw_xmit.c +3 -2
@@ -1198,8 +1198,9 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, sClearRetry (BIP_AAD );ClearPwrMgt (BIP_AAD );ClearMData (BIP_AAD ); -/* conscruct AAD, copy address 1 to address 3 */ -memcpy (BIP_AAD +2 , pwlanhdr->addr1,18 ); +/* conscruct AAD, copy address 1 through address 3 */ +BUILD_BUG_ON (sizeof (pwlanhdr->addrs) !=3 *ETH_ALEN ); +memcpy (BIP_AAD +2 , &pwlanhdr->addrs,3 *ETH_ALEN );/* copy management fram body */ memcpy (BIP_AAD +BIP_AAD_SIZE , MGMT_body, frame_body_len);/* calculate mic */
include/linux/ieee80211.h +5 -3
@@ -297,9 +297,11 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)struct ieee80211_hdr {__le16 frame_control;__le16 duration_id; -u8 addr1[ETH_ALEN ]; -u8 addr2[ETH_ALEN ]; -u8 addr3[ETH_ALEN ]; + struct_group(addrs, + u8 addr1[ETH_ALEN]; +u8 addr2[ETH_ALEN ]; +u8 addr3[ETH_ALEN ]; + );__le16 seq_ctrl;u8 addr4[ETH_ALEN ]; } __packed__aligned(2) ;
net/wireless/lib80211_crypt_ccmp.c +2 -1
@@ -136,7 +136,8 @@ static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr, pos = (u8 *) hdr; aad[0 ] = pos[0 ] &0x8f ; aad[1 ] = pos[1 ] &0xc7 ; -memcpy (aad +2 , hdr->addr1,3 *ETH_ALEN ); +BUILD_BUG_ON (sizeof (hdr->addrs) !=3 *ETH_ALEN ); +memcpy (aad +2 , &hdr->addrs,ETH_ALEN ); pos = (u8 *) & hdr->seq_ctrl; aad[20 ] = pos[0 ] &0x0f ; aad[21 ] =0 ;/* all bits masked */
Signature · 1 line
2.30.2
Re: [PATCH 10/64] lib80211: Use struct_group() for memcpy() region
Quoted 13 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()around members addr1, addr2, and addr3 in structieee80211_hdrso they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of addr1."pahole" shows no size nor member offset changes to struct
ieee80211_hdr. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
Quoted 7 lines
Signed-off-by Kees Cook <[email protected]>--- drivers/staging/rtl8723bs/core/rtw_security.c | 5 +++-- drivers/staging/rtl8723bs/core/rtw_xmit.c | 5 +++-- include/linux/ieee80211.h | 8 +++++--- net/wireless/lib80211_crypt_ccmp.c | 3 ++- 4 files changed, 13 insertions(+), 8 deletions(-)
For the staging portion:
Johannes Berg
maintainerRe: [PATCH 10/64] lib80211: Use struct_group() for memcpy() region
In reply to Kees CookQuoted 7 lines · Kees Cook
+++
b/include/linux/ieee80211.hinclude/linux/ieee80211.h +0
-1@@ -297,9 +297,11 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; - u8 addr1[ETH_ALEN];
include/linux/ieee80211.h static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) · line 307
Quoted 10 lines
include/linux/ieee80211.h +5
-2-u8 addr2[ETH_ALEN ]; -u8 addr3[ETH_ALEN ]; +struct_group (addrs, + u8 addr1[ETH_ALEN]; +u8 addr2[ETH_ALEN ]; +u8 addr3[ETH_ALEN ]; + ); __le16 seq_ctrl; u8 addr4[ETH_ALEN]; } __packed __aligned(2);
This file isn't really just lib80211, it's also used by everyone else for 802.11, but I guess that's OK - after all, this doesn't really result in any changes here.
net/wireless/lib80211_crypt_ccmp.c static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr, · line 140
Quoted 8 lines
+++
b/net/wireless/lib80211_crypt_ccmp.cnet/wireless/lib80211_crypt_ccmp.c +2
-1@@ -136,7 +136,8 @@ static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr, pos = (u8 *) hdr; aad[0] = pos[0] & 0x8f; aad[1] = pos[1] & 0xc7; -memcpy (aad +2 , hdr->addr1,3 *ETH_ALEN ); +BUILD_BUG_ON (sizeof (hdr->addrs) !=3 *ETH_ALEN ); +memcpy (aad +2 , &hdr->addrs,ETH_ALEN );
However, how is it you don't need the same change in net/mac80211/wpa.c?
We have three similar instances:
/* AAD (extra authenticate-only data) / masked 802.11 header
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
put_unaligned_be16(len_a, &aad[0]);
put_unaligned(mask_fc, (__le16 *)&aad[2]);
memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);and
memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
and
memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);
so those should also be changed, it seems?
In which case I'd probably prefer to do this separately from the staging drivers ...
johannes
Re: [PATCH 10/64] lib80211: Use struct_group() for memcpy() region
Quoted 46 lines · Johannes Berg
Quoted 7 lines · Kees Cook
+++
b/include/linux/ieee80211.hinclude/linux/ieee80211.h +0
-1@@ -297,9 +297,11 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; - u8 addr1[ETH_ALEN];include/linux/ieee80211.h static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) · line 307
Quoted 10 lines
include/linux/ieee80211.h +5
-2-u8 addr2[ETH_ALEN ]; -u8 addr3[ETH_ALEN ]; +struct_group (addrs, + u8 addr1[ETH_ALEN]; +u8 addr2[ETH_ALEN ]; +u8 addr3[ETH_ALEN ]; + ); __le16 seq_ctrl; u8 addr4[ETH_ALEN]; } __packed __aligned(2);This file isn't really just lib80211, it's also used by everyone else for 802.11, but I guess that's OK - after all, this doesn't really result in any changes here.
net/wireless/lib80211_crypt_ccmp.c static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr, · line 140
Quoted 8 lines
+++
b/net/wireless/lib80211_crypt_ccmp.cnet/wireless/lib80211_crypt_ccmp.c +2
-1@@ -136,7 +136,8 @@ static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr, pos = (u8 *) hdr; aad[0] = pos[0] & 0x8f; aad[1] = pos[1] & 0xc7; -memcpy (aad +2 , hdr->addr1,3 *ETH_ALEN ); +BUILD_BUG_ON (sizeof (hdr->addrs) !=3 *ETH_ALEN ); +memcpy (aad +2 , &hdr->addrs,ETH_ALEN );However, how is it you don't need the same change in
net/mac80211/wpa.c?We have three similar instances:
/* AAD (extra authenticate-only data) / masked 802.11 header * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ put_unaligned_be16(len_a, &aad[0]); put_unaligned(mask_fc, (__le16 *)&aad[2]); memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);and
Quoted 7 lines
memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);and
memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);so those should also be changed, it seems?
Ah! Yes, thanks for pointing this out. During earlier development I split the "cross-field write" changes from the "cross-field read" changes, and it looks like I missed moving lib80211_crypt_ccmp.c into that portion of the series (which I haven't posted nor finished -- it's lower priority than fixing the cross-field writes).
Quoted 2 lines
In which case I'd probably prefer to do this separately from the staging drivers ...
Agreed. Sorry for the noise on that part. I will double-check the other patches.
Signature · 1 line
Kees Cook
Johannes Berg
maintainerRe: [PATCH 10/64] lib80211: Use struct_group() for memcpy() region
Quoted 6 lines · Kees Cook
Ah! Yes, thanks for pointing this out. During earlier development I split the "cross-field write" changes from the "cross-field read" changes, and it looks like I missed moving
lib80211_crypt_ccmp.cinto that portion of the series (which I haven't posted nor finished -- it's lower priority than fixing the cross-field writes).
Oh, OK. I think all of this patch was cross-field read though.
Anyway, the patch itself is fine, just seems incomplete and somewhat badly organised :)
johannes
PATCH 11/64 net/mlx5e: Avoid field-overflowing memcpy()
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use flexible arrays instead of zero-element arrays (which look like they are always overflowing) and split the cross-field memcpy() into two halves that can be appropriately bounds-checked by the compiler.
"pahole" shows no size nor member offset changes to struct mlx5e_tx_wqe nor struct mlx5e_umr_wqe. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
--- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en.h +2 -2
@@ -204,7 +204,7 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)struct mlx5e_tx_wqe {struct mlx5_wqe_ctrl_seg ctrl;struct mlx5_wqe_eth_seg eth; -struct mlx5_wqe_data_seg data[0 ]; +struct mlx5_wqe_data_seg data[]; };struct mlx5e_rx_wqe_ll {
@@ -220,7 +220,7 @@ struct mlx5e_umr_wqe {struct mlx5_wqe_ctrl_seg ctrl;struct mlx5_wqe_umr_ctrl_seg uctrl;struct mlx5_mkey_seg mkc; -struct mlx5_mtt inline_mtts[0 ]; +struct mlx5_mtt inline_mtts[]; };extern const char mlx5e_self_tests[][ETH_GSTRING_LEN ];
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +3 -1
@@ -341,8 +341,10 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,/* copy the inline part if required */ if (sq->min_inline_mode !=MLX5_INLINE_MODE_NONE ) { -memcpy (eseg->inline_hdr.start, xdptxd->data,MLX5E_XDP_MIN_INLINE ); +memcpy (eseg->inline_hdr.start, xdptxd->data,sizeof (eseg->inline_hdr.start)); eseg->inline_hdr.sz =cpu_to_be16 (MLX5E_XDP_MIN_INLINE ); +memcpy (dseg, xdptxd->data +sizeof (eseg->inline_hdr.start), +MLX5E_XDP_MIN_INLINE -sizeof (eseg->inline_hdr.start)); dma_len -=MLX5E_XDP_MIN_INLINE ; dma_addr +=MLX5E_XDP_MIN_INLINE ; dseg++;
Signature · 1 line
2.30.2
PATCH 12/64 mwl8k: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct mwl8k_cmd_set_key around members key_material, tkip_tx_mic_key, and tkip_rx_mic_key so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of key_material.
"pahole" shows no size nor member offset changes to struct mwl8k_cmd_set_key. "objdump -d" shows no object code changes.
--- drivers/net/wireless/marvell/mwl8k.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/net/wireless/marvell/mwl8k.c +6 -4
@@ -4225,9 +4225,11 @@ struct mwl8k_cmd_set_key {__le32 key_info;__le32 key_id;__le16 key_len; -__u8 key_material[MAX_ENCR_KEY_LENGTH ]; -__u8 tkip_tx_mic_key[MIC_KEY_LENGTH ]; -__u8 tkip_rx_mic_key[MIC_KEY_LENGTH ]; +struct { +__u8 key_material[MAX_ENCR_KEY_LENGTH ]; +__u8 tkip_tx_mic_key[MIC_KEY_LENGTH ]; +__u8 tkip_rx_mic_key[MIC_KEY_LENGTH ]; + } tkip;__le16 tkip_rsc_low;__le32 tkip_rsc_high;__le16 tkip_tsc_low;
@@ -4375,7 +4377,7 @@ static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, goto done; } -memcpy (cmd->key_material, key->key, keymlen); +memcpy (&cmd->tkip, key->key, keymlen); cmd->action =cpu_to_le32 (action); rc =mwl8k_post_pervif_cmd (hw, vif, &cmd->header);
Signature · 1 line
2.30.2
PATCH 13/64 libertas: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct txpd around members tx_dest_addr_high and tx_dest_addr_low so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of queue_id.
"pahole" shows no size nor member offset changes to struct txpd. "objdump -d" shows no object code changes.
--- drivers/net/wireless/marvell/libertas/host.h | 10 ++++++---- drivers/net/wireless/marvell/libertas/tx.c | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-)
drivers/net/wireless/marvell/libertas/host.h +6 -4
@@ -308,10 +308,12 @@ struct txpd {__le32 tx_packet_location;/* Tx packet length */ __le16 tx_packet_length; -/* First 2 byte of destination MAC address */ -u8 tx_dest_addr_high[2 ]; -/* Last 4 byte of destination MAC address */ -u8 tx_dest_addr_low[4 ]; +struct_group (tx_dest_addr, +/* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; +/* Last 4 byte of destination MAC address */ +u8 tx_dest_addr_low[4 ]; + );/* Pkt Priority */ u8 priority;/* Pkt Trasnit Power control */
drivers/net/wireless/marvell/libertas/tx.c +3 -2
@@ -113,6 +113,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) p802x_hdr = skb->data; pkt_len = skb->len; +BUILD_BUG_ON (sizeof (txpd->tx_dest_addr) !=ETH_ALEN );if (priv->wdev->iftype ==NL80211_IFTYPE_MONITOR ) {struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
@@ -124,10 +125,10 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) pkt_len -=sizeof (*rtap_hdr);/* copy destination address from 802.11 header */ -memcpy (txpd->tx_dest_addr_high, p802x_hdr +4 ,ETH_ALEN ); +memcpy (&txpd->tx_dest_addr, p802x_hdr +4 ,ETH_ALEN ); }else {/* copy destination address from 802.3 header */ -memcpy (txpd->tx_dest_addr_high, p802x_hdr,ETH_ALEN ); +memcpy (&txpd->tx_dest_addr, p802x_hdr,ETH_ALEN ); } txpd->tx_packet_length =cpu_to_le16 (pkt_len);
Signature · 1 line
2.30.2
PATCH 14/64 libertas_tf: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field array bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct txpd around members tx_dest_addr_high and tx_dest_addr_low so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of tx_dest_addr_high.
"pahole" shows no size nor member offset changes to struct txpd. "objdump -d" shows no object code changes.
--- drivers/net/wireless/marvell/libertas_tf/libertas_tf.h | 10 ++++++---- drivers/net/wireless/marvell/libertas_tf/main.c | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-)
drivers/net/wireless/marvell/libertas_tf/libertas_tf.h +6 -4
@@ -268,10 +268,12 @@ struct txpd {__le32 tx_packet_location;/* Tx packet length */ __le16 tx_packet_length; -/* First 2 byte of destination MAC address */ -u8 tx_dest_addr_high[2 ]; -/* Last 4 byte of destination MAC address */ -u8 tx_dest_addr_low[4 ]; +struct_group (tx_dest_addr, +/* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; +/* Last 4 byte of destination MAC address */ +u8 tx_dest_addr_low[4 ]; + );/* Pkt Priority */ u8 priority;/* Pkt Trasnit Power control */
drivers/net/wireless/marvell/libertas_tf/main.c +2 -1
@@ -232,7 +232,8 @@ static void lbtf_tx_work(struct work_struct *work) ieee80211_get_tx_rate(priv->hw, info)->hw_value);/* copy destination address from 802.11 header */ -memcpy (txpd->tx_dest_addr_high, skb->data +sizeof (struct txpd ) +4 , +BUILD_BUG_ON (sizeof (txpd->tx_dest_addr) !=ETH_ALEN ); +memcpy (&txpd->tx_dest_addr, skb->data +sizeof (struct txpd ) +4 ,ETH_ALEN ); txpd->tx_packet_length =cpu_to_le16 (len); txpd->tx_packet_location =cpu_to_le32 (sizeof (struct txpd ));
Signature · 1 line
2.30.2
PATCH 15/64 ipw2x00: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field array bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct libipw_qos_information_element around members qui, qui_type, qui_subtype, version, and ac_info, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of qui.
"pahole" shows no size nor member offset changes to struct libipw_qos_information_element.
Additionally corrects the size in libipw_read_qos_param_element() as it was testing the wrong structure size (it should have been struct libipw_qos_information_element, not struct libipw_qos_parameter_info).
--- drivers/net/wireless/intel/ipw2x00/libipw.h | 12 +++++++----- drivers/net/wireless/intel/ipw2x00/libipw_rx.c | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-)
drivers/net/wireless/intel/ipw2x00/libipw.h +7 -5
@@ -537,11 +537,13 @@ struct libipw_txb {struct libipw_qos_information_element {u8 elementID;u8 length; -u8 qui[QOS_OUI_LEN ]; -u8 qui_type; -u8 qui_subtype; -u8 version; -u8 ac_info; + struct_group(data, + u8 qui[QOS_OUI_LEN]; +u8 qui_type; +u8 qui_subtype; +u8 version; +u8 ac_info; + ); } __packed;struct libipw_qos_ac_parameter {
drivers/net/wireless/intel/ipw2x00/libipw_rx.c +4 -4
@@ -948,13 +948,13 @@ static int libipw_read_qos_param_element(struct libipw_qos_parameter_info *info_element) {int ret =0 ; -u16 size =sizeof (struct libipw_qos_parameter_info ) -2 ; +u16 size =sizeof (element_param->info_element.data);if ((info_element ==NULL ) || (element_param ==NULL ))return -1 ;if (info_element->id ==QOS_ELEMENT_ID && info_element->len == size) { -memcpy (element_param->info_element.qui, info_element->data, +memcpy (&element_param->info_element.data, info_element->data, info_element->len); element_param->info_element.elementID = info_element->id; element_param->info_element.length = info_element->len;
@@ -975,7 +975,7 @@ static int libipw_read_qos_info_element(struct *info_element) {int ret =0 ; -u16 size =sizeof (struct libipw_qos_information_element ) -2 ; +u16 size =sizeof (element_info->data);if (element_info ==NULL )return -1 ;
@@ -983,7 +983,7 @@ static int libipw_read_qos_info_element(structreturn -1 ;if ((info_element->id ==QOS_ELEMENT_ID ) && (info_element->len == size)) { -memcpy (element_info->qui, info_element->data, +memcpy (&element_info->data, info_element->data, info_element->len); element_info->elementID = info_element->id; element_info->length = info_element->len;
Signature · 1 line
2.30.2
Re: [PATCH 15/64] ipw2x00: Use struct_group() for memcpy() region
Quoted 17 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field array bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in structlibipw_qos_information_elementaround members qui,qui_type,qui_subtype, version, andac_info, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of qui."pahole" shows no size nor member offset changes to struct
libipw_qos_information_element.Additionally corrects the size in
libipw_read_qos_param_element()as it was testing the wrong structure size (it should have been structlibipw_qos_information_element, not structlibipw_qos_parameter_info).
Quoted 6 lines
Signed-off-by Kees Cook <[email protected]>--- drivers/net/wireless/intel/ipw2x00/libipw.h | 12 +++++++----- drivers/net/wireless/intel/ipw2x00/libipw_rx.c | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-)
Looks fine, thanks!
Stanislav.
PATCH 16/64 thermal: intel: int340x_thermal: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct art around members weight, and ac[0-9]_max, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of weight.
"pahole" shows no size nor member offset changes to struct art. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences).
--- .../intel/int340x_thermal/acpi_thermal_rel.c | 5 +- .../intel/int340x_thermal/acpi_thermal_rel.h | 48 ++++++++++--------- 2 files changed, 29 insertions(+), 24 deletions(-)
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c +3 -2
@@ -250,8 +250,9 @@ static int fill_art(char __user *ubuf)get_single_name (arts[i].source, art_user[i].source_device);get_single_name (arts[i].target, art_user[i].target_device);/* copy the rest int data in addition to source and target */ -memcpy (&art_user[i].weight, &arts[i].weight, -sizeof (u64) * (ACPI_NR_ART_ELEMENTS -2 )); +BUILD_BUG_ON (sizeof (art_user[i].data) != +sizeof (u64) * (ACPI_NR_ART_ELEMENTS -2 )); +memcpy (&art_user[i].data, &arts[i].data,sizeof (art_user[i].data)); }if (copy_to_user (ubuf, art_user, art_len))
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.h +26 -22
60 lines not on this page · raw message
Signature · 1 line
2.30.2
PATCH 17/64 iommu/amd: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct ivhd_entry around members ext and hidh, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of ext.
"pahole" shows no size nor member offset changes to struct ivhd_entry. "objdump -d" shows no object code changes.
--- drivers/iommu/amd/init.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/iommu/amd/init.c +6 -3
@@ -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;
@@ -1378,7 +1380,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)) {
Signature · 1 line
2.30.2
PATCH 18/64 cxgb3: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct rss_hdr around members imm_data and intr_gen, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of imm_data.
"pahole" shows no size nor member offset changes to struct rss_hdr. "objdump -d" shows no object code changes.
--- drivers/net/ethernet/chelsio/cxgb3/sge.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/ethernet/chelsio/cxgb3/sge.c +6 -3
@@ -126,8 +126,10 @@ struct rsp_desc { /* response queue descriptor */struct rss_header rss_hdr;__be32 flags;__be32 len_cq; -u8 imm_data[47 ]; -u8 intr_gen; +struct_group (immediate, + u8 imm_data[47]; +u8 intr_gen; + ); };/*
@@ -929,7 +931,8 @@ static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp)if (skb) {__skb_put (skb,IMMED_PKT_SIZE ); -skb_copy_to_linear_data (skb, resp->imm_data,IMMED_PKT_SIZE ); +BUILD_BUG_ON (IMMED_PKT_SIZE !=sizeof (resp->immediate)); +skb_copy_to_linear_data (skb, &resp->immediate,IMMED_PKT_SIZE ); }return skb; }
Signature · 1 line
2.30.2
PATCH 19/64 ip: Use struct_group() for memcpy() regions
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct flowi4, struct ipv4hdr, and struct ipv6hdr around members saddr and daddr, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of saddr.
"pahole" shows no size nor member offset changes to struct flowi4. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
Note that since this is a UAPI header, struct_group() has been open coded.
--- include/net/flow.h | 6 ++++-- include/uapi/linux/if_ether.h | 12 ++++++++++-- include/uapi/linux/ip.h | 12 ++++++++++-- include/uapi/linux/ipv6.h | 12 ++++++++++-- net/core/flow_dissector.c | 10 ++++++---- net/ipv4/ip_output.c | 6 ++---- 6 files changed, 42 insertions(+), 16 deletions(-)
include/net/flow.h +4 -2
@@ -81,8 +81,10 @@ struct flowi4 {#define flowi4_multipath_hash __fl_common.flowic_multipath_hash/* (saddr,daddr) must be grouped, same order as in IP header */ -__be32 saddr; -__be32 daddr; +struct_group (addrs, + __be32 saddr; + __be32 daddr; + );union flowi_uli uli;#define fl4_sport uli.ports.sport
include/uapi/linux/if_ether.h +10 -2
@@ -163,8 +163,16 @@#if __UAPI_DEF_ETHHDRstruct ethhdr { -unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ -unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs; + };__be16 h_proto;/* packet type ID field */ } __attribute__((packed));#endif
include/uapi/linux/ip.h +10 -2
@@ -100,8 +100,16 @@ struct iphdr {__u8 ttl;__u8 protocol;__sum16 check; -__be32 saddr; -__be32 daddr; +union { +struct { +__be32 saddr; +__be32 daddr; + } addrs; +struct { +__be32 saddr; +__be32 daddr; + }; + };/*The options start here. */ };
include/uapi/linux/ipv6.h +10 -2
@@ -130,8 +130,16 @@ struct ipv6hdr {__u8 nexthdr;__u8 hop_limit; -struct in6_addr saddr; -struct in6_addr daddr; +union { +struct { +struct in6_addr saddr; +struct in6_addr daddr; + } addrs; +struct { +struct in6_addr saddr; +struct in6_addr daddr; + }; + }; };
net/core/flow_dissector.c +6 -4
@@ -1029,7 +1029,8 @@ bool __skb_flow_dissect(const struct net *net, key_eth_addrs =skb_flow_dissector_target (flow_dissector,FLOW_DISSECTOR_KEY_ETH_ADDRS , target_container); -memcpy (key_eth_addrs, ð->h_dest,sizeof (*key_eth_addrs)); +BUILD_BUG_ON (sizeof (*key_eth_addrs) !=sizeof (eth->addrs)); +memcpy (key_eth_addrs, ð->addrs,sizeof (*key_eth_addrs)); } proto_again:
@@ -1056,8 +1057,8 @@ bool __skb_flow_dissect(const struct net *net,FLOW_DISSECTOR_KEY_IPV4_ADDRS , target_container); -memcpy (&key_addrs->v4addrs, &iph->saddr, -sizeof (key_addrs->v4addrs)); +BUILD_BUG_ON (sizeof (key_addrs->v4addrs) !=sizeof (iph->addrs)); +memcpy (&key_addrs->v4addrs, &iph->addrs,sizeof (iph->addrs)); key_control->addr_type =FLOW_DISSECTOR_KEY_IPV4_ADDRS ; }
@@ -1101,7 +1102,8 @@ bool __skb_flow_dissect(const struct net *net,FLOW_DISSECTOR_KEY_IPV6_ADDRS , target_container); -memcpy (&key_addrs->v6addrs, &iph->saddr, +BUILD_BUG_ON (sizeof (iph->addrs) !=sizeof (key_addrs->v6addrs)); +memcpy (&key_addrs->v6addrs, &iph->addrs,sizeof (key_addrs->v6addrs)); key_control->addr_type =FLOW_DISSECTOR_KEY_IPV6_ADDRS ; }
net/ipv4/ip_output.c +2 -4
@@ -444,10 +444,8 @@ EXPORT_SYMBOL(ip_output);*/ static void ip_copy_addrs (struct iphdr *iph,const struct flowi4 *fl4) { - BUILD_BUG_ON(offsetof(typeof(*fl4), daddr) != - offsetof(typeof(*fl4), saddr) + sizeof(fl4->saddr)); -memcpy (&iph->saddr, &fl4->saddr, -sizeof (fl4->saddr) +sizeof (fl4->daddr)); +BUILD_BUG_ON (sizeof (iph->addrs) !=sizeof (fl4->addrs)); +memcpy (&iph->addrs, &fl4->addrs,sizeof (fl4->addrs)); }/* Note: skb->sk can be different from sk, in case of tunnels */
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerRe: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
Quoted 53 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in struct flowi4, struct ipv4hdr, and struct ipv6hdr around members saddr and daddr, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of saddr."pahole" shows no size nor member offset changes to struct flowi4. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
Note that since this is a UAPI header,
struct_group()has been open coded.Signed-off-by Kees Cook <[email protected]>--- include/net/flow.h | 6 ++++-- include/uapi/linux/if_ether.h | 12 ++++++++++-- include/uapi/linux/ip.h | 12 ++++++++++-- include/uapi/linux/ipv6.h | 12 ++++++++++-- net/core/flow_dissector.c | 10 ++++++---- net/ipv4/ip_output.c | 6 ++---- 6 files changed, 42 insertions(+), 16 deletions(-)include/net/flow.h +4
-2@@ -81,8 +81,10 @@ struct flowi4 {#define flowi4_multipath_hash __fl_common.flowic_multipath_hash/* (saddr,daddr) must be grouped, same order as in IP header */ -__be32 saddr; -__be32 daddr; +struct_group (addrs, + __be32 saddr; + __be32 daddr; + );union flowi_uli uli;#define fl4_sport uli.ports.sportinclude/uapi/linux/if_ether.h +0
-1@@ -163,8 +163,16 @@#if __UAPI_DEF_ETHHDR struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
include/uapi/linux/if_ether.h line 174
Quoted 10 lines
include/uapi/linux/if_ether.h +9
-1-unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs;
A union of the same fields in the same structure in the same way?
Ah, because struct_group() can not be used here? Still feels odd to see in a userspace-visible header.
Quoted 13 lines
include/uapi/linux/if_ether.h +1
-0+ };__be16 h_proto;/* packet type ID field */ } __attribute__((packed));#endif include/uapi/linux/ip.h +0
-1@@ -100,8 +100,16 @@ struct iphdr {__u8 ttl;__u8 protocol;__sum16 check; -__be32 saddr;
include/uapi/linux/ip.h struct iphdr { · line 111
Quoted 10 lines
include/uapi/linux/ip.h +9
-1-__be32 daddr; +union { +struct { +__be32 saddr; +__be32 daddr; + } addrs; +struct { +__be32 saddr; +__be32 daddr; + };
Same here (except you named the first struct addrs, not the second, unlike above).
Quoted 13 lines
include/uapi/linux/ip.h +1
-0+ };/*The options start here. */ };include/uapi/linux/ipv6.h +0
-1@@ -130,8 +130,16 @@ struct ipv6hdr {__u8 nexthdr;__u8 hop_limit; -struct in6_addr saddr;
include/uapi/linux/ipv6.h struct ipv6hdr { · line 141
Quoted 10 lines
include/uapi/linux/ipv6.h +9
-1-struct in6_addr daddr; +union { +struct { +struct in6_addr saddr; +struct in6_addr daddr; + } addrs; +struct { +struct in6_addr saddr; +struct in6_addr daddr; + };
addrs first? Consistancy is key :)
thanks,
greg k-h
Re: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
Quoted 110 lines · Greg Kroah-Hartman
Quoted 53 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in struct flowi4, struct ipv4hdr, and struct ipv6hdr around members saddr and daddr, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of saddr."pahole" shows no size nor member offset changes to struct flowi4. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
Note that since this is a UAPI header,
struct_group()has been open coded.Signed-off-by Kees Cook <[email protected]>--- include/net/flow.h | 6 ++++-- include/uapi/linux/if_ether.h | 12 ++++++++++-- include/uapi/linux/ip.h | 12 ++++++++++-- include/uapi/linux/ipv6.h | 12 ++++++++++-- net/core/flow_dissector.c | 10 ++++++---- net/ipv4/ip_output.c | 6 ++---- 6 files changed, 42 insertions(+), 16 deletions(-)include/net/flow.h +4
-2@@ -81,8 +81,10 @@ struct flowi4 {#define flowi4_multipath_hash __fl_common.flowic_multipath_hash/* (saddr,daddr) must be grouped, same order as in IP header */ -__be32 saddr; -__be32 daddr; +struct_group (addrs, + __be32 saddr; + __be32 daddr; + );union flowi_uli uli;#define fl4_sport uli.ports.sportinclude/uapi/linux/if_ether.h +0
-1@@ -163,8 +163,16 @@#if __UAPI_DEF_ETHHDR struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */include/uapi/linux/if_ether.h line 174
Quoted 10 lines
include/uapi/linux/if_ether.h +9
-1-unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs;A union of the same fields in the same structure in the same way?
Ah, because
struct_group()can not be used here? Still feels odd to see in a userspace-visible header.Quoted 13 lines
include/uapi/linux/if_ether.h +1
-0+ };__be16 h_proto;/* packet type ID field */ } __attribute__((packed));#endif include/uapi/linux/ip.h +0
-1@@ -100,8 +100,16 @@ struct iphdr {__u8 ttl;__u8 protocol;__sum16 check; -__be32 saddr;include/uapi/linux/ip.h struct iphdr { · line 111
Quoted 10 lines
include/uapi/linux/ip.h +9
-1-__be32 daddr; +union { +struct { +__be32 saddr; +__be32 daddr; + } addrs; +struct { +__be32 saddr; +__be32 daddr; + };Same here (except you named the first struct addrs, not the second, unlike above).
Quoted 12 lines
include/uapi/linux/ip.h +1
-0+ };/*The options start here. */ };include/uapi/linux/ipv6.h +0
-0@@ -130,8 +130,16 @@ struct ipv6hdr {__u8 nexthdr;__u8 hop_limit;
Quoted 13 lines
include/uapi/linux/ipv6.h struct ipv6hdr { · line 141
Quoted 11 lines
include/uapi/linux/ipv6.h +9
-2-struct in6_addr saddr; -struct in6_addr daddr; +union { +struct { +struct in6_addr saddr; +struct in6_addr daddr; + } addrs; +struct { +struct in6_addr saddr; +struct in6_addr daddr; + };addrs first? Consistancy is key :)
I think addrs should be second. In general, I think all newly added non-anonymous structures should be second.
Thanks
--
Gustavo
Greg Kroah-Hartman
maintainerRe: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
Quoted 127 lines · Gustavo A. R. Silva
Quoted 110 lines · Greg Kroah-Hartman
Quoted 53 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in struct flowi4, struct ipv4hdr, and struct ipv6hdr around members saddr and daddr, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of saddr."pahole" shows no size nor member offset changes to struct flowi4. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
Note that since this is a UAPI header,
struct_group()has been open coded.Signed-off-by Kees Cook <[email protected]>--- include/net/flow.h | 6 ++++-- include/uapi/linux/if_ether.h | 12 ++++++++++-- include/uapi/linux/ip.h | 12 ++++++++++-- include/uapi/linux/ipv6.h | 12 ++++++++++-- net/core/flow_dissector.c | 10 ++++++---- net/ipv4/ip_output.c | 6 ++---- 6 files changed, 42 insertions(+), 16 deletions(-)include/net/flow.h +4
-2@@ -81,8 +81,10 @@ struct flowi4 {#define flowi4_multipath_hash __fl_common.flowic_multipath_hash/* (saddr,daddr) must be grouped, same order as in IP header */ -__be32 saddr; -__be32 daddr; +struct_group (addrs, + __be32 saddr; + __be32 daddr; + );union flowi_uli uli;#define fl4_sport uli.ports.sportinclude/uapi/linux/if_ether.h +0
-1@@ -163,8 +163,16 @@#if __UAPI_DEF_ETHHDR struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */include/uapi/linux/if_ether.h line 174
Quoted 10 lines
include/uapi/linux/if_ether.h +9
-1-unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs;A union of the same fields in the same structure in the same way?
Ah, because
struct_group()can not be used here? Still feels odd to see in a userspace-visible header.Quoted 13 lines
include/uapi/linux/if_ether.h +1
-0+ };__be16 h_proto;/* packet type ID field */ } __attribute__((packed));#endif include/uapi/linux/ip.h +0
-1@@ -100,8 +100,16 @@ struct iphdr {__u8 ttl;__u8 protocol;__sum16 check; -__be32 saddr;include/uapi/linux/ip.h struct iphdr { · line 111
Quoted 10 lines
include/uapi/linux/ip.h +9
-1-__be32 daddr; +union { +struct { +__be32 saddr; +__be32 daddr; + } addrs; +struct { +__be32 saddr; +__be32 daddr; + };Same here (except you named the first struct addrs, not the second, unlike above).
Quoted 12 lines
include/uapi/linux/ip.h +1
-0+ };/*The options start here. */ };include/uapi/linux/ipv6.h +0
-0@@ -130,8 +130,16 @@ struct ipv6hdr {__u8 nexthdr;__u8 hop_limit;Quoted 13 lines
include/uapi/linux/ipv6.h struct ipv6hdr { · line 141
Quoted 11 lines
include/uapi/linux/ipv6.h +9
-2-struct in6_addr saddr; -struct in6_addr daddr; +union { +struct { +struct in6_addr saddr; +struct in6_addr daddr; + } addrs; +struct { +struct in6_addr saddr; +struct in6_addr daddr; + };addrs first? Consistancy is key :)
Quoted 2 lines
I think addrs should be second. In general, I think all newly added non-anonymous structures should be second.
Why not use a local version of the macro like was done in the DRM header file, to make it always work the same and more obvious what is happening? If I were a userspace developer and saw the above, I would think that the kernel developers have lost it :)
thanks,
greg k-h
Re: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
Quoted 128 lines · Greg Kroah-Hartman
Quoted 127 lines · Gustavo A. R. Silva
Quoted 123 lines · Greg Kroah-Hartman
Quoted 53 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in struct flowi4, struct ipv4hdr, and struct ipv6hdr around members saddr and daddr, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of saddr."pahole" shows no size nor member offset changes to struct flowi4. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
Note that since this is a UAPI header,
struct_group()has been open coded.Signed-off-by Kees Cook <[email protected]>--- include/net/flow.h | 6 ++++-- include/uapi/linux/if_ether.h | 12 ++++++++++-- include/uapi/linux/ip.h | 12 ++++++++++-- include/uapi/linux/ipv6.h | 12 ++++++++++-- net/core/flow_dissector.c | 10 ++++++---- net/ipv4/ip_output.c | 6 ++---- 6 files changed, 42 insertions(+), 16 deletions(-)include/net/flow.h +4
-2@@ -81,8 +81,10 @@ struct flowi4 {#define flowi4_multipath_hash __fl_common.flowic_multipath_hash/* (saddr,daddr) must be grouped, same order as in IP header */ -__be32 saddr; -__be32 daddr; +struct_group (addrs, + __be32 saddr; + __be32 daddr; + );union flowi_uli uli;#define fl4_sport uli.ports.sportinclude/uapi/linux/if_ether.h +0
-1@@ -163,8 +163,16 @@#if __UAPI_DEF_ETHHDR struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */include/uapi/linux/if_ether.h line 174
Quoted 10 lines
include/uapi/linux/if_ether.h +9
-1-unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs;A union of the same fields in the same structure in the same way?
Ah, because
struct_group()can not be used here? Still feels odd to see in a userspace-visible header.Quoted 13 lines
include/uapi/linux/if_ether.h +1
-0+ };__be16 h_proto;/* packet type ID field */ } __attribute__((packed));#endif include/uapi/linux/ip.h +0
-1@@ -100,8 +100,16 @@ struct iphdr {__u8 ttl;__u8 protocol;__sum16 check; -__be32 saddr;include/uapi/linux/ip.h struct iphdr { · line 111
Quoted 10 lines
include/uapi/linux/ip.h +9
-1-__be32 daddr; +union { +struct { +__be32 saddr; +__be32 daddr; + } addrs; +struct { +__be32 saddr; +__be32 daddr; + };Same here (except you named the first struct addrs, not the second, unlike above).
Quoted 13 lines
include/uapi/linux/ip.h +1
-0+ };/*The options start here. */ };include/uapi/linux/ipv6.h +0
-1@@ -130,8 +130,16 @@ struct ipv6hdr {__u8 nexthdr;__u8 hop_limit; -struct in6_addr saddr;include/uapi/linux/ipv6.h struct ipv6hdr { · line 141
Quoted 10 lines
include/uapi/linux/ipv6.h +9
-1-struct in6_addr daddr; +union { +struct { +struct in6_addr saddr; +struct in6_addr daddr; + } addrs; +struct { +struct in6_addr saddr; +struct in6_addr daddr; + };addrs first? Consistancy is key :)
Quoted 7 lines
Quoted 2 lines
I think addrs should be second. In general, I think all newly added non-anonymous structures should be second.
Why not use a local version of the macro like was done in the DRM header file, to make it always work the same and more obvious what is happening? If I were a userspace developer and saw the above, I would think that the kernel developers have lost it :)
Then don't take a look at this[1]. :p
--
Gustavo
[1] https://git.kernel.org/linus/c0a744dcaa29e9537e8607ae9c965ad936124a4d
Re: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
Quoted 131 lines · Gustavo A. R. Silva
Quoted 128 lines · Greg Kroah-Hartman
Quoted 127 lines · Gustavo A. R. Silva
Quoted 123 lines · Greg Kroah-Hartman
Quoted 53 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in struct flowi4, struct ipv4hdr, and struct ipv6hdr around members saddr and daddr, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of saddr."pahole" shows no size nor member offset changes to struct flowi4. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
Note that since this is a UAPI header,
struct_group()has been open coded.Signed-off-by Kees Cook <[email protected]>--- include/net/flow.h | 6 ++++-- include/uapi/linux/if_ether.h | 12 ++++++++++-- include/uapi/linux/ip.h | 12 ++++++++++-- include/uapi/linux/ipv6.h | 12 ++++++++++-- net/core/flow_dissector.c | 10 ++++++---- net/ipv4/ip_output.c | 6 ++---- 6 files changed, 42 insertions(+), 16 deletions(-)include/net/flow.h +4
-2@@ -81,8 +81,10 @@ struct flowi4 {#define flowi4_multipath_hash __fl_common.flowic_multipath_hash/* (saddr,daddr) must be grouped, same order as in IP header */ -__be32 saddr; -__be32 daddr; +struct_group (addrs, + __be32 saddr; + __be32 daddr; + );union flowi_uli uli;#define fl4_sport uli.ports.sportinclude/uapi/linux/if_ether.h +0
-1@@ -163,8 +163,16 @@#if __UAPI_DEF_ETHHDR struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */include/uapi/linux/if_ether.h line 174
Quoted 10 lines
include/uapi/linux/if_ether.h +9
-1-unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs;A union of the same fields in the same structure in the same way?
Ah, because
struct_group()can not be used here? Still feels odd to see in a userspace-visible header.Quoted 13 lines
include/uapi/linux/if_ether.h +1
-0+ };__be16 h_proto;/* packet type ID field */ } __attribute__((packed));#endif include/uapi/linux/ip.h +0
-1@@ -100,8 +100,16 @@ struct iphdr {__u8 ttl;__u8 protocol;__sum16 check; -__be32 saddr;include/uapi/linux/ip.h struct iphdr { · line 111
Quoted 10 lines
include/uapi/linux/ip.h +9
-1-__be32 daddr; +union { +struct { +__be32 saddr; +__be32 daddr; + } addrs; +struct { +__be32 saddr; +__be32 daddr; + };Same here (except you named the first struct addrs, not the second, unlike above).
Quoted 13 lines
include/uapi/linux/ip.h +1
-0+ };/*The options start here. */ };include/uapi/linux/ipv6.h +0
-1@@ -130,8 +130,16 @@ struct ipv6hdr {__u8 nexthdr;__u8 hop_limit; -struct in6_addr saddr;include/uapi/linux/ipv6.h struct ipv6hdr { · line 141
Quoted 10 lines
include/uapi/linux/ipv6.h +9
-1-struct in6_addr daddr; +union { +struct { +struct in6_addr saddr; +struct in6_addr daddr; + } addrs; +struct { +struct in6_addr saddr; +struct in6_addr daddr; + };addrs first? Consistancy is key :)
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
I think addrs should be second. In general, I think all newly added non-anonymous structures should be second.
Why not use a local version of the macro like was done in the DRM header file, to make it always work the same and more obvious what is
Yep; I agree. That one looks just fine. :)
--
Gustavo
Greg Kroah-Hartman
maintainerRe: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
In reply to Gustavo A. R. SilvaQuoted 11 lines · Gustavo A. R. Silva
Quoted 4 lines
Why not use a local version of the macro like was done in the DRM header file, to make it always work the same and more obvious what is happening? If I were a userspace developer and saw the above, I would think that the kernel developers have lost it :)
Then don't take a look at this[1]. :p
--
Gustavo[1] https://git.kernel.org/linus/c0a744dcaa29e9537e8607ae9c965ad936124a4d
That one at least looks a "little" different so maybe it could be seen as semi-reasonable :)
Re: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
In reply to Greg Kroah-HartmanQuoted 15 lines · Greg Kroah-Hartman
include/uapi/linux/if_ether.h line 174
Quoted 12 lines
struct ethhdr {
include/uapi/linux/if_ether.h +9
-2-unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ -unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs;A union of the same fields in the same structure in the same way?
Quoted 2 lines
Ah, because
struct_group()can not be used here? Still feels odd to see in a userspace-visible header.
Yeah, there is some inconsistency here. I will clean this up for v2.
Is there a place we can put kernel-specific macros for use in UAPI headers? (I need to figure out where things like __kernel_size_t get defined...)
Signature · 1 line
Kees Cook
Re: [PATCH 19/64] ip: Use struct_group() for memcpy() regions
Quoted 16 lines · Kees Cook
Quoted 15 lines · Greg Kroah-Hartman
include/uapi/linux/if_ether.h line 174
Quoted 12 lines
struct ethhdr {
include/uapi/linux/if_ether.h +9
-2-unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ -unsigned char h_source[ETH_ALEN ];/* source ether addr */ +union { +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + }; +struct { +unsigned char h_dest[ETH_ALEN ];/* destination eth addr */ +unsigned char h_source[ETH_ALEN ];/* source ether addr */ + } addrs;A union of the same fields in the same structure in the same way?
Quoted 8 lines
Quoted 2 lines
Ah, because
struct_group()can not be used here? Still feels odd to see in a userspace-visible header.Yeah, there is some inconsistency here. I will clean this up for v2.
Is there a place we can put kernel-specific macros for use in UAPI headers? (I need to figure out where things like
__kernel_size_tget defined...)
How about using two memset() calls to clear h_dest[] and h_source[] instead of modifying the uapi header?
Thanks,
Bart.
PATCH 20/64 intersil: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct hfa384x_tx_frame around members frame_control, duration_id, addr1, addr2, addr3, and seq_ctrl, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of frame_control.
"pahole" shows no size nor member offset changes to struct hfa384x_tx_frame. "objdump -d" shows no object code changes.
--- drivers/net/wireless/intersil/hostap/hostap_hw.c | 5 +++-- drivers/net/wireless/intersil/hostap/hostap_wlan.h | 14 ++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-)
drivers/net/wireless/intersil/hostap/hostap_hw.c +3 -2
@@ -1812,8 +1812,9 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)memset (&txdesc,0 ,sizeof (txdesc));/* skb->data starts with txdesc->frame_control */ - hdr_len =24 ; -skb_copy_from_linear_data (skb, &txdesc.frame_control, hdr_len); + hdr_len =sizeof (txdesc.frame); +BUILD_BUG_ON (hdr_len !=24 ); +skb_copy_from_linear_data (skb, &txdesc.frame, hdr_len);if (ieee80211_is_data (txdesc.frame_control) &&ieee80211_has_a4 (txdesc.frame_control) && skb->len >=30 ) {
drivers/net/wireless/intersil/hostap/hostap_wlan.h +8 -6
@@ -115,12 +115,14 @@ struct hfa384x_tx_frame {__le16 tx_control;/* HFA384X_TX_CTRL_ flags */ /* 802.11 */ -__le16 frame_control;/* parts not used */ -__le16 duration_id; -u8 addr1[ETH_ALEN ]; -u8 addr2[ETH_ALEN ];/* filled by firmware */ -u8 addr3[ETH_ALEN ]; -__le16 seq_ctrl;/* filled by firmware */ +struct_group (frame, + __le16 frame_control; /* parts not used */ + __le16 duration_id; + u8 addr1[ETH_ALEN]; +u8 addr2[ETH_ALEN ];/* filled by firmware */ +u8 addr3[ETH_ALEN ]; +__le16 seq_ctrl;/* filled by firmware */ + );u8 addr4[ETH_ALEN ];__le16 data_len;
Signature · 1 line
2.30.2
PATCH 21/64 cxgb4: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct fw_eth_tx_pkt_vm_wr around members ethmacdst, ethmacsrc, ethtype, and vlantci, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of ethmacdst.
"pahole" shows no size nor member offset changes to struct fw_eth_tx_pkt_vm_wr. "objdump -d" shows no object code changes.
--- drivers/net/ethernet/chelsio/cxgb4/sge.c | 8 +++++--- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 10 ++++++---- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 7 ++----- 3 files changed, 13 insertions(+), 12 deletions(-)
drivers/net/ethernet/chelsio/cxgb4/sge.c +5 -3
@@ -1842,8 +1842,10 @@ static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb,* (including the VLAN tag) into the header so we reject anything * smaller than that ... */ - fw_hdr_copy_len =sizeof (wr->ethmacdst) +sizeof (wr->ethmacsrc) + -sizeof (wr->ethtype) +sizeof (wr->vlantci); +BUILD_BUG_ON (sizeof (wr->firmware) != + (sizeof (wr->ethmacdst) +sizeof (wr->ethmacsrc) + +sizeof (wr->ethtype) +sizeof (wr->vlantci))); + fw_hdr_copy_len =sizeof (wr->firmware); ret =cxgb4_validate_skb (skb, dev, fw_hdr_copy_len);if (ret) goto out_free;
@@ -1924,7 +1926,7 @@ static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb, wr->equiq_to_len16 =cpu_to_be32 (wr_mid); wr->r3[0 ] =cpu_to_be32 (0 ); wr->r3[1 ] =cpu_to_be32 (0 ); -skb_copy_from_linear_data (skb, (void *)wr->ethmacdst, fw_hdr_copy_len); +skb_copy_from_linear_data (skb, &wr->firmware, fw_hdr_copy_len); end = (u64 *)wr + flits;/* If this is a Large Send Offload packet we'll put in an LSO CPL
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +6 -4
@@ -794,10 +794,12 @@ struct fw_eth_tx_pkt_vm_wr {__be32 op_immdlen;__be32 equiq_to_len16;__be32 r3[2 ]; -u8 ethmacdst[6 ]; -u8 ethmacsrc[6 ]; -__be16 ethtype; -__be16 vlantci; +struct_group (firmware, + u8 ethmacdst[ETH_ALEN]; +u8 ethmacsrc[ETH_ALEN ]; +__be16 ethtype; +__be16 vlantci; + ); };#define FW_CMD_MAX_TIMEOUT 10000
drivers/net/ethernet/chelsio/cxgb4vf/sge.c +2 -5
@@ -1167,10 +1167,7 @@ netdev_tx_t t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)struct cpl_tx_pkt_core *cpl;const struct skb_shared_info *ssi;dma_addr_t addr[MAX_SKB_FRAGS +1 ]; -const size_t fw_hdr_copy_len = (sizeof (wr->ethmacdst) + -sizeof (wr->ethmacsrc) + -sizeof (wr->ethtype) + -sizeof (wr->vlantci)); +const size_t fw_hdr_copy_len =sizeof (wr->firmware);/* * The chip minimum packet length is 10 octets but the firmware
@@ -1267,7 +1264,7 @@ netdev_tx_t t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) wr->equiq_to_len16 =cpu_to_be32 (wr_mid); wr->r3[0 ] =cpu_to_be32 (0 ); wr->r3[1 ] =cpu_to_be32 (0 ); -skb_copy_from_linear_data (skb, (void *)wr->ethmacdst, fw_hdr_copy_len); +skb_copy_from_linear_data (skb, &wr->firmware, fw_hdr_copy_len); end = (u64 *)wr + flits;/*
Signature · 1 line
2.30.2
PATCH 22/64 bnx2x: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct nig_stats around members egress_mac_pkt0_lo, egress_mac_pkt0_hi, egress_mac_pkt1_lo, and egress_mac_pkt1_hi (and the respective members in struct bnx2x_eth_stats), so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of struct bnx2x_eth_stats's rx_stat_ifhcinbadoctets_hi.
"pahole" shows no size nor member offset changes to either struct. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
Additionally adds BUILD_BUG_ON() to compare the separate struct group sizes.
--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 7 ++++--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h | 14 ++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-)
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c +4 -3
@@ -849,7 +849,8 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)memcpy (old, new,sizeof (struct nig_stats )); -memcpy (&(estats->rx_stat_ifhcinbadoctets_hi), &(pstats->mac_stx[1 ]), +BUILD_BUG_ON (sizeof (estats->shared) !=sizeof (pstats->mac_stx[1 ])); +memcpy (&(estats->shared), &(pstats->mac_stx[1 ]),sizeof (struct mac_stx )); estats->brb_drop_hi = pstats->brb_drop_hi; estats->brb_drop_lo = pstats->brb_drop_lo;
@@ -1634,9 +1635,9 @@ void bnx2x_stats_init(struct bnx2x *bp)REG_RD (bp,NIG_REG_STAT0_BRB_TRUNCATE + port*0x38 );if (!CHIP_IS_E3 (bp)) {REG_RD_DMAE (bp,NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50 , - &(bp->port.old_nig_stats.egress_mac_pkt0_lo),2 ); + &(bp->port.old_nig_stats.egress_mac_pkt0),2 );REG_RD_DMAE (bp,NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50 , - &(bp->port.old_nig_stats.egress_mac_pkt1_lo),2 ); + &(bp->port.old_nig_stats.egress_mac_pkt1),2 ); }/* Prepare statistics ramrod data */
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h +10 -4
@@ -36,10 +36,14 @@ struct nig_stats {u32 pbf_octets;u32 pbf_packet;u32 safc_inp; -u32 egress_mac_pkt0_lo; -u32 egress_mac_pkt0_hi; -u32 egress_mac_pkt1_lo; -u32 egress_mac_pkt1_hi; +struct_group (egress_mac_pkt0, + u32 egress_mac_pkt0_lo; + u32 egress_mac_pkt0_hi; + ); +struct_group (egress_mac_pkt1, + u32 egress_mac_pkt1_lo; + u32 egress_mac_pkt1_hi; + ); };enum bnx2x_stats_event {
@@ -83,6 +87,7 @@ struct bnx2x_eth_stats {u32 no_buff_discard_hi;u32 no_buff_discard_lo; + struct_group(shared, u32 rx_stat_ifhcinbadoctets_hi; u32 rx_stat_ifhcinbadoctets_lo; u32 tx_stat_ifhcoutbadoctets_hi;
@@ -159,6 +164,7 @@ struct bnx2x_eth_stats {u32 tx_stat_dot3statsinternalmactransmiterrors_lo;u32 tx_stat_bmac_ufl_hi;u32 tx_stat_bmac_ufl_lo; + );u32 pause_frames_received_hi;u32 pause_frames_received_lo;
Signature · 1 line
2.30.2
PATCH 23/64 drm/amd/pm: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in structs:
struct atom_smc_dpm_info_v4_5 struct atom_smc_dpm_info_v4_6 struct atom_smc_dpm_info_v4_7 struct atom_smc_dpm_info_v4_10 PPTable_t
so the grouped members can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of the first member.
"pahole" shows no size nor member offset changes to any structs. "objdump -d" shows no object code changes.
--- drivers/gpu/drm/amd/include/atomfirmware.h | 9 ++++++++- .../gpu/drm/amd/pm/inc/smu11_driver_if_arcturus.h | 3 ++- drivers/gpu/drm/amd/pm/inc/smu11_driver_if_navi10.h | 3 ++- .../gpu/drm/amd/pm/inc/smu13_driver_if_aldebaran.h | 3 ++- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 6 +++--- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 12 ++++++++---- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 6 +++--- 7 files changed, 28 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/include/atomfirmware.h +8 -1
@@ -2081,6 +2081,7 @@ struct atom_smc_dpm_info_v4_5 {struct atom_common_table_header table_header;// SECTION: BOARD PARAMETERS +struct_group (dpm_info,// I2C Control struct smudpm_i2c_controller_config_v2 I2cControllers[8];
@@ -2159,7 +2160,7 @@ struct atom_smc_dpm_info_v4_5uint32_t MvddRatio;// This is used for MVDD Vid workaround. It has 16 fractional bits (Q16.16) uint32_t BoardReserved[9 ]; - + ); };struct atom_smc_dpm_info_v4_6
@@ -2168,6 +2169,7 @@ struct atom_smc_dpm_info_v4_6// section: board parameters uint32_t i2c_padding[3 ];// old i2c control are moved to new area + struct_group(dpm_info, uint16_t maxvoltagestepgfx; // in mv(q2) max voltage step that smu will request. multiple steps are taken if voltage change exceeds this value.uint16_t maxvoltagestepsoc;// in mv(q2) max voltage step that smu will request. multiple steps are taken if voltage change exceeds this value.
@@ -2246,12 +2248,14 @@ struct atom_smc_dpm_info_v4_6// reserved uint32_t boardreserved[10 ]; + ); };struct atom_smc_dpm_info_v4_7 {struct atom_common_table_header table_header;// SECTION: BOARD PARAMETERS + struct_group(dpm_info,// I2C Control struct smudpm_i2c_controller_config_v2 I2cControllers[8];
@@ -2348,6 +2352,7 @@ struct atom_smc_dpm_info_v4_7uint8_t Padding8_Psi2;uint32_t BoardReserved[5 ]; + ); };struct smudpm_i2c_controller_config_v3
@@ -2478,6 +2483,7 @@ struct atom_smc_dpm_info_v4_10struct atom_common_table_header table_header;// SECTION: BOARD PARAMETERS +struct_group (dpm_info,// Telemetry Settings uint16_t GfxMaxCurrent; // in Amps uint8_t GfxOffset; // in Amps
@@ -2524,6 +2530,7 @@ struct atom_smc_dpm_info_v4_10uint16_t spare5;uint32_t reserved[16 ]; + ); };/*
drivers/gpu/drm/amd/pm/inc/smu11_driver_if_arcturus.h +2 -1
@@ -643,6 +643,7 @@ typedef struct {// SECTION: BOARD PARAMETERS // SVI2 Board Parameters + struct_group(v4_6, uint16_t MaxVoltageStepGfx; // In mV(Q2) Max voltage step that SMU will request. Multiple steps are taken if voltage change exceeds this value.uint16_t MaxVoltageStepSoc;// In mV(Q2) Max voltage step that SMU will request. Multiple steps are taken if voltage change exceeds this value.
@@ -728,10 +729,10 @@ typedef struct {uint32_t BoardVoltageCoeffB;// decode by /1000 uint32_t BoardReserved[7 ]; + );// Padding for MMHUB - do not modify this uint32_t MmHubPadding[8 ];// SMU internal use - } PPTable_t; typedef struct {
drivers/gpu/drm/amd/pm/inc/smu11_driver_if_navi10.h +2 -1
@@ -725,6 +725,7 @@ typedef struct {uint32_t Reserved[8 ];// SECTION: BOARD PARAMETERS +struct_group (v4,// I2C Control I2cControllerConfig_t I2cControllers[NUM_I2C_CONTROLLERS];
@@ -809,10 +810,10 @@ typedef struct {uint8_t Padding8_Loadline;uint32_t BoardReserved[8 ]; + );// Padding for MMHUB - do not modify this uint32_t MmHubPadding[8 ];// SMU internal use - } PPTable_t; typedef struct {
drivers/gpu/drm/amd/pm/inc/smu13_driver_if_aldebaran.h +2 -1
@@ -390,6 +390,7 @@ typedef struct {uint32_t spare3[14 ];// SECTION: BOARD PARAMETERS +struct_group (v4_10,// Telemetry Settings uint16_t GfxMaxCurrent; // in Amps int8_t GfxOffset; // in Amps
@@ -444,7 +445,7 @@ typedef struct {//reserved uint32_t reserved[14 ]; - + ); } PPTable_t; typedef struct {
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +3 -3
@@ -463,11 +463,11 @@ static int arcturus_append_powerplay_table(struct smu_context *smu) smc_dpm_table->table_header.format_revision, smc_dpm_table->table_header.content_revision); +BUILD_BUG_ON (sizeof (smc_pptable->v4_6) !=sizeof (smc_dpm_table->dpm_info));if ((smc_dpm_table->table_header.format_revision ==4 ) && (smc_dpm_table->table_header.content_revision ==6 )) -memcpy (&smc_pptable->MaxVoltageStepGfx, - &smc_dpm_table->maxvoltagestepgfx, -sizeof (*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_6 , maxvoltagestepgfx)); +memcpy (&smc_pptable->v4_6, &smc_dpm_table->dpm_info, +sizeof (smc_dpm_table->dpm_info));return 0 ; }
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +8 -4
@@ -431,16 +431,20 @@ static int navi10_append_powerplay_table(struct smu_context *smu)switch (smc_dpm_table->table_header.content_revision) {case 5 :/* nv10 and nv14 */ -memcpy (smc_pptable->I2cControllers, smc_dpm_table->I2cControllers, -sizeof (*smc_dpm_table) -sizeof (smc_dpm_table->table_header)); +BUILD_BUG_ON (sizeof (smc_pptable->v4) != +sizeof (smc_dpm_table->dpm_info)); +memcpy (&smc_pptable->v4, &smc_dpm_table->dpm_info, +sizeof (smc_dpm_table->dpm_info));break ;case 7 :/* nv12 */ ret =amdgpu_atombios_get_data_table (adev, index,NULL ,NULL ,NULL , (uint8_t **)&smc_dpm_table_v4_7);if (ret)return ret; -memcpy (smc_pptable->I2cControllers, smc_dpm_table_v4_7->I2cControllers, -sizeof (*smc_dpm_table_v4_7) -sizeof (smc_dpm_table_v4_7->table_header)); +BUILD_BUG_ON (sizeof (smc_pptable->v4) != +sizeof (smc_dpm_table_v4_7->dpm_info)); +memcpy (&smc_pptable->v4, &smc_dpm_table_v4_7->dpm_info, +sizeof (smc_dpm_table_v4_7->dpm_info));break ;default : dev_err(smu->adev->dev, "smc_dpm_info with unsupported content revision %d!\n",
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +3 -3
@@ -407,11 +407,11 @@ static int aldebaran_append_powerplay_table(struct smu_context *smu) smc_dpm_table->table_header.format_revision, smc_dpm_table->table_header.content_revision); +BUILD_BUG_ON (sizeof (smc_pptable->v4_10) !=sizeof (smc_dpm_table->dpm_info));if ((smc_dpm_table->table_header.format_revision ==4 ) && (smc_dpm_table->table_header.content_revision ==10 )) -memcpy (&smc_pptable->GfxMaxCurrent, - &smc_dpm_table->GfxMaxCurrent, -sizeof (*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_10 , GfxMaxCurrent)); +memcpy (&smc_pptable->v4_10, &smc_dpm_table->dpm_info, +sizeof (smc_dpm_table->dpm_info));return 0 ; }
Signature · 1 line
2.30.2
Re: [PATCH 23/64] drm/amd/pm: Use struct_group() for memcpy() region
Quoted 11 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in structs:struct atom_smc_dpm_info_v4_5 struct atom_smc_dpm_info_v4_6 struct atom_smc_dpm_info_v4_7 struct atom_smc_dpm_info_v4_10 PPTable_t
Quoted 7 lines
so the grouped members can be referenced together. This will allow
memcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of the first member."pahole" shows no size nor member offset changes to any structs. "objdump -d" shows no object code changes.
These headers represent interfaces with firmware running on microcontrollers, so if the sizes or offsets change that could cause a problem. That doesn't seem to be the case, but something to keep in mind. Patch is:
Feel free to take this through whatever tree makes sense.
Alex
Quoted 219 lines
Signed-off-by Kees Cook <[email protected]>--- drivers/gpu/drm/amd/include/atomfirmware.h | 9 ++++++++- .../gpu/drm/amd/pm/inc/smu11_driver_if_arcturus.h | 3 ++- drivers/gpu/drm/amd/pm/inc/smu11_driver_if_navi10.h | 3 ++- .../gpu/drm/amd/pm/inc/smu13_driver_if_aldebaran.h | 3 ++- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 6 +++--- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 12 ++++++++---- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 6 +++--- 7 files changed, 28 insertions(+), 14 deletions(-)drivers/gpu/drm/amd/include/atomfirmware.h +8
-1@@ -2081,6 +2081,7 @@ struct atom_smc_dpm_info_v4_5 {struct atom_common_table_header table_header;// SECTION: BOARD PARAMETERS +struct_group (dpm_info,// I2C Control struct smudpm_i2c_controller_config_v2 I2cControllers[8];@@ -2159,7 +2160,7 @@ struct atom_smc_dpm_info_v4_5uint32_t MvddRatio;// This is used for MVDD Vid workaround. It has 16 fractional bits (Q16.16) uint32_t BoardReserved[9 ]; - + ); };struct atom_smc_dpm_info_v4_6 @@ -2168,6 +2169,7 @@ struct atom_smc_dpm_info_v4_6// section: board parameters uint32_t i2c_padding[3 ];// old i2c control are moved to new area + struct_group(dpm_info, uint16_t maxvoltagestepgfx; // in mv(q2) max voltage step that smu will request. multiple steps are taken if voltage change exceeds this value.uint16_t maxvoltagestepsoc;// in mv(q2) max voltage step that smu will request. multiple steps are taken if voltage change exceeds this value. @@ -2246,12 +2248,14 @@ struct atom_smc_dpm_info_v4_6// reserved uint32_t boardreserved[10 ]; + ); };struct atom_smc_dpm_info_v4_7 {struct atom_common_table_header table_header;// SECTION: BOARD PARAMETERS + struct_group(dpm_info,// I2C Control struct smudpm_i2c_controller_config_v2 I2cControllers[8];@@ -2348,6 +2352,7 @@ struct atom_smc_dpm_info_v4_7uint8_t Padding8_Psi2;uint32_t BoardReserved[5 ]; + ); };struct smudpm_i2c_controller_config_v3 @@ -2478,6 +2483,7 @@ struct atom_smc_dpm_info_v4_10struct atom_common_table_header table_header;// SECTION: BOARD PARAMETERS +struct_group (dpm_info,// Telemetry Settings uint16_t GfxMaxCurrent; // in Amps uint8_t GfxOffset; // in Amps@@ -2524,6 +2530,7 @@ struct atom_smc_dpm_info_v4_10uint16_t spare5;uint32_t reserved[16 ]; + ); };/* drivers/gpu/drm/amd/pm/inc/smu11_driver_if_arcturus.h +2
-1@@ -643,6 +643,7 @@ typedef struct {// SECTION: BOARD PARAMETERS // SVI2 Board Parameters + struct_group(v4_6, uint16_t MaxVoltageStepGfx; // In mV(Q2) Max voltage step that SMU will request. Multiple steps are taken if voltage change exceeds this value.uint16_t MaxVoltageStepSoc;// In mV(Q2) Max voltage step that SMU will request. Multiple steps are taken if voltage change exceeds this value. @@ -728,10 +729,10 @@ typedef struct {uint32_t BoardVoltageCoeffB;// decode by /1000 uint32_t BoardReserved[7 ]; + );// Padding for MMHUB - do not modify this uint32_t MmHubPadding[8 ];// SMU internal use - } PPTable_t; typedef struct {drivers/gpu/drm/amd/pm/inc/smu11_driver_if_navi10.h +2
-1@@ -725,6 +725,7 @@ typedef struct {uint32_t Reserved[8 ];// SECTION: BOARD PARAMETERS +struct_group (v4,// I2C Control I2cControllerConfig_t I2cControllers[NUM_I2C_CONTROLLERS];@@ -809,10 +810,10 @@ typedef struct {uint8_t Padding8_Loadline;uint32_t BoardReserved[8 ]; + );// Padding for MMHUB - do not modify this uint32_t MmHubPadding[8 ];// SMU internal use - } PPTable_t; typedef struct {drivers/gpu/drm/amd/pm/inc/smu13_driver_if_aldebaran.h +2
-1@@ -390,6 +390,7 @@ typedef struct {uint32_t spare3[14 ];// SECTION: BOARD PARAMETERS +struct_group (v4_10,// Telemetry Settings uint16_t GfxMaxCurrent; // in Amps int8_t GfxOffset; // in Amps@@ -444,7 +445,7 @@ typedef struct {//reserved uint32_t reserved[14 ]; - + ); } PPTable_t; typedef struct {drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +3
-3@@ -463,11 +463,11 @@ static int arcturus_append_powerplay_table(struct smu_context *smu) smc_dpm_table->table_header.format_revision, smc_dpm_table->table_header.content_revision); +BUILD_BUG_ON (sizeof (smc_pptable->v4_6) !=sizeof (smc_dpm_table->dpm_info));if ((smc_dpm_table->table_header.format_revision ==4 ) && (smc_dpm_table->table_header.content_revision ==6 )) -memcpy (&smc_pptable->MaxVoltageStepGfx, - &smc_dpm_table->maxvoltagestepgfx, -sizeof (*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_6 , maxvoltagestepgfx)); +memcpy (&smc_pptable->v4_6, &smc_dpm_table->dpm_info, +sizeof (smc_dpm_table->dpm_info));return 0 ; }drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +8
-4@@ -431,16 +431,20 @@ static int navi10_append_powerplay_table(struct smu_context *smu)switch (smc_dpm_table->table_header.content_revision) {case 5 :/* nv10 and nv14 */ -memcpy (smc_pptable->I2cControllers, smc_dpm_table->I2cControllers, -sizeof (*smc_dpm_table) -sizeof (smc_dpm_table->table_header)); +BUILD_BUG_ON (sizeof (smc_pptable->v4) != +sizeof (smc_dpm_table->dpm_info)); +memcpy (&smc_pptable->v4, &smc_dpm_table->dpm_info, +sizeof (smc_dpm_table->dpm_info));break ;case 7 :/* nv12 */ ret =amdgpu_atombios_get_data_table (adev, index,NULL ,NULL ,NULL , (uint8_t **)&smc_dpm_table_v4_7);if (ret)return ret; -memcpy (smc_pptable->I2cControllers, smc_dpm_table_v4_7->I2cControllers, -sizeof (*smc_dpm_table_v4_7) -sizeof (smc_dpm_table_v4_7->table_header)); +BUILD_BUG_ON (sizeof (smc_pptable->v4) != +sizeof (smc_dpm_table_v4_7->dpm_info)); +memcpy (&smc_pptable->v4, &smc_dpm_table_v4_7->dpm_info, +sizeof (smc_dpm_table_v4_7->dpm_info));break ;default : dev_err(smu->adev->dev, "smc_dpm_info with unsupported content revision %d!\n",drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +3
-4@@ -407,11 +407,11 @@ static int aldebaran_append_powerplay_table(struct smu_context *smu) smc_dpm_table->table_header.format_revision, smc_dpm_table->table_header.content_revision); +BUILD_BUG_ON (sizeof (smc_pptable->v4_10) !=sizeof (smc_dpm_table->dpm_info));if ((smc_dpm_table->table_header.format_revision ==4 ) && (smc_dpm_table->table_header.content_revision ==10 )) -memcpy (&smc_pptable->GfxMaxCurrent, - &smc_dpm_table->GfxMaxCurrent, -sizeof (*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_10 , GfxMaxCurrent)); +memcpy (&smc_pptable->v4_10, &smc_dpm_table->dpm_info, +sizeof (smc_dpm_table->dpm_info));return 0 ; } --2.30.2
PATCH 24/64 staging: wlan-ng: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct hfa384x_tx_frame around members frame_control, duration_id, address[1-4], and sequence_control, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of frame_control.
"pahole" shows no size nor member offset changes to struct hfa384x_tx_frame. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
--- drivers/staging/wlan-ng/hfa384x.h | 16 +++++++++------- drivers/staging/wlan-ng/hfa384x_usb.c | 4 +++- 2 files changed, 12 insertions(+), 8 deletions(-)
drivers/staging/wlan-ng/hfa384x.h +9 -7
@@ -476,13 +476,15 @@ struct hfa384x_tx_frame {/*-- 802.11 Header Information --*/ -u16 frame_control; -u16 duration_id; -u8 address1[6 ]; -u8 address2[6 ]; -u8 address3[6 ]; -u16 sequence_control; -u8 address4[6 ]; +struct_group (p80211, + u16 frame_control; + u16 duration_id; + u8 address1[6]; +u8 address2[6 ]; +u8 address3[6 ]; +u16 sequence_control; +u8 address4[6 ]; + );__le16 data_len;/* little endian format */ /*-- 802.3 Header Information --*/
drivers/staging/wlan-ng/hfa384x_usb.c +3 -1
@@ -2516,7 +2516,9 @@ int hfa384x_drvr_txframe(struct hfa384x *hw, struct sk_buff *skb,cpu_to_le16s (&hw->txbuff.txfrm.desc.tx_control);/* copy the header over to the txdesc */ -memcpy (&hw->txbuff.txfrm.desc.frame_control, p80211_hdr, +BUILD_BUG_ON (sizeof (hw->txbuff.txfrm.desc.p80211) != +sizeof (union p80211_hdr )); +memcpy (&hw->txbuff.txfrm.desc.p80211, p80211_hdr,sizeof (union p80211_hdr ));/* if we're using host WEP, increase size by IV+ICV */
Signature · 1 line
2.30.2
Re: [PATCH 24/64] staging: wlan-ng: Use struct_group() for memcpy() region
Quoted 14 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in structhfa384x_tx_framearound membersframe_control,duration_id, address[1-4], andsequence_control, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end offrame_control."pahole" shows no size nor member offset changes to struct
hfa384x_tx_frame. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
Quoted 5 lines
Signed-off-by Kees Cook <[email protected]>--- drivers/staging/wlan-ng/hfa384x.h | 16 +++++++++------- drivers/staging/wlan-ng/hfa384x_usb.c | 4 +++- 2 files changed, 12 insertions(+), 8 deletions(-)
PATCH 25/64 drm/mga/mga_ioc32: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct drm32_mga_init around members chipset, sgram, maccess, fb_cpp, front_offset, front_pitch, back_offset, back_pitch, depth_cpp, depth_offset, depth_pitch, texture_offset, and texture_size, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of chipset.
"pahole" shows no size nor member offset changes to struct drm32_mga_init. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).
Note that since this includes a UAPI header, struct_group() has been explicitly redefined local to the header.
--- drivers/gpu/drm/mga/mga_ioc32.c | 30 ++++++++++++++------------ include/uapi/drm/mga_drm.h | 37 ++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 23 deletions(-)
drivers/gpu/drm/mga/mga_ioc32.c +17 -13
@@ -38,16 +38,21 @@ 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; + unsigned int front_pitch; + unsigned int back_offset; + unsigned int back_pitch; + unsigned int depth_cpp; + unsigned int depth_offset; + unsigned int 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 +72,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;
include/uapi/drm/mga_drm.h +27 -10
@@ -265,6 +265,16 @@ typedef struct _drm_mga_sarea {#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, __u32)#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t) +#define __struct_group (name, fields) \ + union { \ + struct { \ + fields \ + }; \ + struct { \ + fields \ + } name; \ + } + typedef struct _drm_mga_warp_index { int installed; unsigned long phys_addr;
@@ -279,20 +289,25 @@ typedef struct drm_mga_init {unsigned long sarea_priv_offset; -int chipset; -int sgram; +__struct_group (always32bit, + 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; +unsigned int front_pitch; +unsigned int back_offset; +unsigned int back_pitch; -unsigned int depth_cpp; -unsigned int depth_offset, depth_pitch; +unsigned int depth_cpp; +unsigned int depth_offset; +unsigned int 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;
@@ -302,6 +317,8 @@ typedef struct drm_mga_init {unsigned long buffers_offset; } drm_mga_init_t; +#undef __struct_group + typedef struct drm_mga_dma_bootstrap { /** * \name AGP texture region
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerRe: [PATCH 25/64] drm/mga/mga_ioc32: Use struct_group() for memcpy() region
Quoted 130 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in structdrm32_mga_initaround members chipset, sgram, maccess,fb_cpp,front_offset,front_pitch,back_offset,back_pitch,depth_cpp,depth_offset,depth_pitch,texture_offset, andtexture_size, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of chipset."pahole" shows no size nor member offset changes to struct
drm32_mga_init. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).Note that since this includes a UAPI header,
struct_group()has been explicitly redefined local to the header.Signed-off-by Kees Cook <[email protected]>--- drivers/gpu/drm/mga/mga_ioc32.c | 30 ++++++++++++++------------ include/uapi/drm/mga_drm.h | 37 ++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 23 deletions(-)drivers/gpu/drm/mga/mga_ioc32.c +17
-13@@ -38,16 +38,21 @@ 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; + unsigned int front_pitch; + unsigned int back_offset; + unsigned int back_pitch; + unsigned int depth_cpp; + unsigned int depth_offset; + unsigned int 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 +72,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;include/uapi/drm/mga_drm.h +25
-10@@ -265,6 +265,16 @@ typedef struct _drm_mga_sarea {#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, __u32)#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t) +#define __struct_group (name, fields) \ + union { \ + struct { \ + fields \ + }; \ + struct { \ + fields \ + } name; \ + } + typedef struct _drm_mga_warp_index { int installed; unsigned long phys_addr;@@ -279,20 +289,25 @@ typedef struct drm_mga_init {unsigned long sarea_priv_offset; -int chipset; -int sgram; +__struct_group (always32bit, + 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; +unsigned int front_pitch; +unsigned int back_offset; +unsigned int back_pitch; -unsigned int depth_cpp; -unsigned int depth_offset, depth_pitch; +unsigned int depth_cpp; +unsigned int depth_offset; +unsigned int 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;
include/uapi/drm/mga_drm.h typedef struct drm_mga_init { · line 321
Quoted 5 lines
include/uapi/drm/mga_drm.h +2
-0@@ -302,6 +317,8 @@ typedef struct drm_mga_init {unsigned long buffers_offset; } drm_mga_init_t; +#undef __struct_group +
Why can you use __struct_group in this uapi header, but not the networking one?
thanks,
greg k-h
Daniel Vetter
Acked-byRe: [PATCH 25/64] drm/mga/mga_ioc32: Use struct_group() for memcpy() region
Quoted 134 lines · Greg Kroah-Hartman
Quoted 133 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in structdrm32_mga_initaround members chipset, sgram, maccess,fb_cpp,front_offset,front_pitch,back_offset,back_pitch,depth_cpp,depth_offset,depth_pitch,texture_offset, andtexture_size, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of chipset."pahole" shows no size nor member offset changes to struct
drm32_mga_init. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).Note that since this includes a UAPI header,
struct_group()has been explicitly redefined local to the header.Signed-off-by Kees Cook <[email protected]>--- drivers/gpu/drm/mga/mga_ioc32.c | 30 ++++++++++++++------------ include/uapi/drm/mga_drm.h | 37 ++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 23 deletions(-)drivers/gpu/drm/mga/mga_ioc32.c +17
-13@@ -38,16 +38,21 @@ 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; + unsigned int front_pitch; + unsigned int back_offset; + unsigned int back_pitch; + unsigned int depth_cpp; + unsigned int depth_offset; + unsigned int 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 +72,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;include/uapi/drm/mga_drm.h +25
-10@@ -265,6 +265,16 @@ typedef struct _drm_mga_sarea {#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, __u32)#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t) +#define __struct_group (name, fields) \ + union { \ + struct { \ + fields \ + }; \ + struct { \ + fields \ + } name; \ + } + typedef struct _drm_mga_warp_index { int installed; unsigned long phys_addr;@@ -279,20 +289,25 @@ typedef struct drm_mga_init {unsigned long sarea_priv_offset; -int chipset; -int sgram; +__struct_group (always32bit, + 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; +unsigned int front_pitch; +unsigned int back_offset; +unsigned int back_pitch; -unsigned int depth_cpp; -unsigned int depth_offset, depth_pitch; +unsigned int depth_cpp; +unsigned int depth_offset; +unsigned int 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;@@ -302,6 +317,8 @@ typedef struct drm_mga_init {unsigned long buffers_offset; } drm_mga_init_t;
Quoted 5 lines
include/uapi/drm/mga_drm.h typedef struct drm_mga_init { · line 321
Quoted 2 lines
include/uapi/drm/mga_drm.h +2
-0+#undef __struct_group +Why can you use
__struct_groupin this uapi header, but not the networking one?
If there's others, maybe we can stuff the uapi __struct_group into linux/types.h where all the other __ uapi types hang out?
Anyway mga is very dead, I don't anyone cares.
I'm assuming this goes in through a topic pull from you?
I'll leave the drm/amd one to figure out between you and Alex. -Daniel
Quoted 4 lines
thanks,
greg k-h
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: [PATCH 25/64] drm/mga/mga_ioc32: Use struct_group() for memcpy() region
Quoted 21 lines · Daniel Vetter
Quoted 20 lines · Greg Kroah-Hartman
Quoted 18 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Use
struct_group()in structdrm32_mga_initaround members chipset, sgram, maccess,fb_cpp,front_offset,front_pitch,back_offset,back_pitch,depth_cpp,depth_offset,depth_pitch,texture_offset, andtexture_size, so they can be referenced together. This will allowmemcpy()andsizeof()to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of chipset."pahole" shows no size nor member offset changes to struct
drm32_mga_init. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences and optimizations).Note that since this includes a UAPI header,
struct_group()has been explicitly redefined local to the header.
[...]
Quoted 5 lines
Quoted 2 lines
Why can you use
__struct_groupin this uapi header, but not the networking one?If there's others, maybe we can stuff the uapi
__struct_groupintolinux/types.hwhere all the other __ uapi types hang out?
Ah yeah; it looks like include/uapi/linux/stddef.h is the place for it.
Quoted 5 lines
Anyway mga is very dead, I don't anyone cares.
Acked-by Daniel Vetter <[email protected]>I'm assuming this goes in through a topic pull from you?
Thanks! Yeah, my intention is to carry this as topic branch for Linus.
-Kees
Signature · 1 line
Kees Cook
PATCH 26/64 net/mlx5e: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct vlan_ethhdr around members h_dest and h_source, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of h_dest.
"pahole" shows no size nor member offset changes to struct vlan_ethhdr. "objdump -d" shows no object code changes.
--- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 2 +- include/linux/if_vlan.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +1 -1
@@ -207,7 +207,7 @@ static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs)int cpy1_sz =2 *ETH_ALEN ;int cpy2_sz = ihs - cpy1_sz; -memcpy (vhdr, skb->data, cpy1_sz); +memcpy (&vhdr->addrs, skb->data, cpy1_sz); vhdr->h_vlan_proto = skb->vlan_proto; vhdr->h_vlan_TCI =cpu_to_be16 (skb_vlan_tag_get (skb));memcpy (&vhdr->h_vlan_encapsulated_proto, skb->data + cpy1_sz, cpy2_sz);
include/linux/if_vlan.h +4 -2
@@ -46,8 +46,10 @@ struct vlan_hdr {* @h_vlan_encapsulated_proto: packet type ID or len */ struct vlan_ethhdr { -unsigned char h_dest[ETH_ALEN ]; -unsigned char h_source[ETH_ALEN ]; + struct_group(addrs, + unsigned char h_dest[ETH_ALEN]; +unsigned char h_source[ETH_ALEN ]; + );__be16 h_vlan_proto;__be16 h_vlan_TCI;__be16 h_vlan_encapsulated_proto;
Signature · 1 line
2.30.2
PATCH 27/64 HID: cp2112: Use struct_group() for memcpy() region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Use struct_group() in struct cp2112_string_report around members report, length, type, and string, so they can be referenced together. This will allow memcpy() and sizeof() to more easily reason about sizes, improve readability, and avoid future warnings about writing beyond the end of report.
"pahole" shows no size nor member offset changes to struct cp2112_string_report. "objdump -d" shows no meaningful object code changes (i.e. only source line number induced differences.)
--- drivers/hid/hid-cp2112.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
drivers/hid/hid-cp2112.c +8 -6
@@ -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 everyting 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);
Signature · 1 line
2.30.2
PATCH 28/64 compiler_types.h: Remove __compiletime_object_size()
In reply to Kees CookSince all compilers support __builtin_object_size(), and there is only one user of __compiletime_object_size, remove it to avoid the needless indirection. This lets Clang reason about check_copy_size() correctly.
--- include/linux/compiler-gcc.h | 2 -- include/linux/compiler_types.h | 4 ---- include/linux/thread_info.h | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-)
include/linux/compiler-gcc.h +0 -2
@@ -41,8 +41,6 @@#define __UNIQUE_ID (prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) -#define __compiletime_object_size (obj) __builtin_object_size(obj, 0) -#define __compiletime_warning (message) __attribute__((__warning__(message)))#define __compiletime_error (message) __attribute__((__error__(message)))
include/linux/compiler_types.h +0 -4
@@ -290,10 +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 #ifndef __compiletime_warning# define __compiletime_warning (message)#endif
include/linux/thread_info.h +1 -1
@@ -203,7 +203,7 @@ static inline void copy_overflow(int size, unsigned long count) static __always_inline __must_check boolcheck_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);
Signature · 1 line
2.30.2
PATCH 29/64 lib/string: Move helper functions out of string.c
In reply to Kees CookThe core functions of string.c are those that may be implemented by per-architecture functions, or overloaded by FORTIFY_SOURCE. As a result, it needs to be built with __NO_FORTIFY. Without this, macros will collide with function declarations. This was accidentally working due to -ffreestanding (on some architectures). Make this deterministic by explicitly setting __NO_FORTIFY and move all the helper functions into string_helpers.c so that they gain the fortification coverage they had been missing.
--- arch/s390/lib/string.c | 3 + arch/x86/lib/string_32.c | 1 + lib/string.c | 210 ++------------------------------------- lib/string_helpers.c | 193 +++++++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+), 204 deletions(-)
arch/s390/lib/string.c +3 -0
@@ -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>
arch/x86/lib/string_32.c +1 -0
@@ -11,6 +11,7 @@* strings. */ +#define __NO_FORTIFY#include <linux/string.h> #include <linux/export.h>
lib/string.c +6 -204
240 lines not on this page · raw message
lib/string_helpers.c +193 -0
196 lines not on this page · raw message
Signature · 1 line
2.30.2
PATCH 30/64 fortify: Move remaining fortify helpers into fortify-string.h
In reply to Kees CookWhen commit a28a6e860c6c ("string.h: move fortified functions definitions in a dedicated header.") moved the fortify-specific code, some helpers were left behind. Moves the remaining fortify-specific helpers into fortify-string.h so they're together where they're used. This requires that any FORTIFY helper function prototypes be conditionally built to avoid "no prototype" warnings. Additionally removes unused helpers.
--- include/linux/fortify-string.h | 7 +++++++ include/linux/string.h | 9 --------- lib/string_helpers.c | 2 ++ 3 files changed, 9 insertions(+), 9 deletions(-)
include/linux/fortify-string.h +7 -0
@@ -2,6 +2,13 @@#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)");#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);
include/linux/string.h +0 -9
@@ -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
lib/string_helpers.c +2 -0
@@ -883,9 +883,11 @@ char *strreplace(char *s, char old, char new) }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 */
Signature · 1 line
2.30.2
PATCH 31/64 fortify: Explicitly disable Clang support
In reply to Kees CookClang has never correctly compiled the FORTIFY_SOURCE defenses due to a couple bugs:
Eliding inlines with matching __builtin_* names https://bugs.llvm.org/show_bug.cgi?id=50322 Incorrect __builtin_constant_p() of some globals https://bugs.llvm.org/show_bug.cgi?id=41459
In the process of making improvements to the FORTIFY_SOURCE defenses, the first (silent) bug (coincidentally) becomes worked around, but exposes the latter which breaks the build. As such, Clang must not be used with CONFIG_FORTIFY_SOURCE until at least latter bug is fixed (in Clang 13), and the fortify routines have been rearranged.
Update the Kconfig to reflect the reality of the current situation.
--- security/Kconfig | 3 +++ 1 file changed, 3 insertions(+)
security/Kconfig +3 -0
@@ -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 !CONFIG_CC_IS_CLANG help Detect overflows of buffers in common string and memory functions where the compiler can determine and validate the buffer sizes.
Signature · 1 line
2.30.2
Nathan Chancellor
maintainerRe: [PATCH 31/64] fortify: Explicitly disable Clang support
Quoted 27 lines · Kees Cook
Clang has never correctly compiled the
FORTIFY_SOURCEdefenses due to a couple bugs:Eliding inlines with matching __builtin_* names https://bugs.llvm.org/show_bug.cgi?id=50322 Incorrect __builtin_constant_p() of some globals https://bugs.llvm.org/show_bug.cgi?id=41459In the process of making improvements to the
FORTIFY_SOURCEdefenses, the first (silent) bug (coincidentally) becomes worked around, but exposes the latter which breaks the build. As such, Clang must not be used withCONFIG_FORTIFY_SOURCEuntil at least latter bug is fixed (in Clang 13), and the fortify routines have been rearranged.Update the
Kconfigto reflect the reality of the current situation.Signed-off-by Kees Cook <[email protected]>--- security/Kconfig | 3 +++ 1 file changed, 3 insertions(+)security/Kconfig +0
-0
security/Kconfig config HARDENED_USERCOPY_PAGESPAN · line 196
Quoted 6 lines
security/Kconfig +3
-0@@ -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 !CONFIG_CC_IS_CLANG
Should be !CC_IS_CLANG, Kconfig is hard :)
security/Kconfig config HARDENED_USERCOPY_PAGESPAN · line 199
Quoted 4 lines
security/Kconfig +0
-0help Detect overflows of buffers in common string and memory functions where the compiler can determine and validate the buffer sizes.
Cheers,
Nathan
Re: [PATCH 31/64] fortify: Explicitly disable Clang support
Quoted 23 lines · Nathan Chancellor
Quoted 22 lines · Kees Cook
Clang has never correctly compiled the
FORTIFY_SOURCEdefenses due to a couple bugs:Eliding inlines with matching __builtin_* names https://bugs.llvm.org/show_bug.cgi?id=50322 Incorrect __builtin_constant_p() of some globals https://bugs.llvm.org/show_bug.cgi?id=41459In the process of making improvements to the
FORTIFY_SOURCEdefenses, the first (silent) bug (coincidentally) becomes worked around, but exposes the latter which breaks the build. As such, Clang must not be used withCONFIG_FORTIFY_SOURCEuntil at least latter bug is fixed (in Clang 13), and the fortify routines have been rearranged.Update the
Kconfigto reflect the reality of the current situation.Signed-off-by Kees Cook <[email protected]>--- security/Kconfig | 3 +++ 1 file changed, 3 insertions(+)
Quoted 13 lines
security/Kconfig config HARDENED_USERCOPY_PAGESPAN · line 196
Quoted 11 lines
security/Kconfig +3
-0@@ -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 !CONFIG_CC_IS_CLANGShould be !CC_IS_CLANG,
Kconfigis hard :)
/me shakes fist at sky
Thank you! Fixed locally. :)
-Kees
Quoted 8 lines
security/Kconfig config HARDENED_USERCOPY_PAGESPAN · line 199
Quoted 5 lines
security/Kconfig +0
-0help Detect overflows of buffers in common string and memory functions where the compiler can determine and validate the buffer sizes.Cheers,
Nathan
Signature · 1 line
Kees Cook
PATCH 32/64 fortify: Add compile-time FORTIFY_SOURCE tests
In reply to Kees CookWhile the run-time testing of FORTIFY_SOURCE is already present in LKDTM, there is no testing of the expected compile-time detections. In preparation for correctly supporting FORTIFY_SOURCE under Clang, adding additional FORTIFY_SOURCE defenses, and making sure FORTIFY_SOURCE doesn't silently regress with GCC, introduce a build-time test suite that checks each expected compile-time failure condition.
As this is relatively backwards from standard build rules in the sense that a successful test is actually a compile _failure_, create a wrapper script to check for the correct errors, and wire it up as a dummy dependency to lib/string.o, collecting the results into a log file artifact.
--- lib/.gitignore | 2 + lib/Makefile | 30 ++++++++++ lib/test_fortify/read_overflow-memchr.c | 5 ++ lib/test_fortify/read_overflow-memchr_inv.c | 5 ++ lib/test_fortify/read_overflow-memcmp.c | 5 ++ lib/test_fortify/read_overflow-memscan.c | 5 ++ lib/test_fortify/read_overflow2-memcmp.c | 5 ++ lib/test_fortify/read_overflow2-memcpy.c | 5 ++ lib/test_fortify/read_overflow2-memmove.c | 5 ++ lib/test_fortify/test_fortify.h | 31 ++++++++++ lib/test_fortify/write_overflow-memcpy.c | 5 ++ lib/test_fortify/write_overflow-memmove.c | 5 ++ lib/test_fortify/write_overflow-memset.c | 5 ++ lib/test_fortify/write_overflow-strlcpy.c | 5 ++ lib/test_fortify/write_overflow-strncpy.c | 5 ++ lib/test_fortify/write_overflow-strscpy.c | 5 ++ scripts/test_fortify.sh | 64 +++++++++++++++++++++ 17 files changed, 192 insertions(+) create mode 100644 lib/test_fortify/read_overflow-memchr.c create mode 100644 lib/test_fortify/read_overflow-memchr_inv.c create mode 100644 lib/test_fortify/read_overflow-memcmp.c create mode 100644 lib/test_fortify/read_overflow-memscan.c create mode 100644 lib/test_fortify/read_overflow2-memcmp.c create mode 100644 lib/test_fortify/read_overflow2-memcpy.c create mode 100644 lib/test_fortify/read_overflow2-memmove.c create mode 100644 lib/test_fortify/test_fortify.h create mode 100644 lib/test_fortify/write_overflow-memcpy.c create mode 100644 lib/test_fortify/write_overflow-memmove.c create mode 100644 lib/test_fortify/write_overflow-memset.c create mode 100644 lib/test_fortify/write_overflow-strlcpy.c create mode 100644 lib/test_fortify/write_overflow-strncpy.c create mode 100644 lib/test_fortify/write_overflow-strscpy.c create mode 100644 scripts/test_fortify.sh
lib/.gitignore +2 -0
@@ -4,3 +4,5 @@ /gen_crc32table /gen_crc64table /oid_registry_data.c +/test_fortify.log +/test_fortify/*.log
lib/Makefile +30 -0
@@ -360,3 +360,33 @@ obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_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 $(srctree)/scripts/test_fortify.sh \ + $(srctree)/include/linux/fortify-string.h 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
lib/test_fortify/read_overflow-memchr.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memchr(small, 0x7A, sizeof(small) + 1) + +#include "test_fortify.h"
lib/test_fortify/read_overflow-memchr_inv.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memchr_inv(small, 0x7A, sizeof(small) + 1) + +#include "test_fortify.h"
lib/test_fortify/read_overflow-memcmp.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcmp(small, large, sizeof(small) + 1) + +#include "test_fortify.h"
lib/test_fortify/read_overflow-memscan.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memscan(small, 0x7A, sizeof(small) + 1) + +#include "test_fortify.h"
lib/test_fortify/read_overflow2-memcmp.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcmp(large, small, sizeof(small) + 1) + +#include "test_fortify.h"
lib/test_fortify/read_overflow2-memcpy.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(large, instance.buf, sizeof(large)) + +#include "test_fortify.h"
lib/test_fortify/read_overflow2-memmove.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memmove(large, instance.buf, sizeof(large)) + +#include "test_fortify.h"
lib/test_fortify/test_fortify.h new file +31 -0
@@ -0,0 +1,31 @@ +// 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; +}; +const char small_src[__BUF_SMALL] ="AAAAAAAAAAAAAAA" ; +const char large_src[__BUF_LARGE] ="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ; + +char small[__BUF_SMALL]; +char large[__BUF_LARGE]; +struct fortify_object instance; + +void do_fortify_tests (void ) +{ +/* Normal initializations. */ +memset (&instance,0x32 ,sizeof (instance)); +memset (small,0xA5 ,sizeof (small)); +memset (large,0x5A ,sizeof (large)); + +TEST ; +}
lib/test_fortify/write_overflow-memcpy.c new file +5 -0
@@ -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"
lib/test_fortify/write_overflow-memmove.c new file +5 -0
@@ -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"
lib/test_fortify/write_overflow-memset.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memset(instance.buf, 0x5A, sizeof(large_src)) + +#include "test_fortify.h"
lib/test_fortify/write_overflow-strlcpy.c new file +5 -0
@@ -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"
lib/test_fortify/write_overflow-strncpy.c new file +5 -0
@@ -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"
lib/test_fortify/write_overflow-strscpy.c new file +5 -0
@@ -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"
scripts/test_fortify.sh new file +64 -0
64 lines not on this page · raw message
Signature · 1 line
2.30.2
PATCH 33/64 lib: Introduce CONFIG_TEST_MEMCPY
In reply to Kees CookBefore changing anything about memcpy(), memmove(), and memset(), add run-time tests to check basic behaviors for any regressions.
--- lib/Kconfig.debug | 3 + lib/Makefile | 1 + lib/test_memcpy.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 lib/test_memcpy.c
lib/Kconfig.debug +3 -0
@@ -2220,6 +2220,9 @@ config TEST_XARRAY config TEST_OVERFLOW tristate "Test check_*_overflow() functions at runtime" +config TEST_MEMCPY + tristate "Test memcpy*(), memmove*(), and memset*() functions at runtime" + config TEST_RHASHTABLE tristate "Perform selftest on resizable hash table" help
lib/Makefile +1 -0
@@ -77,6 +77,7 @@ obj-$(CONFIG_TEST_MIN_HEAP) += test_min_heap.o obj-$(CONFIG_TEST_LKM) += test_module.o obj-$(CONFIG_TEST_VMALLOC) += test_vmalloc.o obj-$(CONFIG_TEST_OVERFLOW) += test_overflow.o +obj-$(CONFIG_TEST_MEMCPY) += test_memcpy.o obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o obj-$(CONFIG_TEST_SORT) += test_sort.o obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
lib/test_memcpy.c new file +285 -0
285 lines not on this page · raw message
Signature · 1 line
2.30.2
Re: [PATCH 33/64] lib: Introduce CONFIG_TEST_MEMCPY
Quoted 14 lines · Kees Cook
lib/test_memcpy.c new file +14
-0+static int __init test_memcpy_init (void ) +{ +int err =0 ; + + err |=test_memcpy (); + err |=test_memmove (); + err |=test_memset (); + +if (err) { +pr_warn ("FAIL!\n" ); + err = -EINVAL ; + }else { +pr_info ("all tests passed\n" ); + }
lib/test_memcpy.c line 285
Quoted 10 lines
lib/test_memcpy.c new file +10
-0+ +return err; +} + +static void __exit test_memcpy_exit(void) +{ } + +module_init (test_memcpy_init); +module_exit (test_memcpy_exit); +MODULE_LICENSE ("GPL" );
Has it been considered to implement this test using the Kunit framework?
Thanks,
Bart.
Re: [PATCH 33/64] lib: Introduce CONFIG_TEST_MEMCPY
Quoted 19 lines · Bart Van Assche
Quoted 18 lines · Kees Cook
lib/test_memcpy.c new file +18
-0+static int __init test_memcpy_init (void ) +{ + int err = 0; + + err |= test_memcpy(); + err |= test_memmove(); + err |= test_memset(); + + if (err) { + pr_warn("FAIL!\n"); + err = -EINVAL; + } else { + pr_info("all tests passed\n"); + } + + return err; +} +
Quoted 8 lines
lib/test_memcpy.c line 285
Quoted 6 lines
lib/test_memcpy.c new file +6
-0+static void __exit test_memcpy_exit(void) +{ } + +module_init (test_memcpy_init); +module_exit (test_memcpy_exit); +MODULE_LICENSE ("GPL" );Has it been considered to implement this test using the Kunit framework?
and do we want everything converted to use the Kunit test framework?
My answer is No, we don't, but I could easily be in the minority.
Signature · 1 line
~Randy
Re: [PATCH 33/64] lib: Introduce CONFIG_TEST_MEMCPY
In reply to Bart Van AsscheQuoted 19 lines · Bart Van Assche
Quoted 18 lines · Kees Cook
lib/test_memcpy.c new file +18
-0+static int __init test_memcpy_init (void ) +{ +int err =0 ; + + err |=test_memcpy (); + err |=test_memmove (); + err |=test_memset (); + +if (err) { +pr_warn ("FAIL!\n" ); + err = -EINVAL ; + }else { +pr_info ("all tests passed\n" ); + } + +return err; +} +
Quoted 8 lines
lib/test_memcpy.c line 285
Quoted 6 lines
lib/test_memcpy.c new file +6
-0+static void __exit test_memcpy_exit(void) +{ } + +module_init (test_memcpy_init); +module_exit (test_memcpy_exit); +MODULE_LICENSE ("GPL" );Has it been considered to implement this test using the Kunit framework?
Good point! I will see if that works here; it would make sense to make this KUnit from the start.
Signature · 1 line
Kees Cook
PATCH 34/64 fortify: Detect struct member overflows in memcpy() at compile-time
In reply to Kees Cookmemcpy() is dead; long live memcpy()
tl;dr: In order to eliminate a large class of common buffer overflow flaws that continue to persist in the kernel, have memcpy() (under CONFIG_FORTIFY_SOURCE) perform bounds checking of the destination struct member when they have a known size. This would have caught all of the memcpy()-related buffer write overflow flaws identified in at least the last three years.
Background and analysis:
While stack-based buffer overflow flaws are largely mitigated by stack canaries (and similar) features, heap-based buffer overflow flaws continue to regularly appear in the kernel. Many classes of heap buffer overflows are mitigated by FORTIFY_SOURCE when using the strcpy() family of functions, but a significant number remain exposed through the memcpy() family of functions.
At its core, FORTIFY_SOURCE uses the compiler's __builtin_object_size() internal[0] to determine the available size at a target address based on the compile-time known structure layout details. It operates in two
modes: outer bounds (0) and inner bounds (1). In mode 0, the size of the enclosing structure is used. In mode 1, the size of the specific field is used. For example:
struct object {
u16 scalar1; /* 2 bytes */
char array[6]; /* 6 bytes */
u64 scalar2; /* 8 bytes */
u32 scalar3; /* 4 bytes */
} instance;__builtin_object_size(instance.array, 0) == 18, since the remaining size of the enclosing structure starting from "array" is 18 bytes (6 + 8 + 4).
__builtin_object_size(instance.array, 1) == 6, since the remaining size of the specific field "array" is 6 bytes.
The initial implementation of FORTIFY_SOURCE used mode 0 because there were many cases of both strcpy() and memcpy() functions being used to write (or read) across multiple fields in a structure. For example, this would catch this, which is writing 2 bytes beyond the end of "instance":
memcpy(&instance.array, data, 20);
While this didn't protect against overwriting adjacent fields in a given structure, it would at least stop overflows from reaching beyond the end of the structure into neighboring memory, and provided a meaningful mitigation of a subset of buffer overflow flaws. However, many desirable targets remain within the enclosing structure (for example function pointers).
As it happened, there were very few cases of strcpy() family functions intentionally writing beyond the end of a string buffer. Once all known cases were removed from the kernel, the strcpy() family was tightened[1] to use mode 1, providing greater mitigation coverage.
What remains is switching memcpy() to mode 1 as well, but making the switch is much more difficult because of how frustrating it can be to find existing "normal" uses of memcpy() that expect to write (or read) across multiple fields. The root cause of the problem is that the C language lacks a common pattern to indicate the intent of an author's use of memcpy(), and is further complicated by the available compile-time and run-time mitigation behaviors.
The FORTIFY_SOURCE mitigation comes in two halves: the compile-time half, when both the buffer size _and_ the length of the copy is known, and the run-time half, when only the buffer size is known. If neither size is known, there is no bounds checking possible. At compile-time when the compiler sees that a length will always exceed a known buffer size, a warning can be deterministically emitted. For the run-time half, the length is tested against the known size of the buffer, and the overflowing operation is detected. (The performance overhead for these tests is virtually zero.)
It is relatively easy to find compile-time false-positives since a warning is always generated. Fixing the false positives, however, can be very time-consuming as there are hundreds of instances. While it's possible some over-read conditions could lead to kernel memory exposures, the bulk of the risk comes from the run-time flaws where the length of a write may end up being attacker-controlled and lead to an overflow.
Many of the compile-time false-positives take a form similar to this:
memcpy(&instance.scalar2, data, sizeof(instance.scalar2) + sizeof(instance.scalar3));
and the run-time ones are similar, but lack a constant expression for the size of the copy:
memcpy(instance.array, data, length);
The former is meant to cover multiple fields (though its style has been frowned upon more recently), but has been technically legal. Both lack any expressivity in the C language about the author's _intent_ in a way that a compiler can check when the length isn't known at compile time. A comment doesn't work well because what's needed is something a compiler can directly reason about. Is a given memcpy() call expected to overflow into neighbors? Is it not? By using the new struct_group() macro, this intent can be much more easily encoded.
It is not as easy to find the run-time false-positives since the code path to exercise a seemingly out-of-bounds condition that is actually expected may not be trivially reachable. Tightening the restrictions to block an operation for a false positive will either potentially create a greater flaw (if a copy is truncated by the mitigation), or destabilize the kernel (e.g. with a BUG()), making things completely useless for the end user.
As a result, tightening the memcpy() restriction (when there is a reasonable level of uncertainty of the number of false positives), needs to first WARN() with no truncation. (Though any sufficiently paranoid end-user can always opt to set the panic_on_warn=1 sysctl.) Once enough development time has passed, the mitigation can be further intensified.
Given the potential frustrations of weeding out all the false positives when tightening the run-time checks, it is reasonable to wonder if these changes would actually add meaningful protection. Looking at just the last three years, there are 23 identified flaws with a CVE that mention "buffer overflow", and 11 are memcpy()-related buffer overflows.
(For the remaining 12: 7 are array index overflows that would be mitigated by systems built with CONFIG_UBSAN_BOUNDS=y: CVE-2019-0145, CVE-2019-14835, CVE-2019-14896, CVE-2019-14897, CVE-2019-14901, CVE-2019-17666, CVE-2021-28952. 2 are miscalculated allocation sizes which could be mitigated with memory tagging: CVE-2019-16746, CVE-2019-2181. 1 is an iovec buffer bug maybe mitigated by memory tagging:
CVE-2020-10742. 1 is a type confusion bug mitigated by stack canaries:
CVE-2020-10942. 1 is a string handling logic bug with no mitigation I'm aware of: CVE-2021-28972.)
At my last count on an x86_64 allmodconfig build, there are 25,018 calls to memcpy(). With callers instrumented to report all places where the buffer size is known but the length remains unknown (i.e. a run-time bounds check is added), we can count how many new run-time bounds checks are added when the destination and source arguments of memcpy() are changed to use "mode 1" bounds checking: 1540. In addition, there were 146 new compile-time warnings to evaluate and fix.
With this it's also possible to compare the places where the known 11 memcpy() flaw overflows happened against the resulting list of potential new bounds checks, as a measure of potential efficacy of the tightened mitigation. Much to my surprise, horror, and delight, all 11 flaws would have been detected by the newly added run-time bounds checks, making this a distinctly clear mitigation improvement: 100% coverage for memcpy() flaws, with a possible 2 orders of magnitude gain in coverage over existing but undiscovered run-time dynamic length flaws, against only 6% of all callers maybe gaining a false positive run-time check, with fewer than 150 new compile-time instances needing evaluation.
Specifically these would have been mitigated:
CVE-2020-24490 https://git.kernel.org/linus/a2ec905d1e160a33b2e210e45ad30445ef26ce0e
CVE-2020-12654 https://git.kernel.org/linus/3a9b153c5591548612c3955c9600a98150c81875
CVE-2020-12653 https://git.kernel.org/linus/b70261a288ea4d2f4ac7cd04be08a9f0f2de4f4d
CVE-2019-14895 https://git.kernel.org/linus/3d94a4a8373bf5f45cf5f939e88b8354dbf2311b
CVE-2019-14816 https://git.kernel.org/linus/7caac62ed598a196d6ddf8d9c121e12e082cac3a
CVE-2019-14815 https://git.kernel.org/linus/7caac62ed598a196d6ddf8d9c121e12e082cac3a
CVE-2019-14814 https://git.kernel.org/linus/7caac62ed598a196d6ddf8d9c121e12e082cac3a
CVE-2019-10126 https://git.kernel.org/linus/69ae4f6aac1578575126319d3f55550e7e440449
CVE-2019-9500 https://git.kernel.org/linus/1b5e2423164b3670e8bc9174e4762d297990deff no-CVE-yet https://git.kernel.org/linus/130f634da1af649205f4a3dd86cbe5c126b57914 no-CVE-yet https://git.kernel.org/linus/d10a87a3535cce2b890897914f5d0d83df669c63
To accelerate the review of potential run-time false positives, it's also worth noting that it is possible to partially automate checking by examining memcpy() buffer argument fields to see if they have a neighboring. It is reasonable to expect that the vast majority of run-time false positives would look like the already evaluated and fixed compile-time false positives, where the most common pattern is neighboring arrays. (And, FWIW, several of the compile-time fixes were actual bugs.)
Implementation:
Tighten the memcpy() buffer size checking to use the actual ("mode 1") target buffer size as the bounds check instead of their enclosing structure's ("mode 0") size. Use a common inline for memcpy() (and memmove() in a following patch), since all the tests are the same. All new cross-field memcpy() uses must use the struct_group() macro or similar to target a specific range of fields, so that FORTIFY_SOURCE can reason about the size and safety of the copy.
For run-time, the "mode 0" size checking and mitigation is left unchanged, with "mode 1" added only to writes, and only performing a WARN() for now. This way any missed run-time false positives can be flushed out over the coming several development cycles, but system builders who have tested their workloads to be WARN()-free can enable the panic_on_warn=1 sysctl to immediately gain a mitigation against this class of buffer overflows.
For now, cross-member "mode 1" read detection at compile-time will be limited to W=1 builds, since it is, unfortunately, very common. As the priority is solving write overflows, read overflows can be the next phase. Similarly, run-time cross-member "mode 1" read detection will be added at a later time, once write false-positives have been handled.
Related classes of flaws that remain unmitigated:
- memcpy() with raw pointers (e.g. void *, char *, etc) have no good mitigation beyond memory tagging (and even that would only protect against inter-object overflow, not intra-object neighboring field overflows). Some kind of "fat pointer" solution is likely needed to gain proper size-of-buffer awareness.
- type confusion where a higher level type's allocation size does not match the resulting cast type eventually passed to a deeper memcpy() call where the compiler cannot see the true type. In theory, greater static analysis could catch these.
[0] https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
[1] https://git.kernel.org/linus/6a39e62abbafd1d58d1722f40c7d26ef379c6a2f
--- include/linux/fortify-string.h | 111 ++++++++++++++++-- include/linux/string.h | 5 +- lib/Makefile | 3 +- lib/string_helpers.c | 6 + .../read_overflow2_field-memcpy.c | 5 + .../write_overflow_field-memcpy.c | 5 + 6 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 lib/test_fortify/read_overflow2_field-memcpy.c create mode 100644 lib/test_fortify/write_overflow_field-memcpy.c
include/linux/fortify-string.h +99 -12
@@ -2,13 +2,17 @@#ifndef _LINUX_FORTIFY_STRING_H_#define _LINUX_FORTIFY_STRING_H_ +#include <linux/bug.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 __read_overflow2_field(void) __compiletime_warning("detected read beyond size of field (2nd parameter); maybe use struct_group()?"); void __write_overflow(void) __compiletime_error("detected write beyond size of object (1st parameter)"); +void __write_overflow_field(void) __compiletime_warning("detected write beyond size of field (1st parameter); maybe use struct_group()?");#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);
@@ -182,22 +186,105 @@ __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)return __underlying_memset (p, c, size); } -__FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size) +/* +* To make sure the compiler can enforce protection against buffer overflows, +* memcpy(), memmove(), and memset() must not be used beyond individual +* struct members. If you need to copy across multiple members, please use +* struct_group() to create a named mirror of an anonymous struct union. +* (e.g. see struct sk_buff.) +* +* Mitigation coverage +* Bounds checking at: +* +-------+-------+-------+-------+ +* | Compile time | Run time | +* memcpy() argument sizes: | write | read | write | read | +* +-------+-------+-------+-------+ +* memcpy(known, known, constant) | y | y | n/a | n/a | +* memcpy(unknown, known, constant) | n | y | V | n/a | +* memcpy(known, unknown, constant) | y | n | n/a | V | +* memcpy(unknown, unknown, constant) | n | n | V | V | +* memcpy(known, known, dynamic) | n | n | b | B | +* memcpy(unknown, known, dynamic) | n | n | V | B | +* memcpy(known, unknown, dynamic) | n | n | b | V | +* memcpy(unknown, unknown, dynamic) | n | n | V | V | +* +-------+-------+-------+-------+ +* +* y = deterministic compile-time bounds checking +* n = cannot do deterministic compile-time bounds checking +* n/a = no run-time bounds checking needed since compile-time deterministic +* b = perform run-time bounds checking +* B = can perform run-time bounds checking, but current unenforced +* V = vulnerable to run-time overflow +* +*/ +__FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t size, +const size_t p_size, +const size_t q_size, +const size_t p_size_field, +const size_t q_size_field, +const char *func) { -size_t p_size =__builtin_object_size (p,0 ); -size_t q_size =__builtin_object_size (q,0 ); -if (__builtin_constant_p (size)) { -if (p_size < size) +/* +* Length argument is a constant expression, so we +* can perform compile-time bounds checking where +* buffer sizes are known. +*/ + +/* Error when size is larger than enclosing struct. */ +if (p_size > p_size_field && p_size < size)__write_overflow (); -if (q_size < size) +if (q_size > q_size_field && q_size < size)__read_overflow2 (); + +/* Warn when write size argument larger than dest field. */ +if (p_size_field < size) +__write_overflow_field (); +/* +* Warn for source field over-read when building with W=1 +* or when an over-write happened, so both can be fixed at +* the same time. +*/ +if ((IS_ENABLED (KBUILD_EXTRA_WARN1 ) || p_size_field < size) && + q_size_field < size) +__read_overflow2_field (); } -if (p_size < size || q_size < size) -fortify_panic (__func__); -return __underlying_memcpy (p, q, size); +/* +* At this point, length argument may not be a constant expression, +* so run-time bounds checking can be done where buffer sizes are +* known. (This is not an "else" because the above checks may only +* be compile-time warnings, and we want to still warn for run-time +* overflows.) +*/ + +/* +* Always stop accesses beyond the struct that contains the +* field, when the buffer's remaining size is known. +* (The -1 test is to optimize away checks where the buffer +* lengths are unknown.) +*/ +if ((p_size != (size_t )(-1 ) && p_size < size) || + (q_size != (size_t )(-1 ) && q_size < size)) +fortify_panic (func); } +#define __fortify_memcpy_chk (p, q, size, p_size, q_size, \ + p_size_field, q_size_field, op) ({ \ + size_t __fortify_size = (size_t)(size); \ + fortify_memcpy_chk(__fortify_size, p_size, q_size, \ + p_size_field, q_size_field, #op); \ + __underlying_##op(p, q, __fortify_size); \ +}) + +/* +* __builtin_object_size() must be captured here to avoid evaluating argument +* side-effects further into the macro layers. +*/ +#define memcpy (p, q, s) __fortify_memcpy_chk(p, q, s, \ + __builtin_object_size(p, 0), __builtin_object_size(q, 0), \ + __builtin_object_size(p, 1), __builtin_object_size(q, 1), \ + memcpy) + __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) {size_t p_size =__builtin_object_size (p,0 );
@@ -277,27 +364,27 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp)return __real_kmemdup (p, size, gfp); } -/* defined after fortified strlen and memcpy to reuse them */ +/* Defined after fortified strlen to reuse it. */ __FORTIFY_INLINE char *strcpy(char *p, const char *q) {size_t p_size =__builtin_object_size (p,1 );size_t q_size =__builtin_object_size (q,1 );size_t size; +/* If neither buffer size is known, immediately give up. */ 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 */ if (p_size < size)fortify_panic (__func__); -memcpy (p, q, size); +__underlying_memcpy (p, q, size);return p; }/* Don't use these outside the FORITFY_SOURCE implementation */ #undef __underlying_memchr#undef __underlying_memcmp -#undef __underlying_memcpy#undef __underlying_memmove#undef __underlying_memset#undef __underlying_strcat
include/linux/string.h +3 -2
@@ -261,8 +261,9 @@ static inline const char *kbasename(const char *path)* @count: The number of bytes to copy * @pad: Character to use for padding if space is left in destination. */ -static inline void memcpy_and_pad (void *dest,size_t dest_len, -const void *src,size_t count,int pad) +static __always_inline void memcpy_and_pad(void *dest, size_t dest_len, +const void *src,size_t count, +int pad) {if (dest_len > count) {memcpy (dest, src, count);
lib/Makefile +2 -1
@@ -370,7 +370,8 @@ 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) + $(call cc-disable-warning,fortify-source) \ + -DKBUILD_EXTRA_WARN1 targets += $(TEST_FORTIFY_LOGS) clean-files += $(TEST_FORTIFY_LOGS)
lib/string_helpers.c +6 -0
@@ -884,6 +884,12 @@ char *strreplace(char *s, char old, char new)EXPORT_SYMBOL (strreplace);#ifdef CONFIG_FORTIFY_SOURCE +/* These are placeholders for fortify compile-time warnings. */ +void __read_overflow2_field (void ) { } +EXPORT_SYMBOL (__read_overflow2_field); +void __write_overflow_field (void ) { } +EXPORT_SYMBOL (__write_overflow_field); +void fortify_panic (const char *name) {pr_emerg ("detected buffer overflow in %s\n" , name);
lib/test_fortify/read_overflow2_field-memcpy.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(large, instance.buf, sizeof(instance.buf) + 1) + +#include "test_fortify.h"
lib/test_fortify/write_overflow_field-memcpy.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(instance.buf, large, sizeof(instance.buf) + 1) + +#include "test_fortify.h"
Signature · 1 line
2.30.2
Re: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
Quoted 5 lines · Kees Cook
To accelerate the review of potential run-time false positives, it's also worth noting that it is possible to partially automate checking by examining
memcpy()buffer argument fields to see if they have a neighboring. It is reasonable to expect that the vast majority of
a neighboring...field?
include/linux/fortify-string.h line 5
Quoted 9 lines
include/linux/fortify-string.h +1
-0@@ -2,13 +2,17 @@#ifndef _LINUX_FORTIFY_STRING_H_#define _LINUX_FORTIFY_STRING_H_ +#include <linux/bug.h>
What are you using from linux/bug.h here?
Quoted 105 lines
include/linux/fortify-string.h +77
-9+#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 __read_overflow2_field(void) __compiletime_warning("detected read beyond size of field (2nd parameter); maybe use struct_group()?"); void __write_overflow(void) __compiletime_error("detected write beyond size of object (1st parameter)"); +void __write_overflow_field(void) __compiletime_warning("detected write beyond size of field (1st parameter); maybe use struct_group()?");#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);@@ -182,22 +186,105 @@ __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)return __underlying_memset (p, c, size); } -__FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size) +/* +* To make sure the compiler can enforce protection against buffer overflows, +* memcpy(), memmove(), and memset() must not be used beyond individual +* struct members. If you need to copy across multiple members, please use +* struct_group() to create a named mirror of an anonymous struct union. +* (e.g. see struct sk_buff.) +* +* Mitigation coverage +* Bounds checking at: +* +-------+-------+-------+-------+ +* | Compile time | Run time | +* memcpy() argument sizes: | write | read | write | read | +* +-------+-------+-------+-------+ +* memcpy(known, known, constant) | y | y | n/a | n/a | +* memcpy(unknown, known, constant) | n | y | V | n/a | +* memcpy(known, unknown, constant) | y | n | n/a | V | +* memcpy(unknown, unknown, constant) | n | n | V | V | +* memcpy(known, known, dynamic) | n | n | b | B | +* memcpy(unknown, known, dynamic) | n | n | V | B | +* memcpy(known, unknown, dynamic) | n | n | b | V | +* memcpy(unknown, unknown, dynamic) | n | n | V | V | +* +-------+-------+-------+-------+ +* +* y = deterministic compile-time bounds checking +* n = cannot do deterministic compile-time bounds checking +* n/a = no run-time bounds checking needed since compile-time deterministic +* b = perform run-time bounds checking +* B = can perform run-time bounds checking, but current unenforced +* V = vulnerable to run-time overflow +* +*/ +__FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t size, +const size_t p_size, +const size_t q_size, +const size_t p_size_field, +const size_t q_size_field, +const char *func) { -size_t p_size =__builtin_object_size (p,0 ); -size_t q_size =__builtin_object_size (q,0 ); -if (__builtin_constant_p (size)) { -if (p_size < size) +/* +* Length argument is a constant expression, so we +* can perform compile-time bounds checking where +* buffer sizes are known. +*/ + +/* Error when size is larger than enclosing struct. */ +if (p_size > p_size_field && p_size < size)__write_overflow (); -if (q_size < size) +if (q_size > q_size_field && q_size < size)__read_overflow2 (); + +/* Warn when write size argument larger than dest field. */ +if (p_size_field < size) +__write_overflow_field (); +/* +* Warn for source field over-read when building with W=1 +* or when an over-write happened, so both can be fixed at +* the same time. +*/ +if ((IS_ENABLED (KBUILD_EXTRA_WARN1 ) || p_size_field < size) && + q_size_field < size) +__read_overflow2_field (); } -if (p_size < size || q_size < size) -fortify_panic (__func__); -return __underlying_memcpy (p, q, size); +/* +* At this point, length argument may not be a constant expression, +* so run-time bounds checking can be done where buffer sizes are +* known. (This is not an "else" because the above checks may only +* be compile-time warnings, and we want to still warn for run-time +* overflows.) +*/ + +/* +* Always stop accesses beyond the struct that contains the +* field, when the buffer's remaining size is known. +* (The -1 test is to optimize away checks where the buffer +* lengths are unknown.) +*/ +if ((p_size != (size_t )(-1 ) && p_size < size) || + (q_size != (size_t )(-1 ) && q_size < size))
include/linux/fortify-string.h __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size) · line 277
Quoted 10 lines
include/linux/fortify-string.h +8
-0+fortify_panic (func); } +#define __fortify_memcpy_chk (p, q, size, p_size, q_size, \ + p_size_field, q_size_field, op) ({ \ + size_t __fortify_size = (size_t)(size); \ + fortify_memcpy_chk(__fortify_size, p_size, q_size, \ + p_size_field, q_size_field, #op); \ + __underlying_##op(p, q, __fortify_size); \ +})
Are there other macro expansion sites for __fortify_memcpy_chk, perhaps later in this series? I don't understand why memcpy is passed as func to fortify_panic() rather than continuing to use __func__?
Quoted 49 lines
include/linux/fortify-string.h +13
-3+ +/* +* __builtin_object_size() must be captured here to avoid evaluating argument +* side-effects further into the macro layers. +*/ +#define memcpy (p, q, s) __fortify_memcpy_chk(p, q, s, \ + __builtin_object_size(p, 0), __builtin_object_size(q, 0), \ + __builtin_object_size(p, 1), __builtin_object_size(q, 1), \ + memcpy) + __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) {size_t p_size =__builtin_object_size (p,0 );@@ -277,27 +364,27 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp)return __real_kmemdup (p, size, gfp); } -/* defined after fortified strlen and memcpy to reuse them */ +/* Defined after fortified strlen to reuse it. */ __FORTIFY_INLINE char *strcpy(char *p, const char *q) {size_t p_size =__builtin_object_size (p,1 );size_t q_size =__builtin_object_size (q,1 );size_t size; +/* If neither buffer size is known, immediately give up. */ 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 */ if (p_size < size)fortify_panic (__func__); -memcpy (p, q, size); +__underlying_memcpy (p, q, size);return p; }/* Don't use these outside the FORITFY_SOURCE implementation */ #undef __underlying_memchr#undef __underlying_memcmp -#undef __underlying_memcpy#undef __underlying_memmove#undef __underlying_memset#undef __underlying_strcatinclude/linux/string.h +0
-0
include/linux/string.h static inline const char *kbasename(const char *path) · line 266
Quoted 8 lines
include/linux/string.h +3
-2@@ -261,8 +261,9 @@ static inline const char *kbasename(const char *path)* @count: The number of bytes to copy * @pad: Character to use for padding if space is left in destination. */ -static inline void memcpy_and_pad (void *dest,size_t dest_len, -const void *src,size_t count,int pad) +static __always_inline void memcpy_and_pad(void *dest, size_t dest_len, +const void *src,size_t count, +int pad)
Why __always_inline here?
Quoted 22 lines
include/linux/string.h +0
-0{if (dest_len > count) {memcpy (dest, src, count);lib/Makefile +2
-1@@ -370,7 +370,8 @@ 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) + $(call cc-disable-warning,fortify-source) \ + -DKBUILD_EXTRA_WARN1 targets += $(TEST_FORTIFY_LOGS) clean-files += $(TEST_FORTIFY_LOGS)lib/string_helpers.c +0
-0
lib/string_helpers.c char *strreplace(char *s, char old, char new) · line 892
Quoted 9 lines
lib/string_helpers.c +6
-0@@ -884,6 +884,12 @@ char *strreplace(char *s, char old, char new)EXPORT_SYMBOL (strreplace);#ifdef CONFIG_FORTIFY_SOURCE +/* These are placeholders for fortify compile-time warnings. */ +void __read_overflow2_field (void ) { } +EXPORT_SYMBOL (__read_overflow2_field); +void __write_overflow_field (void ) { } +EXPORT_SYMBOL (__write_overflow_field); +
Don't we rely on these being undefined for Clang to produce a linkage failure (until https://reviews.llvm.org/D106030 has landed)? By providing a symbol definition we can link against, I don't think __compiletime_{warning|error} will warn at all with Clang?
Quoted 20 lines
lib/string_helpers.c +0
-0void fortify_panic (const char *name) {pr_emerg ("detected buffer overflow in %s\n" , name);lib/test_fortify/read_overflow2_field-memcpy.c new file +5
-0@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(large, instance.buf, sizeof(instance.buf) + 1) + +#include "test_fortify.h" lib/test_fortify/write_overflow_field-memcpy.c new file +0
-0
lib/test_fortify/write_overflow_field-memcpy.c
Quoted 6 lines
lib/test_fortify/write_overflow_field-memcpy.c new file +5
-1@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(instance.buf, large, sizeof(instance.buf) + 1) + +#include "test_fortify.h" --
I haven't read the whole series yet, but I assume test_fortify.h was provided earlier in the series?
Signature · 2 lines
Thanks, ~Nick Desaulniers
Re: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
Quoted 8 lines · Nick Desaulniers
Quoted 5 lines · Kees Cook
To accelerate the review of potential run-time false positives, it's also worth noting that it is possible to partially automate checking by examining
memcpy()buffer argument fields to see if they have a neighboring. It is reasonable to expect that the vast majority ofa neighboring...field?
Whoops, sorry, this should say "array member". I've fixed this to read:
To accelerate the review of potential run-time false positives, it's also worth noting that it is possible to partially automate checking by examining the memcpy() buffer argument to check for the destination struct member having a neighboring array member. It is reasonable to expect that the vast majority of run-time false positives would look like the already evaluated and fixed compile-time false positives, where the most common pattern is neighboring arrays. (And, FWIW, several of the compile-time fixes were actual bugs.)
Quoted 11 lines
include/linux/fortify-string.h line 5
Quoted 9 lines
include/linux/fortify-string.h +1
-0@@ -2,13 +2,17 @@#ifndef _LINUX_FORTIFY_STRING_H_#define _LINUX_FORTIFY_STRING_H_ +#include <linux/bug.h> What are you using from
linux/bug.hhere?
Thanks; yes, that should have been added in patch 64, when the WARN_ONCE() use is introduced:
https://lore.kernel.org/lkml/[email protected]/
Quoted 14 lines
Quoted 14 lines
[...]
include/linux/fortify-string.h +13
-0+#define __fortify_memcpy_chk (p, q, size, p_size, q_size, \ + p_size_field, q_size_field, op) ({ \ + size_t __fortify_size = (size_t)(size); \ + fortify_memcpy_chk(__fortify_size, p_size, q_size, \ + p_size_field, q_size_field, #op); \ + __underlying_##op(p, q, __fortify_size); \ +}) + +/* +* __builtin_object_size() must be captured here to avoid evaluating argument +* side-effects further into the macro layers. +*/ +#define memcpy (p, q, s) __fortify_memcpy_chk(p, q, s, \
Quoted 8 lines
include/linux/fortify-string.h __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size) · line 286
Quoted 3 lines
include/linux/fortify-string.h +3
-0+__builtin_object_size (p,0 ),__builtin_object_size (q,0 ), \ +__builtin_object_size (p,1 ),__builtin_object_size (q,1 ), \ + memcpy)Are there other macro expansion sites for
__fortify_memcpy_chk, perhaps later in this series? I don't understand whymemcpyis passed asfunctofortify_panic()rather than continuing to use__func__?
Yes, memmove() follows exactly the same pattern. Rather than refactoring the declaration in that patch, this felt cleaner.
https://lore.kernel.org/lkml/[email protected]/
Quoted 11 lines
include/linux/fortify-string.h
Quoted 9 lines
[...]
* @count: The number of bytes to copy
* @pad: Character to use for padding if space is left in destination. */include/linux/fortify-string.h +3
-2-static inline void memcpy_and_pad (void *dest,size_t dest_len, -const void *src,size_t count,int pad) +static __always_inline void memcpy_and_pad(void *dest, size_t dest_len, +const void *src,size_t count, +int pad)Why
__always_inlinehere?
Without it, we run the risk of it being made out of line, and potentially losing access to the __builtin_object_size() checking of arguments. Though given some of the Clang bugs, it's possible this needs to be strictly converted into a macro.
Quoted 5 lines
Quoted 5 lines
[...]
#ifdefCONFIG_FORTIFY_SOURCEinclude/linux/fortify-string.h +3
-0+/* These are placeholders for fortify compile-time warnings. */ +void __read_overflow2_field (void ) { } +EXPORT_SYMBOL (__read_overflow2_field);
Quoted 8 lines
include/linux/fortify-string.h
Quoted 3 lines
include/linux/fortify-string.h +3
-0+void __write_overflow_field (void ) { } +EXPORT_SYMBOL (__write_overflow_field); +Don't we rely on these being undefined for Clang to produce a linkage failure (until https://reviews.llvm.org/D106030 has landed)? By providing a symbol definition we can link against, I don't think __compiletime_{warning|error} will warn at all with Clang?
This was intentional because I explicitly do not want to break the build for new warnings, and there is no way currently for Clang to _warn_ (rather than fail to link). This could be adjusted to break only Clang's builds, but at this point, it seemed best.
Quoted 10 lines
include/linux/fortify-string.h
Quoted 7 lines
[...]
include/linux/fortify-string.h +5
-1+// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memcpy(instance.buf, large, sizeof(instance.buf) + 1) + +#include "test_fortify.h" --I haven't read the whole series yet, but I assume
test_fortify.hwas provided earlier in the series?
Yup, it's part of the compile-time tests in patch 32:
https://lore.kernel.org/lkml/[email protected]/
-Kees
Signature · 1 line
Kees Cook
kernel test robot
build botRe: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
In reply to Kees CookI love your patch! Perhaps something to improve:
Hi Kees,
I love your patch! Perhaps something to improve:
[auto build test WARNING on staging/staging-testing]
[also build test WARNING on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210727] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: arm-randconfig-r031-20210727 (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 10.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/6617421fca0f2272593a2659a5cba25bf8249857
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout 6617421fca0f2272593a2659a5cba25bf8249857
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-10.3.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
In file included from include/linux/string.h:253,
from arch/arm/include/asm/io.h:23,
from include/linux/io.h:13,
from sound/isa/wavefront/wavefront_synth.c:20:
In function 'fortify_memcpy_chk',
inlined from 'raw_copy_from_user' at arch/arm/include/asm/uaccess.h:567:2,
inlined from 'wavefront_load_patch' at include/linux/uaccess.h:159:9:
>> include/linux/fortify-string.h:242:4: warning: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribute-warning]
242 | __write_overflow_field();
| ^~~~~~~~~~~~~~~~~~~~~~~~vim +/__write_overflow_field +242 include/linux/fortify-string.h
188
189 /*
190 * To make sure the compiler can enforce protection against buffer overflows,
191 * memcpy(), memmove(), and memset() must not be used beyond individual
192 * struct members. If you need to copy across multiple members, please use
193 * struct_group() to create a named mirror of an anonymous struct union.
194 * (e.g. see struct sk_buff.)
195 *
196 * Mitigation coverage
197 * Bounds checking at:
198 * +-------+-------+-------+-------+
199 * | Compile time | Run time |
200 * memcpy() argument sizes: | write | read | write | read |
201 * +-------+-------+-------+-------+
202 * memcpy(known, known, constant) | y | y | n/a | n/a |
203 * memcpy(unknown, known, constant) | n | y | V | n/a |
204 * memcpy(known, unknown, constant) | y | n | n/a | V |
205 * memcpy(unknown, unknown, constant) | n | n | V | V |
206 * memcpy(known, known, dynamic) | n | n | b | B |
207 * memcpy(unknown, known, dynamic) | n | n | V | B |
208 * memcpy(known, unknown, dynamic) | n | n | b | V |
209 * memcpy(unknown, unknown, dynamic) | n | n | V | V |
210 * +-------+-------+-------+-------+
211 *
212 * y = deterministic compile-time bounds checking
213 * n = cannot do deterministic compile-time bounds checking
214 * n/a = no run-time bounds checking needed since compile-time deterministic
215 * b = perform run-time bounds checking
216 * B = can perform run-time bounds checking, but current unenforced
217 * V = vulnerable to run-time overflow
218 *
219 */
220 __FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t size,
221 const size_t p_size,
222 const size_t q_size,
223 const size_t p_size_field,
224 const size_t q_size_field,
225 const char *func)
226 {
227 if (__builtin_constant_p(size)) {
228 /*
229 * Length argument is a constant expression, so we
230 * can perform compile-time bounds checking where
231 * buffer sizes are known.
232 */
233
234 /* Error when size is larger than enclosing struct. */
235 if (p_size > p_size_field && p_size < size)
236 __write_overflow();
237 if (q_size > q_size_field && q_size < size)
238 __read_overflow2();
239
240 /* Warn when write size argument larger than dest field. */
241 if (p_size_field < size)
> 242 __write_overflow_field(); 243 /*
244 * Warn for source field over-read when building with W=1
245 * or when an over-write happened, so both can be fixed at
246 * the same time.
247 */
248 if ((IS_ENABLED(KBUILD_EXTRA_WARN1) || p_size_field < size) &&
249 q_size_field < size)
250 __read_overflow2_field();
251 }
252 /*
253 * At this point, length argument may not be a constant expression,
254 * so run-time bounds checking can be done where buffer sizes are
255 * known. (This is not an "else" because the above checks may only
256 * be compile-time warnings, and we want to still warn for run-time
257 * overflows.)
258 */
259
260 /*
261 * Always stop accesses beyond the struct that contains the
262 * field, when the buffer's remaining size is known.
263 * (The -1 test is to optimize away checks where the buffer
264 * lengths are unknown.)
265 */
266 if ((p_size != (size_t)(-1) && p_size < size) ||
267 (q_size != (size_t)(-1) && q_size < size))
268 fortify_panic(func);
269 }
270
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]
kernel test robot
build botRe: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
In reply to Kees CookI love your patch! Yet something to improve:
Hi Kees,
I love your patch! Yet something to improve:
[auto build test ERROR on staging/staging-testing]
[also build test ERROR on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210727] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: arm-randconfig-r031-20210727 (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 10.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/6617421fca0f2272593a2659a5cba25bf8249857
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout 6617421fca0f2272593a2659a5cba25bf8249857
# save the attached .config to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-10.3.0 make.cross O=build_dir ARCH=arm SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate
All errors (new ones prefixed by >>):
In file included from include/linux/string.h:253,
from arch/arm/boot/compressed/string.c:8:
>> include/linux/fortify-string.h:272:42: error: expected identifier or '(' before '{' token
272 | p_size_field, q_size_field, op) ({ \
| ^
include/linux/fortify-string.h:283:26: note: in expansion of macro '__fortify_memcpy_chk'
283 | #define memcpy(p, q, s) __fortify_memcpy_chk(p, q, s, \
| ^~~~~~~~~~~~~~~~~~~~
arch/arm/boot/compressed/string.c:29:7: note: in expansion of macro 'memcpy'
29 | void *memcpy(void *__dest, __const void *__src, size_t __n)
| ^~~~~~vim +272 include/linux/fortify-string.h
270
271 #define __fortify_memcpy_chk(p, q, size, p_size, q_size, \
> 272 p_size_field, q_size_field, op) ({ \ 273 size_t __fortify_size = (size_t)(size); \
274 fortify_memcpy_chk(__fortify_size, p_size, q_size, \
275 p_size_field, q_size_field, #op); \
276 __underlying_##op(p, q, __fortify_size); \
277 })
278
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
Re: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
In reply to Kees CookQuoted 15 lines · Kees Cook
At its core,
FORTIFY_SOURCEuses the compiler's__builtin_object_size()internal[0] to determine the available size at a target address based on the compile-time known structure layout details. It operates in two
modes: outer bounds (0) and inner bounds (1). In mode 0, the size of the enclosing structure is used. In mode 1, the size of the specific field is used. For example:struct object { u16 scalar1; /* 2 bytes */ char array[6]; /* 6 bytes */ u64 scalar2; /* 8 bytes */ u32 scalar3; /* 4 bytes */ } instance;
Quoted 2 lines
__builtin_object_size(instance.array, 0)== 18, since the remaining size of the enclosing structure starting from "array" is 18 bytes (6 + 8 + 4).
I think the compiler would usually end up making that struct size 24, with 4 bytes of trailing padding (at least when alignof(u64) is 8). In that case, does __builtin_object_size(instance.array, 0) actually evaluate to 18, or to 22? A quick test on x86-64 suggests the latter, so the memcpy(, , 20) would not be a violation.
Perhaps it's better to base the example on something which doesn't have potential trailing padding - so either add another 4 byte member, or also make scalar2 u32.
Rasmus
Re: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
Quoted 26 lines · Rasmus Villemoes
Quoted 15 lines · Kees Cook
At its core,
FORTIFY_SOURCEuses the compiler's__builtin_object_size()internal[0] to determine the available size at a target address based on the compile-time known structure layout details. It operates in two
modes: outer bounds (0) and inner bounds (1). In mode 0, the size of the enclosing structure is used. In mode 1, the size of the specific field is used. For example:struct object { u16 scalar1; /* 2 bytes */ char array[6]; /* 6 bytes */ u64 scalar2; /* 8 bytes */ u32 scalar3; /* 4 bytes */ } instance;Quoted 2 lines
__builtin_object_size(instance.array, 0)== 18, since the remaining size of the enclosing structure starting from "array" is 18 bytes (6 + 8 + 4).I think the compiler would usually end up making that struct size 24, with 4 bytes of trailing padding (at least when alignof(u64) is 8). In that case, does
__builtin_object_size(instance.array, 0)actually evaluate to 18, or to 22? A quick test on x86-64 suggests the latter, so thememcpy(, , 20)would not be a violation.
Quoted 3 lines
Perhaps it's better to base the example on something which doesn't have potential trailing padding - so either add another 4 byte member, or also make scalar2 u32.
Yup, totally right. Thanks! I've fixed the example now for v2.
Signature · 1 line
Kees Cook
kernel test robot
build botRe: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
In reply to Kees CookI love your patch! Perhaps something to improve:
Hi Kees,
I love your patch! Perhaps something to improve:
[auto build test WARNING on staging/staging-testing]
[also build test WARNING on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210727] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: x86_64-randconfig-s022-20210728 (attached as .config) compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-341-g8af24329-dirty # https://github.com/0day-ci/linux/commit/6617421fca0f2272593a2659a5cba25bf8249857 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout 6617421fca0f2272593a2659a5cba25bf8249857 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/gpu/drm/gma500/ drivers/hid/
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
drivers/hid/hid-hyperv.c:202:40: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] report_desc_size @@ got restricted __le16 [usertype] wDescriptorLength @@
drivers/hid/hid-hyperv.c:202:40: sparse: expected unsigned int [usertype] report_desc_size
drivers/hid/hid-hyperv.c:202:40: sparse: got restricted __le16 [usertype] wDescriptorLength
>> drivers/hid/hid-hyperv.c:218:9: sparse: sparse: cast from restricted __le16
vim +218 drivers/hid/hid-hyperv.c
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 180
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 181 static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 182 struct synthhid_device_info *device_info)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 183 {
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 184 int ret = 0;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 185 struct hid_descriptor *desc;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 186 struct mousevsc_prt_msg ack;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 187
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 188 input_device->dev_info_status = -ENOMEM;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 189
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 190 input_device->hid_dev_info = device_info->hid_dev_info;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 191 desc = &device_info->hid_descriptor;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 192 if (desc->bLength == 0)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 193 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 194
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 195 /* The pointer is not NULL when we resume from hibernation */
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 196 kfree(input_device->hid_desc);
a4a23f6d68ad2c Thomas Meyer 2013-06-01 197 input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 198
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 199 if (!input_device->hid_desc)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 200 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 201
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 202 input_device->report_desc_size = desc->desc[0].wDescriptorLength;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 203 if (input_device->report_desc_size == 0) {
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 204 input_device->dev_info_status = -EINVAL;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 205 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 206 }
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 207
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 208 /* The pointer is not NULL when we resume from hibernation */
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 209 kfree(input_device->report_desc);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 210 input_device->report_desc = kzalloc(input_device->report_desc_size,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 211 GFP_ATOMIC);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 212
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 213 if (!input_device->report_desc) {
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 214 input_device->dev_info_status = -ENOMEM;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 215 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 216 }
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 217
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 @218 memcpy(input_device->report_desc,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 219 ((unsigned char *)desc) + desc->bLength,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 220 desc->desc[0].wDescriptorLength);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 221
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 222 /* Send the ack */
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 223 memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 224
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 225 ack.type = PIPE_MESSAGE_DATA;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 226 ack.size = sizeof(struct synthhid_device_info_ack);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 227
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 228 ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 229 ack.ack.header.size = 1;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 230 ack.ack.reserved = 0;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 231
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 232 ret = vmbus_sendpacket(input_device->device->channel,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 233 &ack,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 234 sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 235 sizeof(struct synthhid_device_info_ack),
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 236 (unsigned long)&ack,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 237 VM_PKT_DATA_INBAND,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 238 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 239
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 240 if (!ret)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 241 input_device->dev_info_status = 0;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 242
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 243 cleanup:
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 244 complete(&input_device->wait_event);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 245
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 246 return;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 247 }
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 248 ---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
kernel test robot
build botRe: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
In reply to Kees CookI love your patch! Perhaps something to improve:
Hi Kees,
I love your patch! Perhaps something to improve:
[auto build test WARNING on staging/staging-testing]
[also build test WARNING on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210727] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: x86_64-randconfig-s022-20210728 (attached as .config) compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-341-g8af24329-dirty # https://github.com/0day-ci/linux/commit/6617421fca0f2272593a2659a5cba25bf8249857 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout 6617421fca0f2272593a2659a5cba25bf8249857 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/gpu/drm/gma500/ drivers/hid/
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
drivers/hid/hid-hyperv.c:202:40: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] report_desc_size @@ got restricted __le16 [usertype] wDescriptorLength @@
drivers/hid/hid-hyperv.c:202:40: sparse: expected unsigned int [usertype] report_desc_size
drivers/hid/hid-hyperv.c:202:40: sparse: got restricted __le16 [usertype] wDescriptorLength
>> drivers/hid/hid-hyperv.c:218:9: sparse: sparse: cast from restricted __le16
vim +218 drivers/hid/hid-hyperv.c
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 180
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 181 static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 182 struct synthhid_device_info *device_info)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 183 {
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 184 int ret = 0;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 185 struct hid_descriptor *desc;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 186 struct mousevsc_prt_msg ack;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 187
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 188 input_device->dev_info_status = -ENOMEM;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 189
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 190 input_device->hid_dev_info = device_info->hid_dev_info;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 191 desc = &device_info->hid_descriptor;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 192 if (desc->bLength == 0)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 193 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 194
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 195 /* The pointer is not NULL when we resume from hibernation */
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 196 kfree(input_device->hid_desc);
a4a23f6d68ad2c Thomas Meyer 2013-06-01 197 input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 198
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 199 if (!input_device->hid_desc)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 200 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 201
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 202 input_device->report_desc_size = desc->desc[0].wDescriptorLength;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 203 if (input_device->report_desc_size == 0) {
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 204 input_device->dev_info_status = -EINVAL;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 205 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 206 }
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 207
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 208 /* The pointer is not NULL when we resume from hibernation */
af13f9ed6f9aa6 Dexuan Cui 2019-11-19 209 kfree(input_device->report_desc);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 210 input_device->report_desc = kzalloc(input_device->report_desc_size,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 211 GFP_ATOMIC);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 212
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 213 if (!input_device->report_desc) {
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 214 input_device->dev_info_status = -ENOMEM;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 215 goto cleanup;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 216 }
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 217
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 @218 memcpy(input_device->report_desc,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 219 ((unsigned char *)desc) + desc->bLength,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 220 desc->desc[0].wDescriptorLength);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 221
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 222 /* Send the ack */
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 223 memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 224
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 225 ack.type = PIPE_MESSAGE_DATA;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 226 ack.size = sizeof(struct synthhid_device_info_ack);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 227
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 228 ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 229 ack.ack.header.size = 1;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 230 ack.ack.reserved = 0;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 231
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 232 ret = vmbus_sendpacket(input_device->device->channel,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 233 &ack,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 234 sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 235 sizeof(struct synthhid_device_info_ack),
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 236 (unsigned long)&ack,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 237 VM_PKT_DATA_INBAND,
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 238 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 239
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 240 if (!ret)
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 241 input_device->dev_info_status = 0;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 242
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 243 cleanup:
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 244 complete(&input_device->wait_event);
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 245
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 246 return;
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 247 }
b95f5bcb811e39 K. Y. Srinivasan 2011-11-17 248 ---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
kernel test robot
build botRe: [PATCH 34/64] fortify: Detect struct member overflows in memcpy() at compile-time
In reply to Kees CookI love your patch! Perhaps something to improve:
Hi Kees,
I love your patch! Perhaps something to improve:
[auto build test WARNING on staging/staging-testing]
[also build test WARNING on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210727] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: x86_64-rhel-8.3-kselftests (attached as .config) compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-341-g8af24329-dirty # https://github.com/0day-ci/linux/commit/6617421fca0f2272593a2659a5cba25bf8249857 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout 6617421fca0f2272593a2659a5cba25bf8249857 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
drivers/acpi/apei/erst.c:272:13: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected void *src @@ got void [noderef] __iomem * @@
drivers/acpi/apei/erst.c:272:13: sparse: expected void *src
drivers/acpi/apei/erst.c:272:13: sparse: got void [noderef] __iomem *
drivers/acpi/apei/erst.c:275:13: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected void *dst @@ got void [noderef] __iomem * @@
drivers/acpi/apei/erst.c:275:13: sparse: expected void *dst
drivers/acpi/apei/erst.c:275:13: sparse: got void [noderef] __iomem *
drivers/acpi/apei/erst.c:277:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void *src @@
drivers/acpi/apei/erst.c:277:25: sparse: expected void volatile [noderef] __iomem *addr
drivers/acpi/apei/erst.c:277:25: sparse: got void *src
drivers/acpi/apei/erst.c:283:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void *src @@
drivers/acpi/apei/erst.c:283:17: sparse: expected void volatile [noderef] __iomem *addr
drivers/acpi/apei/erst.c:283:17: sparse: got void *src
drivers/acpi/apei/erst.c:284:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got void *dst @@
drivers/acpi/apei/erst.c:284:17: sparse: expected void volatile [noderef] __iomem *addr
drivers/acpi/apei/erst.c:284:17: sparse: got void *dst
>> drivers/acpi/apei/erst.c:792:9: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got void [noderef] __iomem *static [toplevel] vaddr @@ drivers/acpi/apei/erst.c:792:9: sparse: expected void const * drivers/acpi/apei/erst.c:792:9: sparse: got void [noderef] __iomem *static [toplevel] vaddr >> drivers/acpi/apei/erst.c:792:9: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got void [noderef] __iomem *static [toplevel] vaddr @@
drivers/acpi/apei/erst.c:792:9: sparse: expected void const *
drivers/acpi/apei/erst.c:792:9: sparse: got void [noderef] __iomem *static [toplevel] vaddr
drivers/acpi/apei/erst.c:792:9: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void * @@ got void [noderef] __iomem *static [toplevel] vaddr @@
drivers/acpi/apei/erst.c:792:9: sparse: expected void *
drivers/acpi/apei/erst.c:792:9: sparse: got void [noderef] __iomem *static [toplevel] vaddr
drivers/acpi/apei/erst.c:793:20: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct cper_record_header *rcd_erange @@ got void [noderef] __iomem *static [toplevel] vaddr @@
drivers/acpi/apei/erst.c:793:20: sparse: expected struct cper_record_header *rcd_erange
drivers/acpi/apei/erst.c:793:20: sparse: got void [noderef] __iomem *static [toplevel] vaddr
drivers/acpi/apei/erst.c:830:17: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct cper_record_header *rcd_tmp @@ got void [noderef] __iomem * @@
drivers/acpi/apei/erst.c:830:17: sparse: expected struct cper_record_header *rcd_tmp
drivers/acpi/apei/erst.c:830:17: sparse: got void [noderef] __iomem *
--
>> drivers/misc/sgi-gru/grukdump.c:60:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got void [noderef] __user *[addressable] ubuf @@ drivers/misc/sgi-gru/grukdump.c:60:17: sparse: expected void const * drivers/misc/sgi-gru/grukdump.c:60:17: sparse: got void [noderef] __user *[addressable] ubuf >> drivers/misc/sgi-gru/grukdump.c:60:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got void [noderef] __user *[addressable] ubuf @@ drivers/misc/sgi-gru/grukdump.c:60:17: sparse: expected void const * drivers/misc/sgi-gru/grukdump.c:60:17: sparse: got void [noderef] __user *[addressable] ubuf >> drivers/misc/sgi-gru/grukdump.c:60:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void * @@ got void [noderef] __user *[addressable] ubuf @@
drivers/misc/sgi-gru/grukdump.c:60:17: sparse: expected void *
drivers/misc/sgi-gru/grukdump.c:60:17: sparse: got void [noderef] __user *[addressable] ubuf
drivers/misc/sgi-gru/grukdump.c:129:17: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct gru_context_configuration_handle *ubufcch @@ got void [noderef] __user *[assigned] ubuf @@
drivers/misc/sgi-gru/grukdump.c:129:17: sparse: expected struct gru_context_configuration_handle *ubufcch
drivers/misc/sgi-gru/grukdump.c:129:17: sparse: got void [noderef] __user *[assigned] ubuf
drivers/misc/sgi-gru/grukdump.c:192:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected void [noderef] __user *ubuf @@ got void *[addressable] [assigned] buf @@
drivers/misc/sgi-gru/grukdump.c:192:14: sparse: expected void [noderef] __user *ubuf
drivers/misc/sgi-gru/grukdump.c:192:14: sparse: got void *[addressable] [assigned] buf
drivers/misc/sgi-gru/grukdump.c:193:17: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected void [noderef] __user *ubufend @@ got void * @@
drivers/misc/sgi-gru/grukdump.c:193:17: sparse: expected void [noderef] __user *ubufend
drivers/misc/sgi-gru/grukdump.c:193:17: sparse: got void *
vim +792 drivers/acpi/apei/erst.c
a08f82d08053fb Huang Ying 2010-05-18 766
a08f82d08053fb Huang Ying 2010-05-18 767 int erst_write(const struct cper_record_header *record)
a08f82d08053fb Huang Ying 2010-05-18 768 {
a08f82d08053fb Huang Ying 2010-05-18 769 int rc;
a08f82d08053fb Huang Ying 2010-05-18 770 unsigned long flags;
a08f82d08053fb Huang Ying 2010-05-18 771 struct cper_record_header *rcd_erange;
a08f82d08053fb Huang Ying 2010-05-18 772
a08f82d08053fb Huang Ying 2010-05-18 773 if (erst_disable)
a08f82d08053fb Huang Ying 2010-05-18 774 return -ENODEV;
a08f82d08053fb Huang Ying 2010-05-18 775
a08f82d08053fb Huang Ying 2010-05-18 776 if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
a08f82d08053fb Huang Ying 2010-05-18 777 return -EINVAL;
a08f82d08053fb Huang Ying 2010-05-18 778
a08f82d08053fb Huang Ying 2010-05-18 779 if (erst_erange.attr & ERST_RANGE_NVRAM) {
3b38bb5f7f0635 Huang Ying 2010-12-02 780 if (!raw_spin_trylock_irqsave(&erst_lock, flags))
a08f82d08053fb Huang Ying 2010-05-18 781 return -EBUSY;
a08f82d08053fb Huang Ying 2010-05-18 782 rc = __erst_write_to_nvram(record);
3b38bb5f7f0635 Huang Ying 2010-12-02 783 raw_spin_unlock_irqrestore(&erst_lock, flags);
a08f82d08053fb Huang Ying 2010-05-18 784 return rc;
a08f82d08053fb Huang Ying 2010-05-18 785 }
a08f82d08053fb Huang Ying 2010-05-18 786
a08f82d08053fb Huang Ying 2010-05-18 787 if (record->record_length > erst_erange.size)
a08f82d08053fb Huang Ying 2010-05-18 788 return -EINVAL;
a08f82d08053fb Huang Ying 2010-05-18 789
3b38bb5f7f0635 Huang Ying 2010-12-02 790 if (!raw_spin_trylock_irqsave(&erst_lock, flags))
a08f82d08053fb Huang Ying 2010-05-18 791 return -EBUSY;
a08f82d08053fb Huang Ying 2010-05-18 @792 memcpy(erst_erange.vaddr, record, record->record_length);
a08f82d08053fb Huang Ying 2010-05-18 793 rcd_erange = erst_erange.vaddr;
a08f82d08053fb Huang Ying 2010-05-18 794 /* signature for serialization system */
a08f82d08053fb Huang Ying 2010-05-18 795 memcpy(&rcd_erange->persistence_information, "ER", 2);
a08f82d08053fb Huang Ying 2010-05-18 796
a08f82d08053fb Huang Ying 2010-05-18 797 rc = __erst_write_to_storage(0);
3b38bb5f7f0635 Huang Ying 2010-12-02 798 raw_spin_unlock_irqrestore(&erst_lock, flags);
a08f82d08053fb Huang Ying 2010-05-18 799
a08f82d08053fb Huang Ying 2010-05-18 800 return rc;
a08f82d08053fb Huang Ying 2010-05-18 801 }
a08f82d08053fb Huang Ying 2010-05-18 802 EXPORT_SYMBOL_GPL(erst_write);
a08f82d08053fb Huang Ying 2010-05-18 803 ---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH 35/64 fortify: Detect struct member overflows in memmove() at compile-time
In reply to Kees CookAs done for memcpy(), also update memmove() to use the same tightened compile-time checks under CONFIG_FORTIFY_SOURCE.
--- arch/x86/boot/compressed/misc.c | 3 ++- arch/x86/lib/memcpy_32.c | 1 + include/linux/fortify-string.h | 21 ++++--------------- .../read_overflow2_field-memmove.c | 5 +++++ .../write_overflow_field-memmove.c | 5 +++++ 5 files changed, 17 insertions(+), 18 deletions(-) create mode 100644 lib/test_fortify/read_overflow2_field-memmove.c create mode 100644 lib/test_fortify/write_overflow_field-memmove.c
arch/x86/boot/compressed/misc.c +2 -1
@@ -34,10 +34,11 @@* try to define their own functions if these are not defined as macros. */ #define memzero (s, n) memset((s), 0, (n)) +#ifndef memmove#define memmove memmove -/* Functions used by the included decompressor code below. */ void *memmove (void *dest,const void *src,size_t n); +#endif /* * This is set up by the setup-routine at boot-time
arch/x86/lib/memcpy_32.c +1 -0
@@ -4,6 +4,7 @@#undef memcpy#undef memset +#undef memmove __visible void *memcpy(void *to, const void *from, size_t n) {
include/linux/fortify-string.h +4 -17
@@ -284,22 +284,10 @@ __FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t size, __builtin_object_size(p, 0), __builtin_object_size(q, 0), \ __builtin_object_size(p, 1), __builtin_object_size(q, 1), \ memcpy) - -__FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) -{ -size_t p_size =__builtin_object_size (p,0 ); -size_t q_size =__builtin_object_size (q,0 ); - -if (__builtin_constant_p (size)) { -if (p_size < size) -__write_overflow (); -if (q_size < size) -__read_overflow2 (); - } -if (p_size < size || q_size < size) -fortify_panic (__func__); -return __underlying_memmove (p, q, size); -} +#define memmove (p, q, s) __fortify_memcpy_chk(p, q, s, \ + __builtin_object_size(p, 0), __builtin_object_size(q, 0), \ + __builtin_object_size(p, 1), __builtin_object_size(q, 1), \ + memmove)extern void *__real_memscan (void *,int ,__kernel_size_t )__RENAME (memscan); __FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size)
@@ -385,7 +373,6 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q)/* Don't use these outside the FORITFY_SOURCE implementation */ #undef __underlying_memchr#undef __underlying_memcmp -#undef __underlying_memmove#undef __underlying_memset#undef __underlying_strcat#undef __underlying_strcpy
lib/test_fortify/read_overflow2_field-memmove.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memmove(large, instance.buf, sizeof(instance.buf) + 1) + +#include "test_fortify.h"
lib/test_fortify/write_overflow_field-memmove.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memmove(instance.buf, large, sizeof(instance.buf) + 1) + +#include "test_fortify.h"
Signature · 1 line
2.30.2
kernel test robot
build botRe: [PATCH 35/64] fortify: Detect struct member overflows in memmove() at compile-time
I love your patch! Perhaps something to improve:
Hi Kees,
I love your patch! Perhaps something to improve:
[auto build test WARNING on staging/staging-testing]
[also build test WARNING on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210730] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: x86_64-randconfig-s021-20210728 (attached as .config) compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-341-g8af24329-dirty # https://github.com/0day-ci/linux/commit/ebf3f346baf4e0ddaf9e36fc6041bdc9ac43c3ed git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout ebf3f346baf4e0ddaf9e36fc6041bdc9ac43c3ed # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
>> drivers/video/fbdev/hgafb.c:496:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] dest @@ drivers/video/fbdev/hgafb.c:496:25: sparse: expected void const * drivers/video/fbdev/hgafb.c:496:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] dest >> drivers/video/fbdev/hgafb.c:496:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] src @@ drivers/video/fbdev/hgafb.c:496:25: sparse: expected void const * drivers/video/fbdev/hgafb.c:496:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] src >> drivers/video/fbdev/hgafb.c:496:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] dest @@ drivers/video/fbdev/hgafb.c:496:25: sparse: expected void const * drivers/video/fbdev/hgafb.c:496:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] dest >> drivers/video/fbdev/hgafb.c:496:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] src @@ drivers/video/fbdev/hgafb.c:496:25: sparse: expected void const * drivers/video/fbdev/hgafb.c:496:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] src >> drivers/video/fbdev/hgafb.c:496:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] dest @@
drivers/video/fbdev/hgafb.c:496:25: sparse: expected void *
drivers/video/fbdev/hgafb.c:496:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] dest
drivers/video/fbdev/hgafb.c:496:25: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] src @@
drivers/video/fbdev/hgafb.c:496:25: sparse: expected void const *
drivers/video/fbdev/hgafb.c:496:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] src
drivers/video/fbdev/hgafb.c:507:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] dest @@
drivers/video/fbdev/hgafb.c:507:25: sparse: expected void const *
drivers/video/fbdev/hgafb.c:507:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] dest
drivers/video/fbdev/hgafb.c:507:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] src @@
drivers/video/fbdev/hgafb.c:507:25: sparse: expected void const *
drivers/video/fbdev/hgafb.c:507:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] src
drivers/video/fbdev/hgafb.c:507:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] dest @@
drivers/video/fbdev/hgafb.c:507:25: sparse: expected void const *
drivers/video/fbdev/hgafb.c:507:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] dest
drivers/video/fbdev/hgafb.c:507:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] src @@
drivers/video/fbdev/hgafb.c:507:25: sparse: expected void const *
drivers/video/fbdev/hgafb.c:507:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] src
drivers/video/fbdev/hgafb.c:507:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] dest @@
drivers/video/fbdev/hgafb.c:507:25: sparse: expected void *
drivers/video/fbdev/hgafb.c:507:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] dest
drivers/video/fbdev/hgafb.c:507:25: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem *[assigned] src @@
drivers/video/fbdev/hgafb.c:507:25: sparse: expected void const *
drivers/video/fbdev/hgafb.c:507:25: sparse: got unsigned char [noderef] [usertype] __iomem *[assigned] src
vim +496 drivers/video/fbdev/hgafb.c
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 482
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 483 static void hgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 484 {
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 485 u_int rows, y1, y2;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 486 u8 __iomem *src;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 487 u8 __iomem *dest;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 488
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 489 if (area->dy <= area->sy) {
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 490 y1 = area->sy;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 491 y2 = area->dy;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 492
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 493 for (rows = area->height; rows--; ) {
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 494 src = rowaddr(info, y1) + (area->sx >> 3);
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 495 dest = rowaddr(info, y2) + (area->dx >> 3);
529ed806d4540d drivers/video/hgafb.c Brent Cook 2010-12-31 @496 memmove(dest, src, (area->width >> 3));
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 497 y1++;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 498 y2++;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 499 }
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 500 } else {
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 501 y1 = area->sy + area->height - 1;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 502 y2 = area->dy + area->height - 1;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 503
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 504 for (rows = area->height; rows--;) {
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 505 src = rowaddr(info, y1) + (area->sx >> 3);
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 506 dest = rowaddr(info, y2) + (area->dx >> 3);
529ed806d4540d drivers/video/hgafb.c Brent Cook 2010-12-31 507 memmove(dest, src, (area->width >> 3));
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 508 y1--;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 509 y2--;
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 510 }
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 511 }
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 512 }
^1da177e4c3f41 drivers/video/hgafb.c Linus Torvalds 2005-04-16 513 ---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH 36/64 scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Instead of writing beyond the end of evt_struct->iu.srp.cmd, target the upper union (evt_struct->iu.srp) instead, as that's what is being wiped.
--- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/ibmvscsi/ibmvscsi.c +1 -1
@@ -1055,8 +1055,8 @@ static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,return SCSI_MLQUEUE_HOST_BUSY ;/* Set up the actual SRP IU */ +memset (&evt_struct->iu.srp,0x00 ,SRP_MAX_IU_LEN ); 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);
Signature · 1 line
2.30.2
Re: [PATCH 36/64] scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp
Kees,
Quoted 8 lines
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Instead of writing beyond the end of
evt_struct->iu.srp.cmd, target the upper union (evt_struct->iu.srp) instead, as that's what is being wiped.Signed-off-by Kees Cook <[email protected]>
Orthogonal to your change, it wasn't immediately obvious to me that SRP_MAX_IU_LEN was the correct length to use for an srp_cmd. However, I traversed the nested unions and it does look OK.
For good measure I copied Tyrel and Brian.
Quoted 18 lines
--- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/scsi/ibmvscsi/ibmvscsi.c +1
-1@@ -1055,8 +1055,8 @@ static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,return SCSI_MLQUEUE_HOST_BUSY ;/* Set up the actual SRP IU */ +memset (&evt_struct->iu.srp,0x00 ,SRP_MAX_IU_LEN ); 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);
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Re: [PATCH 36/64] scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp
Quoted 7 lines · Martin K. Petersen
Kees,
Quoted 4 lines
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.
Quoted 8 lines
Quoted 4 lines
Instead of writing beyond the end of
evt_struct->iu.srp.cmd, target the upper union (evt_struct->iu.srp) instead, as that's what is being wiped.Signed-off-by Kees Cook <[email protected]>Orthogonal to your change, it wasn't immediately obvious to me that
SRP_MAX_IU_LENwas the correct length to use for ansrp_cmd. However, I traversed the nested unions and it does look OK.
Yeah, I had the same fun. Maybe I should add a BUILD_BUG_ON() here to help illustrate the relationship? I did that in a few other places where the equalities weren't very clear.
For example, change it to:
+ 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);
Quoted 4 lines
For good measure I copied Tyrel and Brian.
For the moment, I'll leave the patch as-is unless you prefer having the BUILD_BUG_ON(). :)
Thanks!
-Kees
Quoted 22 lines
Quoted 19 lines
--- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/scsi/ibmvscsi/ibmvscsi.c +1
-1@@ -1055,8 +1055,8 @@ static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,return SCSI_MLQUEUE_HOST_BUSY ;/* Set up the actual SRP IU */ +memset (&evt_struct->iu.srp,0x00 ,SRP_MAX_IU_LEN ); 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);Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Signature · 1 line
Kees Cook
Re: [PATCH 36/64] scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp
Kees,
Quoted 9 lines
For example, change it to:
drivers/scsi/ibmvscsi/ibmvscsi.c +2
-1+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 );For the moment, I'll leave the patch as-is unless you prefer having the
BUILD_BUG_ON(). :)
I'm OK with the BUILD_BUG_ON(). Hopefully Tyrel or Brian will chime in.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Tyrel Datwyler
maintainerRe: [PATCH 36/64] scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp
Quoted 10 lines · Martin K. Petersen
Kees,
Quoted 6 lines
For example, change it to:
drivers/scsi/ibmvscsi/ibmvscsi.c +2
-1+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 );
Quoted 5 lines
Quoted 2 lines
For the moment, I'll leave the patch as-is unless you prefer having the
BUILD_BUG_ON(). :)I'm OK with the
BUILD_BUG_ON(). Hopefully Tyrel or Brian will chime in.
All the other srp structs are at most 64 bytes and the size of the union is explicitly set to SRP_MAX_IU_LEN by the last field of the union.
union srp_iu {
struct srp_login_req login_req;
struct srp_login_rsp login_rsp;
struct srp_login_rej login_rej;
struct srp_i_logout i_logout;
struct srp_t_logout t_logout;
struct srp_tsk_mgmt tsk_mgmt;
struct srp_cmd cmd;
struct srp_rsp rsp;
u8 reserved[SRP_MAX_IU_LEN];
};So, in my mind if SRP_MAX_IU_LEN ever changes so does the size of the union making the BUILD_BUG_ON() superfluous. But it doesn't really hurt anything either.
-Tyrel
Re: [PATCH 36/64] scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp
In reply to Martin K. PetersenQuoted 10 lines · Martin K. Petersen
Kees,
Quoted 7 lines
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Instead of writing beyond the end of
evt_struct->iu.srp.cmd, target the upper union (evt_struct->iu.srp) instead, as that's what is being wiped.
Quoted 7 lines
Quoted 1 line
Signed-off-by Kees Cook <[email protected]>Orthogonal to your change, it wasn't immediately obvious to me that
SRP_MAX_IU_LENwas the correct length to use for ansrp_cmd. However, I traversed the nested unions and it does look OK.For good measure I copied Tyrel and Brian.
LGTM
Quoted 22 lines
Quoted 18 lines
--- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/scsi/ibmvscsi/ibmvscsi.c +1
-1@@ -1055,8 +1055,8 @@ static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,return SCSI_MLQUEUE_HOST_BUSY ;/* Set up the actual SRP IU */ +memset (&evt_struct->iu.srp,0x00 ,SRP_MAX_IU_LEN ); 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);
PATCH 37/64 string.h: Introduce memset_after() for wiping trailing members/padding
In reply to Kees CookA common idiom in kernel code is to wipe the contents of a structure after a given member. This includes places where there is trailing struct padding. These open-coded cases are usually difficult to read and very sensitive to struct layout changes. Introduce a new helper, memset_after() that takes the target struct instance, the byte to write, and the member name after which the zeroing should start.
--- include/linux/string.h | 12 ++++++++++++ lib/test_memcpy.c | 12 ++++++++++++ 2 files changed, 24 insertions(+)
include/linux/string.h +12 -0
@@ -272,6 +272,18 @@ static __always_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 +*/ +#define memset_after (obj, v, member) do { \ + memset((u8 *)(obj) + offsetofend(typeof(*(obj)), member), v, \ + sizeof(*(obj)) - offsetofend(typeof(*(obj)), member)); \ +} while (0) +/** * str_has_prefix - Test if a string has a given prefix * @str: The string to test
lib/test_memcpy.c +12 -0
@@ -223,6 +223,13 @@ static int __init test_memset(void) 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 dest = { };int count, value;u8 *ptr;
@@ -254,6 +261,11 @@ static int __init test_memset(void)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); +return 0 ;#undef TEST_OP }
Signature · 1 line
2.30.2
PATCH 38/64 xfrm: Use memset_after() to clear padding
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Clear trailing padding bytes using the new helper so that memset() doesn't get confused about writing "past the end" of the last struct member. There is no change to the resulting machine code.
--- net/xfrm/xfrm_policy.c | 4 +--- net/xfrm/xfrm_user.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-)
net/xfrm/xfrm_policy.c +1 -3
@@ -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 );
net/xfrm/xfrm_user.c +1 -1
@@ -2907,7 +2907,7 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const structcopy_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)
Signature · 1 line
2.30.2
PATCH 39/64 mac80211: Use memset_after() to clear tx status
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
Note that the common helper, ieee80211_tx_info_clear_status(), does NOT clear ack_signal, but the open-coded versions do. All three perform checks that the ack_signal position hasn't changed, though.
---
Should these each be clearing the same region? Because they're currently not.
--- drivers/net/wireless/ath/carl9170/tx.c | 4 +--- drivers/net/wireless/intersil/p54/txrx.c | 4 +--- include/net/mac80211.h | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-)
drivers/net/wireless/ath/carl9170/tx.c +1 -3
@@ -278,9 +278,7 @@ static void carl9170_tx_release(struct kref *ref)BUILD_BUG_ON ( offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); -memset (&txinfo->status.ack_signal,0 , -sizeof (struct ieee80211_tx_info ) - - offsetof(struct ieee80211_tx_info, status.ack_signal)); +memset_after (&txinfo->status,0 , rates);if (atomic_read (&ar->tx_total_queued)) ar->tx_schedule = true;
drivers/net/wireless/intersil/p54/txrx.c +1 -3
@@ -431,9 +431,7 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)* Clear manually, ieee80211_tx_info_clear_status would * clear the counts too and we need them. */ -memset (&info->status.ack_signal,0 , -sizeof (struct ieee80211_tx_info ) - - offsetof(struct ieee80211_tx_info, status.ack_signal)); +memset_after (&info->status,0 , rates);BUILD_BUG_ON (offsetof (struct ieee80211_tx_info , status.ack_signal) != 20);
include/net/mac80211.h +1 -3
@@ -1200,9 +1200,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)BUILD_BUG_ON ( offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); -memset (&info->status.ampdu_ack_len,0 , -sizeof (struct ieee80211_tx_info ) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); +memset_after (&info->status,0 , ack_signal); }
Signature · 1 line
2.30.2
Re: [PATCH 39/64] mac80211: Use memset_after() to clear tx status
Quoted 11 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.Note that the common helper,
ieee80211_tx_info_clear_status(), does NOT clearack_signal, but the open-coded versions do. All three perform checks that theack_signalposition hasn't changed, though.
Quick ping on this question: there is a mismatch between the common helper and the other places that do this. Is there a bug here?
Quoted 58 lines
Signed-off-by Kees Cook <[email protected]>---
Should these each be clearing the same region? Because they're currently not.--- drivers/net/wireless/ath/carl9170/tx.c | 4 +--- drivers/net/wireless/intersil/p54/txrx.c | 4 +--- include/net/mac80211.h | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-)drivers/net/wireless/ath/carl9170/tx.c +1
-3@@ -278,9 +278,7 @@ static void carl9170_tx_release(struct kref *ref)BUILD_BUG_ON ( offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); -memset (&txinfo->status.ack_signal,0 , -sizeof (struct ieee80211_tx_info ) - - offsetof(struct ieee80211_tx_info, status.ack_signal)); +memset_after (&txinfo->status,0 , rates);if (atomic_read (&ar->tx_total_queued)) ar->tx_schedule = true;drivers/net/wireless/intersil/p54/txrx.c +1
-3@@ -431,9 +431,7 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)* Clear manually, ieee80211_tx_info_clear_status would * clear the counts too and we need them. */ -memset (&info->status.ack_signal,0 , -sizeof (struct ieee80211_tx_info ) - - offsetof(struct ieee80211_tx_info, status.ack_signal)); +memset_after (&info->status,0 , rates);BUILD_BUG_ON (offsetof (struct ieee80211_tx_info , status.ack_signal) != 20);include/net/mac80211.h +1
-3@@ -1200,9 +1200,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)BUILD_BUG_ON ( offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); -memset (&info->status.ampdu_ack_len,0 , -sizeof (struct ieee80211_tx_info ) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); +memset_after (&info->status,0 , ack_signal); }Signature · 1 line
2.30.2
Signature · 1 line
Kees Cook
Johannes Berg
maintainerRe: [PATCH 39/64] mac80211: Use memset_after() to clear tx status
Quoted 9 lines · Kees Cook
Quoted 8 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
Quoted 6 lines
Quoted 3 lines
Note that the common helper,
ieee80211_tx_info_clear_status(), does NOT clearack_signal, but the open-coded versions do. All three perform checks that theack_signalposition hasn't changed, though.Quick ping on this question: there is a mismatch between the common helper and the other places that do this. Is there a bug here?
Yes.
The common helper should also clear ack_signal, but that was broken by commit e3e1a0bcb3f1 ("mac80211: reduce IEEE80211_TX_MAX_RATES"), because that commit changed the order of the fields and updated carl9170 and p54 properly but not the common helper...
It doesn't actually matter much because ack_signal is normally filled in afterwards, and even if it isn't, it's just for statistics.
The correct thing to do here would be to
memset_after(&info->status, 0, rates);
johannes
Re: [PATCH 39/64] mac80211: Use memset_after() to clear tx status
Quoted 17 lines · Johannes Berg
Quoted 9 lines · Kees Cook
Quoted 8 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.Quoted 6 lines
Quoted 3 lines
Note that the common helper,
ieee80211_tx_info_clear_status(), does NOT clearack_signal, but the open-coded versions do. All three perform checks that theack_signalposition hasn't changed, though.Quick ping on this question: there is a mismatch between the common helper and the other places that do this. Is there a bug here?
Quoted 6 lines
Yes.
The common helper should also clear
ack_signal, but that was broken by commite3e1a0bcb3f1("mac80211: reduceIEEE80211_TX_MAX_RATES"), because that commit changed the order of the fields and updated carl9170 and p54 properly but not the common helper...
It looks like p54 actually uses the rates, which is why it does this manually. I can't see why carl9170 does this manually, though.
Quoted 6 lines
It doesn't actually matter much because
ack_signalis normally filled in afterwards, and even if it isn't, it's just for statistics.The correct thing to do here would be to
memset_after(&info->status, 0, rates);
Sounds good; I will adjust these (and drop the BULID_BUG_ONs, as you suggest in the next email).
Thanks!
-Kees
Signature · 1 line
Kees Cook
Johannes Berg
maintainerRe: [PATCH 39/64] mac80211: Use memset_after() to clear tx status
Quoted 8 lines · Kees Cook
Quoted 5 lines
The common helper should also clear
ack_signal, but that was broken by commite3e1a0bcb3f1("mac80211: reduceIEEE80211_TX_MAX_RATES"), because that commit changed the order of the fields and updated carl9170 and p54 properly but not the common helper...It looks like p54 actually uses the rates, which is why it does this manually. I can't see why carl9170 does this manually, though.
mac80211 also uses the rates later again on status reporting, it just expects the # of attempts to be filled etc. I haven't looked at carl9170, but I would expect it to do something there and do it correctly, even though old it's a well-written driver and uses mac80211 rate control, so this would need to be correct for decent performance.
But I guess it could be that the helper could be used because the rates were already handed to the firmware, and the code was just copy/pasted from p54 (the drivers were, IIRC, developed by the same folks)
johannes
Johannes Berg
maintainerRe: [PATCH 39/64] mac80211: Use memset_after() to clear tx status
In reply to Kees CookQuoted 10 lines · Kees Cook
drivers/net/wireless/ath/carl9170/tx.c static void carl9170_tx_release(struct kref *ref) · line 281
Quoted 10 lines
(quoted diff) +0
-0@@ -278,9 +278,7 @@ static void carl9170_tx_release(struct kref *ref)BUILD_BUG_ON(
offsetof(struct ieee80211_tx_info, status.ack_signal)!= 20);drivers/net/wireless/ath/carl9170/tx.c +1
-3-memset (&txinfo->status.ack_signal,0 , -sizeof (struct ieee80211_tx_info ) - - offsetof(struct ieee80211_tx_info, status.ack_signal)); +memset_after (&txinfo->status,0 , rates);
FWIW, I think we should also remove the BUILD_BUG_ON() now in all the places - that was meant to give people a hint to update if some field ordering etc. changed, but now that it's "after rates" this is no longer necessary.
johannes
PATCH 40/64 net: 802: Use memset_after() to clear struct fields
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
--- net/802/hippi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/802/hippi.c +1 -1
@@ -65,7 +65,7 @@ static int hippi_header(struct sk_buff *skb, struct net_device *dev, hip->le.src_addr_type =2 ;/* 12 bit SC address */ memcpy (hip->le.src_switch_addr, dev->dev_addr +3 ,3 ); -memset (&hip->le.reserved,0 ,16 ); +memset_after (&hip->le,0 , src_switch_addr); hip->snap.dsap =HIPPI_EXTENDED_SAP ; hip->snap.ssap =HIPPI_EXTENDED_SAP ;
Signature · 1 line
2.30.2
PATCH 41/64 net: dccp: Use memset_after() for TP zeroing
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
--- net/dccp/trace.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/dccp/trace.h +1 -3
@@ -60,9 +60,7 @@ TRACE_EVENT(dccp_probe, __entry->tx_t_ipi = hc->tx_t_ipi; }else { __entry->tx_s =0 ; -memset (&__entry->tx_rtt,0 , (void *)&__entry->tx_t_ipi - - (void *)&__entry->tx_rtt + -sizeof (__entry->tx_t_ipi)); +memset_after (__entry,0 , tx_s); } ),
Signature · 1 line
2.30.2
PATCH 42/64 net: qede: Use memset_after() for counters
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
---
The old code seems to be doing the wrong thing: starting from not the first member, but sized for the whole struct. Which is correct?
--- drivers/net/ethernet/qlogic/qede/qede_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/qlogic/qede/qede_main.c +1 -1
@@ -2419,7 +2419,7 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, goto out; err4:qede_sync_free_irqs (edev); -memset (&edev->int_info.msix_cnt,0 ,sizeof (struct qed_int_info )); +memset_after (&edev->int_info,0 , msix); err3:qede_napi_disable_remove (edev); err2:
Signature · 1 line
2.30.2
Re: [PATCH 42/64] net: qede: Use memset_after() for counters
Quoted 4 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.
Quoted 8 lines
Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.Signed-off-by Kees Cook <[email protected]>---
The old code seems to be doing the wrong thing: starting from not the first member, but sized for the whole struct. Which is correct?
Quick ping on this question.
The old code seems to be doing the wrong thing: it starts from the second member and writes beyond int_info, clobbering qede_lock:
struct qede_dev {
...
struct qed_int_info int_info;
/* Smaller private variant of the RTNL lock */
struct mutex qede_lock;
...struct qed_int_info {
struct msix_entry *msix;
u8 msix_cnt;
/* This should be updated by the protocol driver */
u8 used_cnt;
};Should this also clear the "msix" member, or should this not write beyond int_info? This patch does the latter.
-Kees
Quoted 20 lines
--- drivers/net/ethernet/qlogic/qede/qede_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/net/ethernet/qlogic/qede/qede_main.c +1
-1@@ -2419,7 +2419,7 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, goto out; err4:qede_sync_free_irqs (edev); -memset (&edev->int_info.msix_cnt,0 ,sizeof (struct qed_int_info )); +memset_after (&edev->int_info,0 , msix); err3:qede_napi_disable_remove (edev); err2:Signature · 1 line
2.30.2
Signature · 1 line
Kees Cook
PATCH 43/64 ath11k: Use memset_after() for clearing queue descriptors
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct. Additionally split up a later field-spanning memset() so that memset() can reason about the size.
--- drivers/net/wireless/ath/ath11k/hal_rx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
drivers/net/wireless/ath/ath11k/hal_rx.c +6 -7
@@ -29,8 +29,7 @@ static int ath11k_hal_reo_cmd_queue_stats(struct hal_tlv_hdr *tlv,FIELD_PREP (HAL_TLV_HDR_LEN ,sizeof (*desc)); desc = (struct hal_reo_get_queue_stats *)tlv->value; -memset (&desc->queue_addr_lo,0 , - (sizeof (*desc) -sizeof (struct hal_reo_cmd_hdr ))); +memset_after (desc,0 , cmd); desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED ;if (cmd->flag &HAL_REO_CMD_FLG_NEED_STATUS )
@@ -62,8 +61,7 @@ static int ath11k_hal_reo_cmd_flush_cache(struct ath11k_hal *hal, struct hal_tlvFIELD_PREP (HAL_TLV_HDR_LEN ,sizeof (*desc)); desc = (struct hal_reo_flush_cache *)tlv->value; -memset (&desc->cache_addr_lo,0 , - (sizeof (*desc) -sizeof (struct hal_reo_cmd_hdr ))); +memset_after (desc,0 , cmd); desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED ;if (cmd->flag &HAL_REO_CMD_FLG_NEED_STATUS )
@@ -101,8 +99,7 @@ static int ath11k_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv,FIELD_PREP (HAL_TLV_HDR_LEN ,sizeof (*desc)); desc = (struct hal_reo_update_rx_queue *)tlv->value; -memset (&desc->queue_addr_lo,0 , - (sizeof (*desc) -sizeof (struct hal_reo_cmd_hdr ))); +memset_after (desc,0 , cmd); desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED ;if (cmd->flag &HAL_REO_CMD_FLG_NEED_STATUS )
@@ -762,15 +759,17 @@ void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size,* size changes and also send WMI message to FW to change the REO * queue descriptor in Rx peer entry as part of dp_rx_tid_update. */ -memset (ext_desc,0 ,3 *sizeof (*ext_desc)); +memset (ext_desc,0 ,sizeof (*ext_desc));ath11k_hal_reo_set_desc_hdr (&ext_desc->desc_hdr,HAL_DESC_REO_OWNED ,HAL_DESC_REO_QUEUE_EXT_DESC ,REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1 ); ext_desc++; +memset (ext_desc,0 ,sizeof (*ext_desc));ath11k_hal_reo_set_desc_hdr (&ext_desc->desc_hdr,HAL_DESC_REO_OWNED ,HAL_DESC_REO_QUEUE_EXT_DESC ,REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2 ); ext_desc++; +memset (ext_desc,0 ,sizeof (*ext_desc));ath11k_hal_reo_set_desc_hdr (&ext_desc->desc_hdr,HAL_DESC_REO_OWNED ,HAL_DESC_REO_QUEUE_EXT_DESC ,REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3 );
Signature · 1 line
2.30.2
PATCH 44/64 iw_cxgb4: Use memset_after() for cpl_t5_pass_accept_rpl
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct. Additionally, since everything appears to perform a roundup (including allocation), just change the size of the struct itself and add a build-time check to validate the expected size.
--- drivers/infiniband/hw/cxgb4/cm.c | 5 +++-- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/infiniband/hw/cxgb4/cm.c +3 -2
@@ -2471,7 +2471,8 @@ static int accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,skb_get (skb); rpl =cplhdr (skb);if (!is_t4 (adapter_type)) { -skb_trim (skb,roundup (sizeof (*rpl5),16 )); +BUILD_BUG_ON (sizeof (*rpl5) !=roundup (sizeof (*rpl5),16 )); +skb_trim (skb,sizeof (*rpl5)); rpl5 = (void *)rpl;INIT_TP_WR (rpl5, ep->hwtid); }else {
@@ -2487,7 +2488,7 @@ static int accept_cr(struct c4iw_ep *ep, struct sk_buff *skb, opt2 |=CONG_CNTRL_V (CONG_ALG_TAHOE ); opt2 |=T5_ISS_F ; rpl5 = (void *)rpl; -memset (&rpl5->iss,0 ,roundup (sizeof (*rpl5)-sizeof (*rpl),16 )); +memset_after (rpl5,0 , opt0);if (peer2peer) isn +=4 ; rpl5->iss =cpu_to_be32 (isn);
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +1 -1
@@ -497,7 +497,7 @@ struct cpl_t5_pass_accept_rpl {__be32 opt2;__be64 opt0;__be32 iss; -__be32 rsvd; +__be32 rsvd[3 ]; };struct cpl_act_open_req {
Signature · 1 line
2.30.2
PATCH 45/64 intel_th: msu: Use memset_after() for clearing hw header
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
--- drivers/hwtracing/intel_th/msu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/hwtracing/intel_th/msu.c +1 -3
@@ -658,13 +658,11 @@ static void msc_buffer_clear_hw_header(struct msc *msc)list_for_each_entry (win, &msc->win_list, entry) {unsigned int blk; -size_t hw_sz =sizeof (struct msc_block_desc ) - - offsetof(struct msc_block_desc , hw_tag);for_each_sg (win->sgt->sgl, sg, win->nr_segs, blk) {struct msc_block_desc *bdesc =sg_virt (sg); -memset (&bdesc->hw_tag,0 , hw_sz); +memset_after (bdesc,0 , res0); } } }
Signature · 1 line
2.30.2
PATCH 46/64 IB/mthca: Use memset_after() for clearing mpt_entry
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
--- drivers/infiniband/hw/mthca/mthca_mr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/infiniband/hw/mthca/mthca_mr.c +1 -2
@@ -469,8 +469,7 @@ int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, mpt_entry->start =cpu_to_be64 (iova); mpt_entry->length =cpu_to_be64 (total_size); -memset (&mpt_entry->lkey,0 , -sizeof *mpt_entry - offsetof(struct mthca_mpt_entry , lkey)); +memset_after (mpt_entry,0 , length);if (mr->mtt) mpt_entry->mtt_seg =
Signature · 1 line
2.30.2
PATCH 47/64 btrfs: Use memset_after() to clear end of struct
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.
--- fs/btrfs/root-tree.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
fs/btrfs/root-tree.c +1 -4
@@ -39,10 +39,7 @@ 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)); - +memset_after (item,0 , level);generate_random_guid (item->uuid); } }
Signature · 1 line
2.30.2
Re: [PATCH 47/64] btrfs: Use memset_after() to clear end of struct
Quoted 18 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.Signed-off-by Kees Cook <[email protected]>--- fs/btrfs/root-tree.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)fs/btrfs/root-tree.c +0
-0
fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 45
Quoted 7 lines
fs/btrfs/root-tree.c +0
-4@@ -39,10 +39,7 @@ 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)); -
Please add
/* Clear all members from generation_v2 onwards */
fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 43
Quoted 2 lines
fs/btrfs/root-tree.c +1
-0+memset_after (item,0 , level);generate_random_guid (item->uuid);
Re: [PATCH 47/64] btrfs: Use memset_after() to clear end of struct
Quoted 28 lines · David Sterba
Quoted 18 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.Signed-off-by Kees Cook <[email protected]>--- fs/btrfs/root-tree.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)fs/btrfs/root-tree.c +0
-0fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 45
Quoted 7 lines
fs/btrfs/root-tree.c +0
-4@@ -39,10 +39,7 @@ 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)); -Please add
Quoted 3 lines
/* Clear all members from generation_v2 onwards */fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 42
Quoted 1 line
fs/btrfs/root-tree.c +1
-0+memset_after (item,0 , level);
Perhaps there should be another helper memset_starting()? That would make these cases a bit more self-documenting.
+ memset_starting(item, 0, generation_v2);
Quoted 3 lines
fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 43
Quoted 1 line
fs/btrfs/root-tree.c +0
-0generate_random_guid (item->uuid);Acked-by David Sterba <[email protected]>
What do you think?
-Kees
Signature · 1 line
Kees Cook
Re: [PATCH 47/64] btrfs: Use memset_after() to clear end of struct
Quoted 31 lines · Kees Cook
Quoted 30 lines · David Sterba
Quoted 18 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.Signed-off-by Kees Cook <[email protected]>--- fs/btrfs/root-tree.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)fs/btrfs/root-tree.c +0
-0fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 45
Quoted 7 lines
fs/btrfs/root-tree.c +0
-4@@ -39,10 +39,7 @@ 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)); -Please add
/* Clear all members from generation_v2 onwards */
Quoted 4 lines
Quoted 1 line
fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 42
Quoted 1 line
fs/btrfs/root-tree.c +1
-0+memset_after (item,0 , level);Perhaps there should be another helper
memset_starting()? That would make these cases a bit more self-documenting.
That would be better, yes.
Review
Quoted 1 line
(quoted diff) +1
-0+ memset_starting(item, 0, generation_v2);
memset_from?
Re: [PATCH 47/64] btrfs: Use memset_after() to clear end of struct
Quoted 37 lines · David Sterba
Quoted 31 lines · Kees Cook
Quoted 30 lines · David Sterba
Quoted 18 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Use
memset_after()somemset()doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct.Signed-off-by Kees Cook <[email protected]>--- fs/btrfs/root-tree.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)fs/btrfs/root-tree.c +0
-0fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 45
Quoted 7 lines
fs/btrfs/root-tree.c +0
-4@@ -39,10 +39,7 @@ 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)); -Please add
/* Clear all members from generation_v2 onwards */Quoted 4 lines
Quoted 1 line
fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 42
Quoted 1 line
fs/btrfs/root-tree.c +1
-0+memset_after (item,0 , level);Perhaps there should be another helper
memset_starting()? That would make these cases a bit more self-documenting.
Quoted 5 lines
That would be better, yes.
Review
Quoted 1 line
(quoted diff) +1
-0+ memset_starting(item, 0, generation_v2);
memset_from?
For v2, I bikeshed this to "memset_startat" since "from" is semantically close to "source" which I thought might be confusing. (I, too, did not like "starting".) :)
Can I make "bikeshed" a verb? :P
Signature · 1 line
Kees Cook
Re: [PATCH 47/64] btrfs: Use memset_after() to clear end of struct
Quoted 21 lines · Kees Cook
Quoted 20 lines · David Sterba
Quoted 12 lines · Kees Cook
Quoted 11 lines · David Sterba
fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 45
Quoted 6 lines · Kees Cook
fs/btrfs/root-tree.c +0
-4}if (need_reset) { -memset (&item->generation_v2,0 , -sizeof (*item) - offsetof(struct btrfs_root_item , - generation_v2)); -Please add
/* Clear all members from generation_v2 onwards */Quoted 4 lines
Quoted 1 line
fs/btrfs/root-tree.c static void btrfs_read_root_item(struct extent_buffer *eb, int slot, · line 42
Quoted 1 line
fs/btrfs/root-tree.c +1
-0+memset_after (item,0 , level);Perhaps there should be another helper
memset_starting()? That would make these cases a bit more self-documenting.That would be better, yes.
Quoted 7 lines
Quoted 3 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ memset_starting(item, 0, generation_v2);
memset_from?For v2, I bikeshed this to "
memset_startat" since "from" is semantically close to "source" which I thought might be confusing. (I, too, did not like "starting".) :)
memset_startat works for me, thanks.
PATCH 48/64 drbd: Use struct_group() to zero algs
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add a struct_group() for the algs so that memset() can correctly reason about the size.
--- drivers/block/drbd/drbd_main.c | 3 ++- drivers/block/drbd/drbd_protocol.h | 6 ++++-- drivers/block/drbd/drbd_receiver.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-)
drivers/block/drbd/drbd_main.c +2 -1
@@ -729,7 +729,8 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device) cmd = apv >=89 ?P_SYNC_PARAM89 :P_SYNC_PARAM ;/* initialize verify_alg and csums_alg */ -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));if (get_ldev (peer_device->device)) { dc =rcu_dereference (peer_device->device->ldev->disk_conf);
drivers/block/drbd/drbd_protocol.h +4 -2
@@ -283,8 +283,10 @@ struct p_rs_param_89 {struct p_rs_param_95 {u32 resync_rate; -char verify_alg[SHARED_SECRET_MAX ]; -char csums_alg[SHARED_SECRET_MAX ]; + struct_group(algs, + char verify_alg[SHARED_SECRET_MAX]; +char csums_alg[SHARED_SECRET_MAX ]; + );u32 c_plan_ahead;u32 c_delay_target;u32 c_fill_target;
drivers/block/drbd/drbd_receiver.c +2 -1
@@ -3921,7 +3921,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i/* initialize verify_alg and csums_alg */ p = pi->data; -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs)); err =drbd_recv_all (peer_device->connection, p, header_size);if (err)
Signature · 1 line
2.30.2
Re: [PATCH 48/64] drbd: Use struct_group() to zero algs
Quoted 50 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add a
struct_group()for the algs so thatmemset()can correctly reason about the size.Signed-off-by Kees Cook <[email protected]>--- drivers/block/drbd/drbd_main.c | 3 ++- drivers/block/drbd/drbd_protocol.h | 6 ++++-- drivers/block/drbd/drbd_receiver.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-)drivers/block/drbd/drbd_main.c +2
-1@@ -729,7 +729,8 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device) cmd = apv >=89 ?P_SYNC_PARAM89 :P_SYNC_PARAM ;/* initialize verify_alg and csums_alg */ -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));if (get_ldev (peer_device->device)) { dc =rcu_dereference (peer_device->device->ldev->disk_conf);drivers/block/drbd/drbd_protocol.h +4
-2@@ -283,8 +283,10 @@ struct p_rs_param_89 {struct p_rs_param_95 {u32 resync_rate; -char verify_alg[SHARED_SECRET_MAX ]; -char csums_alg[SHARED_SECRET_MAX ]; + struct_group(algs, + char verify_alg[SHARED_SECRET_MAX]; +char csums_alg[SHARED_SECRET_MAX ]; + );u32 c_plan_ahead;u32 c_delay_target;u32 c_fill_target;drivers/block/drbd/drbd_receiver.c +0
-0
drivers/block/drbd/drbd_receiver.c static int receive_SyncParam(struct drbd_connection *connection, struct packet_i · line 3925
Quoted 6 lines
drivers/block/drbd/drbd_receiver.c +2
-1@@ -3921,7 +3921,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i/* initialize verify_alg and csums_alg */ p = pi->data; -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));
Using struct_group() introduces complexity. Has it been considered not to modify struct p_rs_param_95 and instead to use two memset() calls instead of one (one memset() call per member)?
Thanks,
Bart.
Re: [PATCH 48/64] drbd: Use struct_group() to zero algs
Quoted 49 lines · Bart Van Assche
Quoted 48 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add a
struct_group()for the algs so thatmemset()can correctly reason about the size.Signed-off-by Kees Cook <[email protected]>--- drivers/block/drbd/drbd_main.c | 3 ++- drivers/block/drbd/drbd_protocol.h | 6 ++++-- drivers/block/drbd/drbd_receiver.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-)drivers/block/drbd/drbd_main.c +2
-1@@ -729,7 +729,8 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device) cmd = apv >=89 ?P_SYNC_PARAM89 :P_SYNC_PARAM ;/* initialize verify_alg and csums_alg */ -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));if (get_ldev (peer_device->device)) { dc =rcu_dereference (peer_device->device->ldev->disk_conf);drivers/block/drbd/drbd_protocol.h +4
-2@@ -283,8 +283,10 @@ struct p_rs_param_89 {struct p_rs_param_95 {u32 resync_rate; -char verify_alg[SHARED_SECRET_MAX ]; -char csums_alg[SHARED_SECRET_MAX ]; + struct_group(algs, + char verify_alg[SHARED_SECRET_MAX]; +char csums_alg[SHARED_SECRET_MAX ]; + );u32 c_plan_ahead;u32 c_delay_target;u32 c_fill_target;drivers/block/drbd/drbd_receiver.c +0
-0@@ -3921,7 +3921,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i/* initialize verify_alg and csums_alg */
Quoted 8 lines
drivers/block/drbd/drbd_receiver.c static int receive_SyncParam(struct drbd_connection *connection, struct packet_i · line 3925
Quoted 4 lines
drivers/block/drbd/drbd_receiver.c +2
-1p = pi->data; -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));Using
struct_group()introduces complexity. Has it been considered not to modify structp_rs_param_95and instead to use twomemset()calls instead of one (onememset()call per member)?
I went this direction because using two memset()s (or memcpy()s in other patches) changes the machine code. It's not much of a change, but it seems easier to justify "no binary changes" via the use of struct_group().
If splitting the memset() is preferred, I can totally do that instead. :)
-Kees
Signature · 1 line
Kees Cook
Re: [PATCH 48/64] drbd: Use struct_group() to zero algs
Quoted 59 lines · Kees Cook
Quoted 49 lines · Bart Van Assche
Quoted 48 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add a
struct_group()for the algs so thatmemset()can correctly reason about the size.Signed-off-by Kees Cook <[email protected]>--- drivers/block/drbd/drbd_main.c | 3 ++- drivers/block/drbd/drbd_protocol.h | 6 ++++-- drivers/block/drbd/drbd_receiver.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-)drivers/block/drbd/drbd_main.c +2
-1@@ -729,7 +729,8 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device) cmd = apv >=89 ?P_SYNC_PARAM89 :P_SYNC_PARAM ;/* initialize verify_alg and csums_alg */ -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));if (get_ldev (peer_device->device)) { dc =rcu_dereference (peer_device->device->ldev->disk_conf);drivers/block/drbd/drbd_protocol.h +4
-2@@ -283,8 +283,10 @@ struct p_rs_param_89 {struct p_rs_param_95 {u32 resync_rate; -char verify_alg[SHARED_SECRET_MAX ]; -char csums_alg[SHARED_SECRET_MAX ]; + struct_group(algs, + char verify_alg[SHARED_SECRET_MAX]; +char csums_alg[SHARED_SECRET_MAX ]; + );u32 c_plan_ahead;u32 c_delay_target;u32 c_fill_target;drivers/block/drbd/drbd_receiver.c +0
-0@@ -3921,7 +3921,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i/* initialize verify_alg and csums_alg */ Quoted 8 lines
drivers/block/drbd/drbd_receiver.c static int receive_SyncParam(struct drbd_connection *connection, struct packet_i · line 3925
Quoted 4 lines
drivers/block/drbd/drbd_receiver.c +2
-1p = pi->data; -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));Using
struct_group()introduces complexity. Has it been considered not to modify structp_rs_param_95and instead to use twomemset()calls instead of one (onememset()call per member)?
Quoted 6 lines
I went this direction because using two memset()s (or memcpy()s in other patches) changes the machine code. It's not much of a change, but it seems easier to justify "no binary changes" via the use of
struct_group().If splitting the
memset()is preferred, I can totally do that instead. :)
I don't have a strong opinion about this. Lars, do you want to comment on this patch?
Thanks,
Bart.
Lars Ellenberg
maintainerRe: [PATCH 48/64] drbd: Use struct_group() to zero algs
Quoted 64 lines · Bart Van Assche
Quoted 63 lines · Kees Cook
Quoted 49 lines · Bart Van Assche
Quoted 48 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add a
struct_group()for the algs so thatmemset()can correctly reason about the size.Signed-off-by Kees Cook <[email protected]>--- drivers/block/drbd/drbd_main.c | 3 ++- drivers/block/drbd/drbd_protocol.h | 6 ++++-- drivers/block/drbd/drbd_receiver.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-)drivers/block/drbd/drbd_main.c +2
-1@@ -729,7 +729,8 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device) cmd = apv >=89 ?P_SYNC_PARAM89 :P_SYNC_PARAM ;/* initialize verify_alg and csums_alg */ -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));if (get_ldev (peer_device->device)) { dc =rcu_dereference (peer_device->device->ldev->disk_conf);drivers/block/drbd/drbd_protocol.h +4
-2@@ -283,8 +283,10 @@ struct p_rs_param_89 {struct p_rs_param_95 {u32 resync_rate; -char verify_alg[SHARED_SECRET_MAX ]; -char csums_alg[SHARED_SECRET_MAX ]; + struct_group(algs, + char verify_alg[SHARED_SECRET_MAX]; +char csums_alg[SHARED_SECRET_MAX ]; + );u32 c_plan_ahead;u32 c_delay_target;u32 c_fill_target;drivers/block/drbd/drbd_receiver.c +0
-0@@ -3921,7 +3921,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i/* initialize verify_alg and csums_alg */ Quoted 8 lines
drivers/block/drbd/drbd_receiver.c static int receive_SyncParam(struct drbd_connection *connection, struct packet_i · line 3925
Quoted 4 lines
drivers/block/drbd/drbd_receiver.c +2
-1p = pi->data; -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));Using
struct_group()introduces complexity. Has it been considered not to modify structp_rs_param_95and instead to use twomemset()calls instead of one (onememset()call per member)?I went this direction because using two memset()s (or memcpy()s in other patches) changes the machine code. It's not much of a change, but it seems easier to justify "no binary changes" via the use of
struct_group().
Quoted 5 lines
Quoted 2 lines
If splitting the
memset()is preferred, I can totally do that instead. :)I don't have a strong opinion about this. Lars, do you want to comment on this patch?
Fine either way. "no binary changes" sounds good ;-)
Thanks,
Lars
Re: [PATCH 48/64] drbd: Use struct_group() to zero algs
In reply to Kees CookQuoted 60 lines · Kees Cook
Quoted 49 lines · Bart Van Assche
Quoted 48 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add a
struct_group()for the algs so thatmemset()can correctly reason about the size.Signed-off-by Kees Cook <[email protected]>--- drivers/block/drbd/drbd_main.c | 3 ++- drivers/block/drbd/drbd_protocol.h | 6 ++++-- drivers/block/drbd/drbd_receiver.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-)drivers/block/drbd/drbd_main.c +2
-1@@ -729,7 +729,8 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device) cmd = apv >=89 ?P_SYNC_PARAM89 :P_SYNC_PARAM ;/* initialize verify_alg and csums_alg */ -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));if (get_ldev (peer_device->device)) { dc =rcu_dereference (peer_device->device->ldev->disk_conf);drivers/block/drbd/drbd_protocol.h +4
-2@@ -283,8 +283,10 @@ struct p_rs_param_89 {struct p_rs_param_95 {u32 resync_rate; -char verify_alg[SHARED_SECRET_MAX ]; -char csums_alg[SHARED_SECRET_MAX ]; + struct_group(algs, + char verify_alg[SHARED_SECRET_MAX]; +char csums_alg[SHARED_SECRET_MAX ]; + );u32 c_plan_ahead;u32 c_delay_target;u32 c_fill_target;drivers/block/drbd/drbd_receiver.c +0
-0@@ -3921,7 +3921,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i/* initialize verify_alg and csums_alg */ Quoted 8 lines
drivers/block/drbd/drbd_receiver.c static int receive_SyncParam(struct drbd_connection *connection, struct packet_i · line 3925
Quoted 4 lines
drivers/block/drbd/drbd_receiver.c +2
-1p = pi->data; -memset (p->verify_alg,0 ,2 *SHARED_SECRET_MAX ); +BUILD_BUG_ON (sizeof (p->algs) !=2 *SHARED_SECRET_MAX ); +memset (&p->algs,0 ,sizeof (p->algs));Using
struct_group()introduces complexity. Has it been considered not to modify structp_rs_param_95and instead to use twomemset()calls instead of one (onememset()call per member)?
Quoted 6 lines
I went this direction because using two memset()s (or memcpy()s in other patches) changes the machine code. It's not much of a change, but it seems easier to justify "no binary changes" via the use of
struct_group().If splitting the
memset()is preferred, I can totally do that instead. :)
I'm not sure that compilers can fold memsets of adjacent members. It might not matter, but you could wrap these members in a _named_ struct then simply use assignment for optimal codegen.
Signature · 2 lines
Thanks, ~Nick Desaulniers
PATCH 49/64 cm4000_cs: Use struct_group() to zero struct cm4000_dev region
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct cm4000_dev that should be initialized to zero.
--- drivers/char/pcmcia/cm4000_cs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/char/pcmcia/cm4000_cs.c +4 -5
@@ -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;
Signature · 1 line
2.30.2
Re: [PATCH 49/64] cm4000_cs: Use struct_group() to zero struct cm4000_dev region
Quoted 11 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add
struct_group()to mark region of structcm4000_devthat should be initialized to zero.Signed-off-by Kees Cook <[email protected]>--- drivers/char/pcmcia/cm4000_cs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
PATCH 50/64 KVM: x86: Use struct_group() to zero decode cache
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct x86_emulate_ctxt that should be initialized to zero.
--- arch/x86/kvm/emulate.c | 3 +-- arch/x86/kvm/kvm_emulate.h | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-)
arch/x86/kvm/emulate.c +1 -2
@@ -5377,8 +5377,7 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop)void init_decode_cache (struct x86_emulate_ctxt *ctxt) { -memset (&ctxt->rip_relative,0 , - (void *)&ctxt->modrm - (void *)&ctxt->rip_relative); +memset (&ctxt->decode_cache,0 ,sizeof (ctxt->decode_cache)); ctxt->io_read.pos =0 ; ctxt->io_read.end =0 ;
arch/x86/kvm/kvm_emulate.h +11 -8
@@ -341,14 +341,17 @@ struct x86_emulate_ctxt {* the rest are initialized unconditionally in x86_decode_insn * or elsewhere */ -bool rip_relative; -u8 rex_prefix; -u8 lock_prefix; -u8 rep_prefix; -/* bitmaps of registers in _regs[] that can be read */ -u32 regs_valid; -/* bitmaps of registers in _regs[] that have been written */ -u32 regs_dirty; +struct_group (decode_cache, + bool rip_relative; + u8 rex_prefix; + u8 lock_prefix; + u8 rep_prefix; +/* bitmaps of registers in _regs[] that can be read */ + u32 regs_valid; +/* bitmaps of registers in _regs[] that have been written */ + u32 regs_dirty; + ); +/* modrm */ u8 modrm;u8 modrm_mod;
Signature · 1 line
2.30.2
PATCH 51/64 tracing: Use struct_group() to zero struct trace_iterator
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct trace_iterator that should be initialized to zero.
--- include/linux/trace_events.h | 26 ++++++++++++++------------ kernel/trace/trace.c | 4 +--- 2 files changed, 15 insertions(+), 15 deletions(-)
include/linux/trace_events.h +14 -12
@@ -101,18 +101,20 @@ struct trace_iterator {bool snapshot;/* The below is zeroed out in pipe_read */ -struct trace_seq seq; -struct trace_entry *ent; -unsigned long lost_events; -int leftover; -int ent_size; -int cpu; -u64 ts; - -loff_t pos; -long idx; - -/* All new field here will be zeroed out in pipe_read */ +struct_group (init, + struct trace_seq seq; + struct trace_entry *ent; +unsigned long lost_events; +int leftover; +int ent_size; +int cpu; +u64 ts; + +loff_t pos; +long idx; + +/* All new field here will be zeroed out in pipe_read */ + ); };enum trace_iter_flags {
kernel/trace/trace.c +1 -3
@@ -6691,9 +6691,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, cnt =PAGE_SIZE -1 ;/* reset all but tr, trace, and overruns */ -memset (&iter->seq,0 , -sizeof (struct trace_iterator ) - - offsetof(struct trace_iterator , seq)); +memset (&iter->init,0 ,sizeof (iter->init));cpumask_clear (iter->started);trace_seq_init (&iter->seq); iter->pos =-1 ;
Signature · 1 line
2.30.2
PATCH 52/64 dm integrity: Use struct_group() to zero struct journal_sector
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct journal_sector that should be initialized to zero.
--- drivers/md/dm-integrity.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/md/dm-integrity.c +6 -3
@@ -119,8 +119,10 @@ struct journal_entry {#define JOURNAL_MAC_SIZE (JOURNAL_MAC_PER_SECTOR * JOURNAL_BLOCK_SECTORS)struct journal_sector { -__u8 entries[JOURNAL_SECTOR_DATA -JOURNAL_MAC_PER_SECTOR ]; -__u8 mac[JOURNAL_MAC_PER_SECTOR ]; + struct_group(sectors, + __u8 entries[JOURNAL_SECTOR_DATA - JOURNAL_MAC_PER_SECTOR]; +__u8 mac[JOURNAL_MAC_PER_SECTOR ]; + );commit_id_t commit_id; };
@@ -2856,7 +2858,8 @@ static void init_journal(struct dm_integrity_c *ic, unsigned start_section,wraparound_section (ic, &i);for (j =0 ; j < ic->journal_section_sectors; j++) {struct journal_sector *js =access_journal (ic, i, j); -memset (&js->entries,0 ,JOURNAL_SECTOR_DATA ); +BUILD_BUG_ON (sizeof (js->sectors) !=JOURNAL_SECTOR_DATA ); +memset (&js->sectors,0 ,sizeof (js->sectors)); js->commit_id =dm_integrity_commit_id (ic, i, j, commit_seq); }for (j =0 ; j < ic->journal_section_entries; j++) {
Signature · 1 line
2.30.2
PATCH 53/64 HID: roccat: Use struct_group() to zero kone_mouse_event
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct kone_mouse_event that should be initialized to zero.
--- drivers/hid/hid-roccat-kone.c | 2 +- drivers/hid/hid-roccat-kone.h | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-)
drivers/hid/hid-roccat-kone.c +1 -1
@@ -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);
drivers/hid/hid-roccat-kone.h +7 -5
@@ -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 {
Signature · 1 line
2.30.2
PATCH 54/64 ipv6: Use struct_group() to zero rt6_info
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct rt6_info that should be initialized to zero.
--- include/net/ip6_fib.h | 30 ++++++++++++++++-------------- net/ipv6/route.c | 4 +--- 2 files changed, 17 insertions(+), 17 deletions(-)
include/net/ip6_fib.h +16 -14
@@ -205,20 +205,22 @@ struct fib6_info {struct rt6_info {struct dst_entry dst; -struct fib6_info __rcu *from; -int sernum; - -struct rt6key rt6i_dst; -struct rt6key rt6i_src; -struct in6_addr rt6i_gateway; -struct inet6_dev *rt6i_idev; -u32 rt6i_flags; - -struct list_head rt6i_uncached; -struct uncached_list *rt6i_uncached_list; - -/* more non-fragment space at head required */ -unsigned short rt6i_nfheader_len; + struct_group(init, + struct fib6_info __rcu *from; +int sernum; + +struct rt6key rt6i_dst; +struct rt6key rt6i_src; +struct in6_addr rt6i_gateway; +struct inet6_dev *rt6i_idev; +u32 rt6i_flags; + +struct list_head rt6i_uncached; +struct uncached_list *rt6i_uncached_list; + +/* more non-fragment space at head required */ +unsigned short rt6i_nfheader_len; + ); };struct fib6_result {
net/ipv6/route.c +1 -3
@@ -327,9 +327,7 @@ static const struct rt6_info ip6_blk_hole_entry_template = {static void rt6_info_init (struct rt6_info *rt) { -struct dst_entry *dst = &rt->dst; - -memset (dst +1 ,0 ,sizeof (*rt) -sizeof (*dst)); +memset (&rt->init,0 ,sizeof (rt->init));INIT_LIST_HEAD (&rt->rt6i_uncached); }
Signature · 1 line
2.30.2
Jakub Kicinski
maintainerRe: [PATCH 54/64] ipv6: Use struct_group() to zero rt6_info
Quoted 6 lines · On Tue, 27 Jul 2021 13:58:45 -0700 Kees Cook wrote:
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add
struct_group()to mark region of structrt6_infothat should be initialized to zero.
memset_after() ?
Quoted 56 lines
include/net/ip6_fib.h +16
-14@@ -205,20 +205,22 @@ struct fib6_info {struct rt6_info {struct dst_entry dst; -struct fib6_info __rcu *from; -int sernum; - -struct rt6key rt6i_dst; -struct rt6key rt6i_src; -struct in6_addr rt6i_gateway; -struct inet6_dev *rt6i_idev; -u32 rt6i_flags; - -struct list_head rt6i_uncached; -struct uncached_list *rt6i_uncached_list; - -/* more non-fragment space at head required */ -unsigned short rt6i_nfheader_len; + struct_group(init, + struct fib6_info __rcu *from; +int sernum; + +struct rt6key rt6i_dst; +struct rt6key rt6i_src; +struct in6_addr rt6i_gateway; +struct inet6_dev *rt6i_idev; +u32 rt6i_flags; + +struct list_head rt6i_uncached; +struct uncached_list *rt6i_uncached_list; + +/* more non-fragment space at head required */ +unsigned short rt6i_nfheader_len; + ); };struct fib6_result {net/ipv6/route.c +1
-3@@ -327,9 +327,7 @@ static const struct rt6_info ip6_blk_hole_entry_template = {static void rt6_info_init (struct rt6_info *rt) { -struct dst_entry *dst = &rt->dst; - -memset (dst +1 ,0 ,sizeof (*rt) -sizeof (*dst)); +memset (&rt->init,0 ,sizeof (rt->init));INIT_LIST_HEAD (&rt->rt6i_uncached); }
Re: [PATCH 54/64] ipv6: Use struct_group() to zero rt6_info
Quoted 9 lines · Jakub Kicinski
Quoted 6 lines · On Tue, 27 Jul 2021 13:58:45 -0700 Kees Cook wrote:
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Add
struct_group()to mark region of structrt6_infothat should be initialized to zero.
memset_after()?
Oh, hah. Yes. I will adjust for v2.
Signature · 1 line
Kees Cook
PATCH 55/64 RDMA/mlx5: Use struct_group() to zero struct mlx5_ib_mr
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct mlx5_ib_mr that should be initialized to zero.
--- drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/mlx5_ib.h +3 -1
@@ -644,6 +644,7 @@ struct mlx5_ib_mr {struct ib_umem *umem;/* This is zero'd when the MR is allocated */ + struct_group(cleared, union { /* Used only while the MR is in the cache */ struct {
@@ -691,12 +692,13 @@ struct mlx5_ib_mr {bool is_odp_implicit; }; }; + ); };/* Zero the fields in the mr that are variant depending on usage */ static inline void mlx5_clear_mr (struct mlx5_ib_mr *mr) { -memset (mr->out,0 ,sizeof (*mr) - offsetof(struct mlx5_ib_mr , out)); +memset (&mr->cleared,0 ,sizeof (mr->cleared)); }static inline bool is_odp_mr (struct mlx5_ib_mr *mr)
Signature · 1 line
2.30.2
PATCH 56/64 ethtool: stats: Use struct_group() to clear all stats at once
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Add struct_group() to mark region of struct stats_reply_data that should be initialized, which can now be done in a single memset() call.
--- net/ethtool/stats.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
net/ethtool/stats.c +7 -8
@@ -14,10 +14,12 @@ struct stats_req_info {struct stats_reply_data {struct ethnl_reply_data base; -struct ethtool_eth_phy_stats phy_stats; -struct ethtool_eth_mac_stats mac_stats; -struct ethtool_eth_ctrl_stats ctrl_stats; -struct ethtool_rmon_stats rmon_stats; + struct_group(stats, + struct ethtool_eth_phy_stats phy_stats; +struct ethtool_eth_mac_stats mac_stats; +struct ethtool_eth_ctrl_stats ctrl_stats; +struct ethtool_rmon_stats rmon_stats; + );const struct ethtool_rmon_hist_range *rmon_ranges; };
@@ -117,10 +119,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,/* Mark all stats as unset (see ETHTOOL_STAT_NOT_SET) to prevent them * from being reported to user space in case driver did not set them. */ -memset (&data->phy_stats,0xff ,sizeof (data->phy_stats)); -memset (&data->mac_stats,0xff ,sizeof (data->mac_stats)); -memset (&data->ctrl_stats,0xff ,sizeof (data->ctrl_stats)); -memset (&data->rmon_stats,0xff ,sizeof (data->rmon_stats)); +memset (&data->stats,0xff ,sizeof (data->stats));if (test_bit (ETHTOOL_STATS_ETH_PHY , req_info->stat_mask) && dev->ethtool_ops->get_eth_phy_stats)
Signature · 1 line
2.30.2
PATCH 57/64 netfilter: conntrack: Use struct_group() to zero struct nf_conn
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Replace the empty __nfct_init_offset member with a struct_group() to mark the region of struct nf_conn that should be initialized to zero, allowing memset() to correctly reason about the size of the write.
--- include/net/netfilter/nf_conntrack.h | 20 ++++++++++---------- net/netfilter/nf_conntrack_core.c | 4 +--- 2 files changed, 11 insertions(+), 13 deletions(-)
include/net/netfilter/nf_conntrack.h +10 -10
@@ -101,24 +101,24 @@ struct nf_conn {struct hlist_node nat_bysource;#endif /* all members below initialized via memset */ -struct { } __nfct_init_offset; - -/* If we were expected by an expectation, this will be it */ -struct nf_conn *master; +struct_group (init, +/* If we were expected by an expectation, this will be it */ + struct nf_conn *master;#if defined(CONFIG_NF_CONNTRACK_MARK ) -u_int32_t mark; +u_int32_t mark;#endif #ifdef CONFIG_NF_CONNTRACK_SECMARK -u_int32_t secmark; +u_int32_t secmark;#endif -/* Extensions */ -struct nf_ct_ext *ext; +/* Extensions */ +struct nf_ct_ext *ext; -/* Storage reserved for other modules, must be the last member */ -union nf_conntrack_proto proto; +/* Storage reserved for other modules, must be the last member */ +union nf_conntrack_proto proto; + ); }; static inline struct nf_conn *
net/netfilter/nf_conntrack_core.c +1 -3
@@ -1527,9 +1527,7 @@ __nf_conntrack_alloc(struct net *net, ct->status =0 ; ct->timeout =0 ;write_pnet (&ct->ct_net, net); -memset (&ct->__nfct_init_offset,0 , - offsetof(struct nf_conn , proto) - - offsetof(struct nf_conn , __nfct_init_offset)); +memset (&ct->init,0 ,sizeof (ct->init));nf_ct_zone_add (ct, zone);
Signature · 1 line
2.30.2
PATCH 58/64 powerpc: Split memset() to avoid multi-field overflow
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields.
Instead of writing across a field boundary with memset(), move the call to just the array, and an explicit zeroing of the prior field.
--- drivers/macintosh/smu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/macintosh/smu.c +2 -1
@@ -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 ,3 );break ;case SMU_I2C_TRANSFER_COMBINED : cmd->info.devaddr &=0xfe ;
Signature · 1 line
2.30.2
Re: [PATCH 58/64] powerpc: Split memset() to avoid multi-field overflow
Quoted 28 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemset(), avoid intentionally writing across neighboring fields.Instead of writing across a field boundary with
memset(), move the call to just the array, and an explicit zeroing of the prior field.Signed-off-by Kees Cook <[email protected]>--- drivers/macintosh/smu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)drivers/macintosh/smu.c +2
-1@@ -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 ,3 );break ;case SMU_I2C_TRANSFER_COMBINED : cmd->info.devaddr &=0xfe ;Signature · 1 line
2.30.2
cheers
PATCH 59/64 fortify: Detect struct member overflows in memset() at compile-time
In reply to Kees CookAs done for memcpy(), also update memset() to use the same tightened compile-time bounds checking under CONFIG_FORTIFY_SOURCE.
--- include/linux/fortify-string.h | 54 ++++++++++++++++--- .../write_overflow_field-memset.c | 5 ++ 2 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 lib/test_fortify/write_overflow_field-memset.c
include/linux/fortify-string.h +46 -8
@@ -175,17 +175,56 @@ __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count)return p; } -__FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size) +__FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size, +const size_t p_size, +const size_t p_size_field) { -size_t p_size =__builtin_object_size (p,0 ); +if (__builtin_constant_p (size)) { +/* +* Length argument is a constant expression, so we +* can perform compile-time bounds checking where +* buffer sizes are known. +*/ -if (__builtin_constant_p (size) && p_size < size) -__write_overflow (); -if (p_size < size) -fortify_panic (__func__); -return __underlying_memset (p, c, size); +/* Error when size is larger than enclosing struct. */ +if (p_size > p_size_field && p_size < size) +__write_overflow (); + +/* Warn when write size is larger than dest field. */ +if (p_size_field < size) +__write_overflow_field (); + } +/* +* At this point, length argument may not be a constant expression, +* so run-time bounds checking can be done where buffer sizes are +* known. (This is not an "else" because the above checks may only +* be compile-time warnings, and we want to still warn for run-time +* overflows.) +*/ + +/* +* Always stop accesses beyond the struct that contains the +* field, when the buffer's remaining size is known. +* (The -1 test is to optimize away checks where the buffer +* lengths are unknown.) +*/ +if (p_size != (size_t )(-1 ) && p_size < size) +fortify_panic ("memset" ); } +#define __fortify_memset_chk (p, c, size, p_size, p_size_field) ({ \ + size_t __fortify_size = (size_t)(size); \ + fortify_memset_chk(__fortify_size, p_size, p_size_field), \ + __underlying_memset(p, c, __fortify_size); \ +}) + +/* +* __builtin_object_size() must be captured here to avoid evaluating argument +* side-effects further into the macro layers. +*/ +#define memset (p, c, s) __fortify_memset_chk(p, c, s, \ + __builtin_object_size(p, 0), __builtin_object_size(p, 1)) +/* * To make sure the compiler can enforce protection against buffer overflows, * memcpy(), memmove(), and memset() must not be used beyond individual
@@ -373,7 +412,6 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q)/* Don't use these outside the FORITFY_SOURCE implementation */ #undef __underlying_memchr#undef __underlying_memcmp -#undef __underlying_memset#undef __underlying_strcat#undef __underlying_strcpy#undef __underlying_strlen
lib/test_fortify/write_overflow_field-memset.c new file +5 -0
@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define TEST \ + memset(instance.buf, 0x42, sizeof(instance.buf) + 1) + +#include "test_fortify.h"
Signature · 1 line
2.30.2
kernel test robot
build botRe: [PATCH 59/64] fortify: Detect struct member overflows in memset() at compile-time
I love your patch! Yet something to improve:
Hi Kees,
I love your patch! Yet something to improve:
[auto build test ERROR on staging/staging-testing]
[also build test ERROR on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210727] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: powerpc64-buildonly-randconfig-r002-20210726 (attached as .config) compiler: powerpc-linux-gcc (GCC) 10.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/d6aff26cc627e1579f89ebaaa51365cabd5c7ee3
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout d6aff26cc627e1579f89ebaaa51365cabd5c7ee3
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-10.3.0 make.cross ARCH=powerpc64
If you fix the issue, kindly add following tag as appropriate
All errors (new ones prefixed by >>):
In file included from include/linux/string.h:253,
from include/linux/bitmap.h:10,
from include/linux/cpumask.h:12,
from include/linux/smp.h:13,
from include/linux/lockdep.h:14,
from include/linux/rcupdate.h:29,
from include/linux/rculist.h:11,
from include/linux/pid.h:5,
from include/linux/sched.h:14,
from arch/powerpc/kernel/signal_32.c:16:
In function 'fortify_memset_chk',
inlined from 'restore_user_regs.part.0' at arch/powerpc/kernel/signal_32.c:539:3:
>> include/linux/fortify-string.h:195:4: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning]
195 | __write_overflow_field();
| ^~~~~~~~~~~~~~~~~~~~~~~~cc1: all warnings being treated as errors
vim +/__write_overflow_field +195 include/linux/fortify-string.h
177
178 __FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size,
179 const size_t p_size,
180 const size_t p_size_field)
181 {
182 if (__builtin_constant_p(size)) {
183 /*
184 * Length argument is a constant expression, so we
185 * can perform compile-time bounds checking where
186 * buffer sizes are known.
187 */
188
189 /* Error when size is larger than enclosing struct. */
190 if (p_size > p_size_field && p_size < size)
191 __write_overflow();
192
193 /* Warn when write size is larger than dest field. */
194 if (p_size_field < size)
> 195 __write_overflow_field();
196 }
197 /*
198 * At this point, length argument may not be a constant expression,
199 * so run-time bounds checking can be done where buffer sizes are
200 * known. (This is not an "else" because the above checks may only
201 * be compile-time warnings, and we want to still warn for run-time
202 * overflows.)
203 */
204
205 /*
206 * Always stop accesses beyond the struct that contains the
207 * field, when the buffer's remaining size is known.
208 * (The -1 test is to optimize away checks where the buffer
209 * lengths are unknown.)
210 */
211 if (p_size != (size_t)(-1) && p_size < size)
212 fortify_panic("memset");
213 }
214
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]
kernel test robot
build botRe: [PATCH 59/64] fortify: Detect struct member overflows in memset() at compile-time
In reply to Kees CookI love your patch! Perhaps something to improve:
Hi Kees,
I love your patch! Perhaps something to improve:
[auto build test WARNING on staging/staging-testing]
[also build test WARNING on linus/master v5.14-rc3]
[cannot apply to wireless-drivers-next/master wireless-drivers/master next-20210727] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 39f9137268ee3df0047706df4e9b7357a40ffc98 config: x86_64-randconfig-s022-20210728 (attached as .config) compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-341-g8af24329-dirty # https://github.com/0day-ci/linux/commit/d6aff26cc627e1579f89ebaaa51365cabd5c7ee3 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Kees-Cook/Introduce-strict-memcpy-bounds-checking/20210728-053749 git checkout d6aff26cc627e1579f89ebaaa51365cabd5c7ee3 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem * @@ drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: expected void const * drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: got unsigned char [noderef] [usertype] __iomem * >> drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const * @@ got unsigned char [noderef] [usertype] __iomem * @@ drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: expected void const * drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: got unsigned char [noderef] [usertype] __iomem * >> drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void * @@ got unsigned char [noderef] [usertype] __iomem * @@
drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: expected void *
drivers/gpu/drm/gma500/framebuffer.c:293:9: sparse: got unsigned char [noderef] [usertype] __iomem *
vim +293 drivers/gpu/drm/gma500/framebuffer.c
4d8d096e9ae866 Alan Cox 2011-11-03 252
4d8d096e9ae866 Alan Cox 2011-11-03 253 /**
4d8d096e9ae866 Alan Cox 2011-11-03 254 * psbfb_create - create a framebuffer
358794a29a5fe3 Lee Jones 2021-01-15 255 * @fb_helper: the framebuffer helper
4d8d096e9ae866 Alan Cox 2011-11-03 256 * @sizes: specification of the layout
4d8d096e9ae866 Alan Cox 2011-11-03 257 *
4d8d096e9ae866 Alan Cox 2011-11-03 258 * Create a framebuffer to the specifications provided
4d8d096e9ae866 Alan Cox 2011-11-03 259 */
6b7ce2c4161a00 Thomas Zimmermann 2019-11-22 260 static int psbfb_create(struct drm_fb_helper *fb_helper,
4d8d096e9ae866 Alan Cox 2011-11-03 261 struct drm_fb_helper_surface_size *sizes)
4d8d096e9ae866 Alan Cox 2011-11-03 262 {
6b7ce2c4161a00 Thomas Zimmermann 2019-11-22 263 struct drm_device *dev = fb_helper->dev;
4d8d096e9ae866 Alan Cox 2011-11-03 264 struct drm_psb_private *dev_priv = dev->dev_private;
a2c68495b57986 Thomas Zimmermann 2020-12-01 265 struct pci_dev *pdev = to_pci_dev(dev->dev);
4d8d096e9ae866 Alan Cox 2011-11-03 266 struct fb_info *info;
0a8ec2ed0783eb Thomas Zimmermann 2019-11-22 267 struct drm_framebuffer *fb;
a9a644ac9e8d6c Dave Airlie 2011-11-28 268 struct drm_mode_fb_cmd2 mode_cmd;
4d8d096e9ae866 Alan Cox 2011-11-03 269 int size;
4d8d096e9ae866 Alan Cox 2011-11-03 270 int ret;
4d8d096e9ae866 Alan Cox 2011-11-03 271 struct gtt_range *backing;
a9a644ac9e8d6c Dave Airlie 2011-11-28 272 u32 bpp, depth;
4d8d096e9ae866 Alan Cox 2011-11-03 273
4d8d096e9ae866 Alan Cox 2011-11-03 274 mode_cmd.width = sizes->surface_width;
4d8d096e9ae866 Alan Cox 2011-11-03 275 mode_cmd.height = sizes->surface_height;
a9a644ac9e8d6c Dave Airlie 2011-11-28 276 bpp = sizes->surface_bpp;
6aa1ead1b85581 Kirill A. Shutemov 2012-03-08 277 depth = sizes->surface_depth;
4d8d096e9ae866 Alan Cox 2011-11-03 278
4d8d096e9ae866 Alan Cox 2011-11-03 279 /* No 24bit packed */
a9a644ac9e8d6c Dave Airlie 2011-11-28 280 if (bpp == 24)
a9a644ac9e8d6c Dave Airlie 2011-11-28 281 bpp = 32;
4d8d096e9ae866 Alan Cox 2011-11-03 282
ebc7d6470ac4b5 Patrik Jakobsson 2020-10-28 283 mode_cmd.pitches[0] = ALIGN(mode_cmd.width * DIV_ROUND_UP(bpp, 8), 64);
a6ba582d264f67 Alan Cox 2011-11-29 284
a6ba582d264f67 Alan Cox 2011-11-29 285 size = mode_cmd.pitches[0] * mode_cmd.height;
a6ba582d264f67 Alan Cox 2011-11-29 286 size = ALIGN(size, PAGE_SIZE);
a6ba582d264f67 Alan Cox 2011-11-29 287
4d8d096e9ae866 Alan Cox 2011-11-03 288 /* Allocate the framebuffer in the GTT with stolen page backing */
4d8d096e9ae866 Alan Cox 2011-11-03 289 backing = psbfb_alloc(dev, size);
4d8d096e9ae866 Alan Cox 2011-11-03 290 if (backing == NULL)
4d8d096e9ae866 Alan Cox 2011-11-03 291 return -ENOMEM;
4d8d096e9ae866 Alan Cox 2011-11-03 292
bb84977941ad85 Alan Cox 2012-05-03 @293 memset(dev_priv->vram_addr + backing->offset, 0, size);
bb84977941ad85 Alan Cox 2012-05-03 294
6b7ce2c4161a00 Thomas Zimmermann 2019-11-22 295 info = drm_fb_helper_alloc_fbi(fb_helper);
546187c85d4d4e Archit Taneja 2015-07-22 296 if (IS_ERR(info)) {
546187c85d4d4e Archit Taneja 2015-07-22 297 ret = PTR_ERR(info);
da7bdda2afdf1a Daniel Vetter 2017-02-07 298 goto out;
4d8d096e9ae866 Alan Cox 2011-11-03 299 }
4d8d096e9ae866 Alan Cox 2011-11-03 300
a9a644ac9e8d6c Dave Airlie 2011-11-28 301 mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
a9a644ac9e8d6c Dave Airlie 2011-11-28 302
0a8ec2ed0783eb Thomas Zimmermann 2019-11-22 303 fb = psb_framebuffer_create(dev, &mode_cmd, &backing->gem);
0a8ec2ed0783eb Thomas Zimmermann 2019-11-22 304 if (IS_ERR(fb)) {
0a8ec2ed0783eb Thomas Zimmermann 2019-11-22 305 ret = PTR_ERR(fb);
da7bdda2afdf1a Daniel Vetter 2017-02-07 306 goto out;
0a8ec2ed0783eb Thomas Zimmermann 2019-11-22 307 }
4d8d096e9ae866 Alan Cox 2011-11-03 308
6b7ce2c4161a00 Thomas Zimmermann 2019-11-22 309 fb_helper->fb = fb;
4d8d096e9ae866 Alan Cox 2011-11-03 310
a6ba582d264f67 Alan Cox 2011-11-29 311 info->fbops = &psbfb_unaccel_ops;
4d8d096e9ae866 Alan Cox 2011-11-03 312
4d8d096e9ae866 Alan Cox 2011-11-03 313 info->fix.smem_start = dev->mode_config.fb_base;
4d8d096e9ae866 Alan Cox 2011-11-03 314 info->fix.smem_len = size;
ebc7d6470ac4b5 Patrik Jakobsson 2020-10-28 315 info->fix.ywrapstep = 0;
a6ba582d264f67 Alan Cox 2011-11-29 316 info->fix.ypanstep = 0;
4d8d096e9ae866 Alan Cox 2011-11-03 317
4d8d096e9ae866 Alan Cox 2011-11-03 318 /* Accessed stolen memory directly */
37214ca00e6474 Kirill A. Shutemov 2012-05-03 319 info->screen_base = dev_priv->vram_addr + backing->offset;
4d8d096e9ae866 Alan Cox 2011-11-03 320 info->screen_size = size;
4d8d096e9ae866 Alan Cox 2011-11-03 321
4d8d096e9ae866 Alan Cox 2011-11-03 322 if (dev_priv->gtt.stolen_size) {
4d8d096e9ae866 Alan Cox 2011-11-03 323 info->apertures->ranges[0].base = dev->mode_config.fb_base;
4d8d096e9ae866 Alan Cox 2011-11-03 324 info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
4d8d096e9ae866 Alan Cox 2011-11-03 325 }
4d8d096e9ae866 Alan Cox 2011-11-03 326
6b7ce2c4161a00 Thomas Zimmermann 2019-11-22 327 drm_fb_helper_fill_info(info, fb_helper, sizes);
4d8d096e9ae866 Alan Cox 2011-11-03 328
a2c68495b57986 Thomas Zimmermann 2020-12-01 329 info->fix.mmio_start = pci_resource_start(pdev, 0);
a2c68495b57986 Thomas Zimmermann 2020-12-01 330 info->fix.mmio_len = pci_resource_len(pdev, 0);
4d8d096e9ae866 Alan Cox 2011-11-03 331
fb2a99e15ff0d3 Sascha Hauer 2012-02-06 332 /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
4d8d096e9ae866 Alan Cox 2011-11-03 333
e18da8ce7d730b Thomas Zimmermann 2019-11-22 334 dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height);
4d8d096e9ae866 Alan Cox 2011-11-03 335
4d8d096e9ae866 Alan Cox 2011-11-03 336 return 0;
da7bdda2afdf1a Daniel Vetter 2017-02-07 337 out:
4d8d096e9ae866 Alan Cox 2011-11-03 338 psb_gtt_free_range(dev, backing);
4d8d096e9ae866 Alan Cox 2011-11-03 339 return ret;
4d8d096e9ae866 Alan Cox 2011-11-03 340 }
4d8d096e9ae866 Alan Cox 2011-11-03 341 ---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH 60/64 fortify: Work around Clang inlining bugs
In reply to Kees CookTo enable FORTIFY_SOURCE support for Clang, the kernel must work around a pair of bugs, related to Clang's inlining.
Change all the fortified APIs into macros with different inline names to bypass Clang's broken inline-of-a-builtin detection:
https://bugs.llvm.org/show_bug.cgi?id=50322
Lift all misbehaving __builtin_object_size() calls into the macros to bypass Clang's broken __builtin_object_size() arguments-of-an-inline visibility:
https://github.com/ClangBuiltLinux/linux/issues/1401
Thankfully, due to how the inlining already behaves in GCC, this change has no effect on GCC builds, but allows Clang to finally gain full FORTIFY coverage.
However, because of a third bug which had no work-arounds, FORTIFY_SOURCE will only work with Clang version 13 and later. Update the Kconfig to reflect the new requirements.
--- include/linux/fortify-string.h | 33 +++++++++++++++++++++------------ security/Kconfig | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-)
include/linux/fortify-string.h +21 -12
@@ -38,10 +38,11 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size)#define __underlying_strncpy __builtin_strncpy#endif -__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) +#define strncpy (p, q, s) __fortify_strncpy(p, q, s, __builtin_object_size(p, 1)) +__FORTIFY_INLINE char *__fortify_strncpy(char *p, const char *q, +__kernel_size_t size, +const size_t p_size) { -size_t p_size =__builtin_object_size (p,1 ); -if (__builtin_constant_p (size) && p_size < size)__write_overflow ();if (p_size < size)
@@ -112,12 +113,15 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)/* defined after fortified strnlen to reuse it */ extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy); -__FORTIFY_INLINE ssize_t strscpy(char *p, const char *q, size_t size) +#define strscpy(p, q, s) __fortify_strscpy(p, q, s, \ +__builtin_object_size (p,1 ), \ +__builtin_object_size (q,1 )) +__FORTIFY_INLINE ssize_t __fortify_strscpy(char *p, const char *q, + size_t size, + const size_t p_size, + const size_t q_size) {size_t len; -/* Use string size rather than possible enclosing struct size. */ -size_t p_size =__builtin_object_size (p,1 ); -size_t q_size =__builtin_object_size (q,1 );/* If we cannot get size of p and q default to call strscpy. */ if (p_size == (size_t )-1 && q_size == (size_t )-1 )
@@ -329,7 +333,8 @@ __FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t size, memmove) extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan); -__FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size) +#define memscan (p, c, s) __fortify_memscan(p, c, s) +__FORTIFY_INLINE void *__fortify_memscan(void *p, int c, __kernel_size_t size) {size_t p_size =__builtin_object_size (p,0 );
@@ -340,7 +345,8 @@ __FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size)return __real_memscan (p, c, size); } -__FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size) +#define memcmp (p, q, s) __fortify_memcmp(p, q, s) +__FORTIFY_INLINE int __fortify_memcmp(const void *p, const void *q, __kernel_size_t size) {size_t p_size =__builtin_object_size (p,0 );size_t q_size =__builtin_object_size (q,0 );
@@ -356,7 +362,8 @@ __FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size)return __underlying_memcmp (p, q, size); } -__FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size) +#define memchr (p, c, s) __fortify_memchr(p, c, s) +__FORTIFY_INLINE void *__fortify_memchr(const void *p, int c, __kernel_size_t size) {size_t p_size =__builtin_object_size (p,0 );
@@ -368,7 +375,8 @@ __FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size) }void *__real_memchr_inv (const void *s,int c,size_t n)__RENAME (memchr_inv); -__FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size) +#define memchr_inv (p, c, s) __fortify_memchr_inv(p, c, s) +__FORTIFY_INLINE void *__fortify_memchr_inv(const void *p, int c, size_t size) {size_t p_size =__builtin_object_size (p,0 );
@@ -392,7 +400,8 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp) }/* Defined after fortified strlen to reuse it. */ -__FORTIFY_INLINE char *strcpy(char *p, const char *q) +#define strcpy (p, q) __fortify_strcpy(p, q) +__FORTIFY_INLINE char *__fortify_strcpy(char *p, const char *q) {size_t p_size =__builtin_object_size (p,1 );size_t q_size =__builtin_object_size (q,1 );
security/Kconfig +1 -1
@@ -193,7 +193,7 @@ config FORTIFY_SOURCE 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 !CONFIG_CC_IS_CLANG + depends on !CONFIG_CC_IS_CLANG || CLANG_VERSION >= 130000 help Detect overflows of buffers in common string and memory functions where the compiler can determine and validate the buffer sizes.
Signature · 1 line
2.30.2
PATCH 61/64 Makefile: Enable -Warray-bounds
In reply to Kees CookWith the recent fixes for flexible arrays and expanded FORTIFY_SOURCE coverage, it is now possible to enable -Warray-bounds. Since both GCC and Clang include -Warray-bounds in -Wall, we just need to stop disabling it.
--- Makefile | 1 - 1 file changed, 1 deletion(-)
Makefile +0 -1
@@ -1089,7 +1089,6 @@ KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation) # We'll want to enable this eventually, but it's not going away for 5.7 at least KBUILD_CFLAGS += $(call cc-disable-warning, zero-length-bounds) -KBUILD_CFLAGS += $(call cc-disable-warning, array-bounds) KBUILD_CFLAGS += $(call cc-disable-warning, stringop-overflow) # Another good warning that we'll want to enable eventually
Signature · 1 line
2.30.2
PATCH 62/64 netlink: Avoid false-positive memcpy() warning
In reply to Kees CookIn preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields.
Add a flexible array member to mark the end of struct nlmsghdr, and split the memcpy() to avoid false positive memcpy() warning:
memcpy: detected field-spanning write (size 32) of single field (size 16)
--- include/uapi/linux/netlink.h | 1 + net/netlink/af_netlink.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
include/uapi/linux/netlink.h +1 -0
@@ -47,6 +47,7 @@ struct nlmsghdr {__u16 nlmsg_flags;/* Additional flags */ __u32 nlmsg_seq;/* Sequence number */ __u32 nlmsg_pid;/* Sending process port ID */ +__u8 contents[]; };/* Flags values */
net/netlink/af_netlink.c +3 -1
@@ -2447,7 +2447,9 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err, NLMSG_ERROR, payload, flags); errmsg =nlmsg_data (rep); errmsg->error = err; -memcpy (&errmsg->msg, nlh, payload >sizeof (*errmsg) ? nlh->nlmsg_len :sizeof (*nlh)); +memcpy (&errmsg->msg, nlh,sizeof (*nlh)); +if (payload >sizeof (*errmsg)) +memcpy (errmsg->msg.contents, nlh->contents, nlh->nlmsg_len -sizeof (*nlh));if (nlk_has_extack && extack) {if (extack->_msg) {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerRe: [PATCH 62/64] netlink: Avoid false-positive memcpy() warning
Quoted 20 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Add a flexible array member to mark the end of struct nlmsghdr, and split the
memcpy()to avoid false positivememcpy()warning:memcpy: detected field-spanning write (size 32) of single field (size 16)
Signed-off-by Kees Cook <[email protected]>--- include/uapi/linux/netlink.h | 1 + net/netlink/af_netlink.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)include/uapi/linux/netlink.h +0
-0
include/uapi/linux/netlink.h struct nlmsghdr { · line 50
Quoted 4 lines
include/uapi/linux/netlink.h +1
-0@@ -47,6 +47,7 @@ struct nlmsghdr {__u16 nlmsg_flags;/* Additional flags */ __u32 nlmsg_seq;/* Sequence number */ __u32 nlmsg_pid;/* Sending process port ID */ +__u8 contents[];
Is this ok to change a public, userspace visable, structure?
Nothing breaks?
thanks,
greg k-h
Re: [PATCH 62/64] netlink: Avoid false-positive memcpy() warning
Quoted 16 lines · Greg Kroah-Hartman
Quoted 15 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Add a flexible array member to mark the end of struct nlmsghdr, and split the
memcpy()to avoid false positivememcpy()warning:memcpy: detected field-spanning write (size 32) of single field (size 16)
Signed-off-by Kees Cook <[email protected]>--- include/uapi/linux/netlink.h | 1 + net/netlink/af_netlink.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
Quoted 11 lines
include/uapi/linux/netlink.h struct nlmsghdr { · line 50
Quoted 9 lines
include/uapi/linux/netlink.h +1
-0@@ -47,6 +47,7 @@ struct nlmsghdr {__u16 nlmsg_flags;/* Additional flags */ __u32 nlmsg_seq;/* Sequence number */ __u32 nlmsg_pid;/* Sending process port ID */ +__u8 contents[];Is this ok to change a public, userspace visable, structure?
At least it should keep using a nlmsg_ prefix for consistency and reduce risk of collision with somebody having defined an object-like contents macro. But there's no guarantees in any case, of course.
Rasmus
Re: [PATCH 62/64] netlink: Avoid false-positive memcpy() warning
Quoted 29 lines · Rasmus Villemoes
Quoted 16 lines · Greg Kroah-Hartman
Quoted 15 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Add a flexible array member to mark the end of struct nlmsghdr, and split the
memcpy()to avoid false positivememcpy()warning:memcpy: detected field-spanning write (size 32) of single field (size 16)
Signed-off-by Kees Cook <[email protected]>--- include/uapi/linux/netlink.h | 1 + net/netlink/af_netlink.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)Quoted 11 lines
include/uapi/linux/netlink.h struct nlmsghdr { · line 50
Quoted 9 lines
include/uapi/linux/netlink.h +1
-0@@ -47,6 +47,7 @@ struct nlmsghdr {__u16 nlmsg_flags;/* Additional flags */ __u32 nlmsg_seq;/* Sequence number */ __u32 nlmsg_pid;/* Sending process port ID */ +__u8 contents[];Is this ok to change a public, userspace visable, structure?
Quoted 3 lines
At least it should keep using a
nlmsg_prefix for consistency and reduce risk of collision with somebody having defined an object-like contents macro. But there's no guarantees in any case, of course.
Ah, good call. I've adjusted this and added a comment.
Thanks!
-Kees
Signature · 1 line
Kees Cook
Re: [PATCH 62/64] netlink: Avoid false-positive memcpy() warning
In reply to Greg Kroah-HartmanQuoted 28 lines · Greg Kroah-Hartman
Quoted 20 lines · Kees Cook
In preparation for
FORTIFY_SOURCEperforming compile-time and run-time field bounds checking formemcpy(),memmove(), andmemset(), avoid intentionally writing across neighboring fields.Add a flexible array member to mark the end of struct nlmsghdr, and split the
memcpy()to avoid false positivememcpy()warning:memcpy: detected field-spanning write (size 32) of single field (size 16)
Signed-off-by Kees Cook <[email protected]>--- include/uapi/linux/netlink.h | 1 + net/netlink/af_netlink.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)include/uapi/linux/netlink.h +0
-0include/uapi/linux/netlink.h struct nlmsghdr { · line 50
Quoted 4 lines
include/uapi/linux/netlink.h +1
-0@@ -47,6 +47,7 @@ struct nlmsghdr {__u16 nlmsg_flags;/* Additional flags */ __u32 nlmsg_seq;/* Sequence number */ __u32 nlmsg_pid;/* Sending process port ID */ +__u8 contents[];Is this ok to change a public, userspace visable, structure?
Quoted 1 line
Nothing breaks?
It really shouldn't break anything. Adding a flex array doesn't change the size. And with Rasmus's suggestion (naming it "nlmsg_content") it should be safe against weird global macro collisions, etc.
Signature · 1 line
Kees Cook
PATCH 63/64 iwlwifi: dbg_ini: Split memcpy() to avoid multi-field write
In reply to Kees CookTo avoid a run-time false positive in the stricter FORTIFY_SOURCE memcpy() checks, split the memcpy() into the struct and the data. Additionally switch the data member to a flexible array to follow modern language conventions.
--- drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-)
drivers/net/wireless/intel/iwlwifi/fw/file.h +1 -1
@@ -116,7 +116,7 @@ enum iwl_ucode_tlv_type {struct iwl_ucode_tlv {__le32 type;/* see above */ __le32 length;/* not including type/length fields */ -u8 data[0 ]; +u8 data[]; };#define IWL_TLV_UCODE_MAGIC 0x0a4c5749
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +2 -1
@@ -71,7 +71,8 @@ static int iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv,if (!node)return -ENOMEM ; -memcpy (&node->tlv, tlv,sizeof (node->tlv) + len); +memcpy (&node->tlv, tlv,sizeof (node->tlv)); +memcpy (node->tlv.data, tlv->data, len);list_add_tail (&node->list, list);return 0 ;
Signature · 1 line
2.30.2