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

wifi: ipw2x00: convert ipw_fw_error->elem to flexible array[]

The ipw_fw_error structure contains a payload[] flexible array as well as
two pointers to this array area, ->elem, and ->log. The total size of the
allocated structure is computed without use of the <linux/overflow.h>
macros.

There's no reason to keep both a payload[] and an extra pointer to both the
elem and log members. Convert the elem pointer member into the flexible
array member, removing payload.

Fix the allocation of the ipw_fw_error structure to use size_add(),
struct_size(), and array_size() to compute the allocation. This ensures
that any overflow saturates at SIZE_MAX rather than overflowing and
potentially allowing an undersized allocation.

Before the structure change, the layout of ipw_fw_error was:

struct ipw_fw_error {
long unsigned int jiffies; /* 0 8 */
u32 status; /* 8 4 */
u32 config; /* 12 4 */
u32 elem_len; /* 16 4 */
u32 log_len; /* 20 4 */
struct ipw_error_elem * elem; /* 24 8 */
struct ipw_event * log; /* 32 8 */
u8 payload[]; /* 40 0 */

/* size: 40, cachelines: 1, members: 8 */
/* last cacheline: 40 bytes */
};

After this change, the layout is now:

struct ipw_fw_error {
long unsigned int jiffies; /* 0 8 */
u32 status; /* 8 4 */
u32 config; /* 12 4 */
u32 elem_len; /* 16 4 */
u32 log_len; /* 20 4 */
struct ipw_event * log; /* 24 8 */
struct ipw_error_elem elem[]; /* 32 0 */

/* size: 32, cachelines: 1, members: 7 */
/* last cacheline: 32 bytes */
};

This saves a total of 8 bytes for every ipw_fw_error allocation, and
removes the risk of a potential overflow on the allocation.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Cc: Stanislav Yakovlev <stas.yakovlev@gmail.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230307230148.3735684-1-jacob.e.keller@intel.com

authored by

Jacob Keller and committed by
Kalle Valo
a23c82e0 0606b344

+4 -6
+3 -4
drivers/net/wireless/intel/ipw2x00/ipw2200.c
··· 1234 1234 u32 base = ipw_read32(priv, IPW_ERROR_LOG); 1235 1235 u32 elem_len = ipw_read_reg32(priv, base); 1236 1236 1237 - error = kmalloc(sizeof(*error) + 1238 - sizeof(*error->elem) * elem_len + 1239 - sizeof(*error->log) * log_len, GFP_ATOMIC); 1237 + error = kmalloc(size_add(struct_size(error, elem, elem_len), 1238 + array_size(sizeof(*error->log), log_len)), 1239 + GFP_ATOMIC); 1240 1240 if (!error) { 1241 1241 IPW_ERROR("Memory allocation for firmware error log " 1242 1242 "failed.\n"); ··· 1247 1247 error->config = priv->config; 1248 1248 error->elem_len = elem_len; 1249 1249 error->log_len = log_len; 1250 - error->elem = (struct ipw_error_elem *)error->payload; 1251 1250 error->log = (struct ipw_event *)(error->elem + elem_len); 1252 1251 1253 1252 ipw_capture_event_log(priv, log_len, error->log);
+1 -2
drivers/net/wireless/intel/ipw2x00/ipw2200.h
··· 1106 1106 u32 config; 1107 1107 u32 elem_len; 1108 1108 u32 log_len; 1109 - struct ipw_error_elem *elem; 1110 1109 struct ipw_event *log; 1111 - u8 payload[]; 1110 + struct ipw_error_elem elem[]; 1112 1111 } __packed; 1113 1112 1114 1113 #ifdef CONFIG_IPW2200_PROMISCUOUS