overflow: Add struct_size_t() helper
authorKees Cook <keescook@chromium.org>
Mon, 22 May 2023 21:18:13 +0000 (14:18 -0700)
committerKees Cook <keescook@chromium.org>
Fri, 26 May 2023 20:52:19 +0000 (13:52 -0700)
While struct_size() is normally used in situations where the structure
type already has a pointer instance, there are places where no variable
is available. In the past, this has been worked around by using a typed
NULL first argument, but this is a bit ugly. Add a helper to do this,
and replace the handful of instances of the code pattern with it.

Instances were found with this Coccinelle script:

@struct_size_t@
identifier STRUCT, MEMBER;
expression COUNT;
@@

-       struct_size((struct STRUCT *)\(0\|NULL\),
+       struct_size_t(struct STRUCT,
                MEMBER, COUNT)

Suggested-by: Christoph Hellwig <hch@infradead.org>
Cc: Jesse Brandeburg <jesse.brandeburg@intel.com>
Cc: Tony Nguyen <anthony.l.nguyen@intel.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: James Smart <james.smart@broadcom.com>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Sagi Grimberg <sagi@grimberg.me>
Cc: HighPoint Linux Team <linux@highpoint-tech.com>
Cc: "James E.J. Bottomley" <jejb@linux.ibm.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Kashyap Desai <kashyap.desai@broadcom.com>
Cc: Sumit Saxena <sumit.saxena@broadcom.com>
Cc: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Cc: Don Brace <don.brace@microchip.com>
Cc: "Darrick J. Wong" <djwong@kernel.org>
Cc: Dave Chinner <dchinner@redhat.com>
Cc: Guo Xuenan <guoxuenan@huawei.com>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Daniel Latypov <dlatypov@google.com>
Cc: kernel test robot <lkp@intel.com>
Cc: intel-wired-lan@lists.osuosl.org
Cc: netdev@vger.kernel.org
Cc: linux-nvme@lists.infradead.org
Cc: linux-scsi@vger.kernel.org
Cc: megaraidlinux.pdl@broadcom.com
Cc: storagedev@microchip.com
Cc: linux-xfs@vger.kernel.org
Cc: linux-hardening@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
Acked-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Link: https://lore.kernel.org/r/20230522211810.never.421-kees@kernel.org
drivers/net/ethernet/intel/ice/ice_ddp.h
drivers/nvme/host/fc.c
drivers/scsi/hptiop.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/smartpqi/smartpqi_init.c
fs/xfs/libxfs/xfs_btree.h
fs/xfs/scrub/btree.h
include/linux/overflow.h
lib/overflow_kunit.c

index 37eadb3..41acfe2 100644 (file)
@@ -185,7 +185,7 @@ struct ice_buf_hdr {
 
 #define ICE_MAX_ENTRIES_IN_BUF(hd_sz, ent_sz)                                 \
        ((ICE_PKG_BUF_SIZE -                                                  \
-         struct_size((struct ice_buf_hdr *)0, section_entry, 1) - (hd_sz)) / \
+         struct_size_t(struct ice_buf_hdr,  section_entry, 1) - (hd_sz)) / \
         (ent_sz))
 
 /* ice package section IDs */
@@ -297,7 +297,7 @@ struct ice_label_section {
 };
 
 #define ICE_MAX_LABELS_IN_BUF                                             \
-       ICE_MAX_ENTRIES_IN_BUF(struct_size((struct ice_label_section *)0, \
+       ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_label_section,  \
                                           label, 1) -                    \
                                       sizeof(struct ice_label),          \
                               sizeof(struct ice_label))
@@ -352,7 +352,7 @@ struct ice_boost_tcam_section {
 };
 
 #define ICE_MAX_BST_TCAMS_IN_BUF                                               \
-       ICE_MAX_ENTRIES_IN_BUF(struct_size((struct ice_boost_tcam_section *)0, \
+       ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_boost_tcam_section,  \
                                           tcam, 1) -                          \
                                       sizeof(struct ice_boost_tcam_entry),    \
                               sizeof(struct ice_boost_tcam_entry))
@@ -372,8 +372,7 @@ struct ice_marker_ptype_tcam_section {
 };
 
 #define ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF                                    \
-       ICE_MAX_ENTRIES_IN_BUF(                                              \
-               struct_size((struct ice_marker_ptype_tcam_section *)0, tcam, \
+       ICE_MAX_ENTRIES_IN_BUF(struct_size_t(struct ice_marker_ptype_tcam_section,  tcam, \
                            1) -                                             \
                        sizeof(struct ice_marker_ptype_tcam_entry),          \
                sizeof(struct ice_marker_ptype_tcam_entry))
index 2ed7592..691f2df 100644 (file)
@@ -2917,8 +2917,8 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
 
        ret = nvme_alloc_io_tag_set(&ctrl->ctrl, &ctrl->tag_set,
                        &nvme_fc_mq_ops, 1,
-                       struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
-                                   ctrl->lport->ops->fcprqst_priv_sz));
+                       struct_size_t(struct nvme_fcp_op_w_sgl, priv,
+                                     ctrl->lport->ops->fcprqst_priv_sz));
        if (ret)
                return ret;
 
@@ -3536,8 +3536,8 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
 
        ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set,
                        &nvme_fc_admin_mq_ops,
-                       struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
-                                   ctrl->lport->ops->fcprqst_priv_sz));
+                       struct_size_t(struct nvme_fcp_op_w_sgl, priv,
+                                     ctrl->lport->ops->fcprqst_priv_sz));
        if (ret)
                goto fail_ctrl;
 
index 06ccb51..f5334cc 100644 (file)
@@ -1394,8 +1394,8 @@ static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
        host->cmd_per_lun = le32_to_cpu(iop_config.max_requests);
        host->max_cmd_len = 16;
 
-       req_size = struct_size((struct hpt_iop_request_scsi_command *)0,
-                              sg_list, hba->max_sg_descriptors);
+       req_size = struct_size_t(struct hpt_iop_request_scsi_command,
+                                sg_list, hba->max_sg_descriptors);
        if ((req_size & 0x1f) != 0)
                req_size = (req_size + 0x1f) & ~0x1f;
 
index 317c944..050eed8 100644 (file)
@@ -5153,8 +5153,8 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance)
                fusion->max_map_sz = ventura_map_sz;
        } else {
                fusion->old_map_sz =
-                       struct_size((struct MR_FW_RAID_MAP *)0, ldSpanMap,
-                                   instance->fw_supported_vd_count);
+                       struct_size_t(struct MR_FW_RAID_MAP, ldSpanMap,
+                                     instance->fw_supported_vd_count);
                fusion->new_map_sz =  sizeof(struct MR_FW_RAID_MAP_EXT);
 
                fusion->max_map_sz =
@@ -5789,8 +5789,8 @@ megasas_setup_jbod_map(struct megasas_instance *instance)
        struct fusion_context *fusion = instance->ctrl_context;
        size_t pd_seq_map_sz;
 
-       pd_seq_map_sz = struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0, seq,
-                                   MAX_PHYSICAL_DEVICES);
+       pd_seq_map_sz = struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC, seq,
+                                     MAX_PHYSICAL_DEVICES);
 
        instance->use_seqnum_jbod_fp =
                instance->support_seqnum_jbod_fp;
@@ -8033,8 +8033,8 @@ skip_firing_dcmds:
        if (instance->adapter_type != MFI_SERIES) {
                megasas_release_fusion(instance);
                pd_seq_map_sz =
-                       struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0,
-                                   seq, MAX_PHYSICAL_DEVICES);
+                       struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC,
+                                     seq, MAX_PHYSICAL_DEVICES);
                for (i = 0; i < 2 ; i++) {
                        if (fusion->ld_map[i])
                                dma_free_coherent(&instance->pdev->dev,
index 4463a53..b8b388a 100644 (file)
@@ -326,9 +326,9 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id)
        else if (instance->supportmax256vd)
                expected_size = sizeof(struct MR_FW_RAID_MAP_EXT);
        else
-               expected_size = struct_size((struct MR_FW_RAID_MAP *)0,
-                                           ldSpanMap,
-                                           le16_to_cpu(pDrvRaidMap->ldCount));
+               expected_size = struct_size_t(struct MR_FW_RAID_MAP,
+                                             ldSpanMap,
+                                             le16_to_cpu(pDrvRaidMap->ldCount));
 
        if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) {
                dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x",
index 03de97c..f4e0aa2 100644 (file)
@@ -5015,7 +5015,7 @@ static int pqi_create_queues(struct pqi_ctrl_info *ctrl_info)
 }
 
 #define PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH  \
-       struct_size((struct pqi_event_config *)0, descriptors, PQI_MAX_EVENT_DESCRIPTORS)
+       struct_size_t(struct pqi_event_config,  descriptors, PQI_MAX_EVENT_DESCRIPTORS)
 
 static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info,
        bool enable_events)
index a2aa36b..4d68a58 100644 (file)
@@ -301,7 +301,7 @@ struct xfs_btree_cur
 static inline size_t
 xfs_btree_cur_sizeof(unsigned int nlevels)
 {
-       return struct_size((struct xfs_btree_cur *)NULL, bc_levels, nlevels);
+       return struct_size_t(struct xfs_btree_cur, bc_levels, nlevels);
 }
 
 /* cursor flags */
index 9d7b9ee..c32b5fa 100644 (file)
@@ -60,7 +60,7 @@ struct xchk_btree {
 static inline size_t
 xchk_btree_sizeof(unsigned int nlevels)
 {
-       return struct_size((struct xchk_btree *)NULL, lastkey, nlevels - 1);
+       return struct_size_t(struct xchk_btree, lastkey, nlevels - 1);
 }
 
 int xchk_btree(struct xfs_scrub *sc, struct xfs_btree_cur *cur,
index 0e33b5c..f9b6031 100644 (file)
@@ -283,7 +283,7 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
  * @member: Name of the array member.
  * @count: Number of elements in the array.
  *
- * Calculates size of memory needed for structure @p followed by an
+ * Calculates size of memory needed for structure of @p followed by an
  * array of @count number of @member elements.
  *
  * Return: number of bytes needed or SIZE_MAX on overflow.
@@ -293,4 +293,20 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
                sizeof(*(p)) + flex_array_size(p, member, count),       \
                size_add(sizeof(*(p)), flex_array_size(p, member, count)))
 
+/**
+ * struct_size_t() - Calculate size of structure with trailing flexible array
+ * @type: structure type name.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of memory needed for structure @type followed by an
+ * array of @count number of @member elements. Prefer using struct_size()
+ * when possible instead, to keep calculations associated with a specific
+ * instance variable of type @type.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define struct_size_t(type, member, count)                                     \
+       struct_size((type *)NULL, member, count)
+
 #endif /* __LINUX_OVERFLOW_H */
index dcd3ba1..34db0b3 100644 (file)
@@ -649,7 +649,7 @@ struct __test_flex_array {
 static void overflow_size_helpers_test(struct kunit *test)
 {
        /* Make sure struct_size() can be used in a constant expression. */
-       u8 ce_array[struct_size((struct __test_flex_array *)0, data, 55)];
+       u8 ce_array[struct_size_t(struct __test_flex_array, data, 55)];
        struct __test_flex_array *obj;
        int count = 0;
        int var;