Commit d88a0240 authored by Kees Cook's avatar Kees Cook Committed by Martin K. Petersen
Browse files

scsi: scsi_transport_fc: Adjust struct fc_nl_event flex array usage

In order to help the compiler reason about the destination buffer in struct
fc_nl_event, add a flexible array member for this purpose.  However, since
the header is UAPI, it must not change size or layout, so a union is used.

The allocation size calculations are also corrected (it was potentially
allocating an extra 8 bytes), and the padding is zeroed to avoid leaking
kernel heap memory contents.

Detected at run-time by the recently added memcpy() bounds checking:

  memcpy: detected field-spanning write (size 8) of single field "&event->event_data" at drivers/scsi/scsi_transport_fc.c:581 (size 4)

Link: https://lore.kernel.org/linux-next/42404B5E-198B-4FD3-94D6-5E16CF579EF3@linux.ibm.com/
Link: https://lore.kernel.org/r/20220921205155.1451649-1-keescook@chromium.org


Cc: "James E.J. Bottomley" <jejb@linux.ibm.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
Reported-by: default avatarSachin Sant <sachinp@linux.ibm.com>
Tested-by: default avatarSachin Sant <sachinp@linux.ibm.com>
Reviewed-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 1a2433b0
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -543,7 +543,7 @@ fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number,
	struct nlmsghdr	*nlh;
	struct fc_nl_event *event;
	const char *name;
	u32 len;
	size_t len, padding;
	int err;

	if (!data_buf || data_len < 4)
@@ -554,7 +554,7 @@ fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number,
		goto send_fail;
	}

	len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
	len = FC_NL_MSGALIGN(sizeof(*event) - sizeof(event->event_data) + data_len);

	skb = nlmsg_new(len, GFP_KERNEL);
	if (!skb) {
@@ -578,7 +578,9 @@ fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number,
	event->event_num = event_number;
	event->event_code = event_code;
	if (data_len)
		memcpy(&event->event_data, data_buf, data_len);
		memcpy(event->event_data_flex, data_buf, data_len);
	padding = len - offsetof(typeof(*event), event_data_flex) - data_len;
	memset(event->event_data_flex + data_len, 0, padding);

	nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
			GFP_KERNEL);
+5 −2
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
 * FC Transport Broadcast Event Message :
 *   FC_NL_ASYNC_EVENT
 *
 * Note: if Vendor Unique message, &event_data will be  start of
 * Note: if Vendor Unique message, event_data_flex will be start of
 * 	 vendor unique payload, and the length of the payload is
 *       per event_datalen
 *
@@ -50,7 +50,10 @@ struct fc_nl_event {
	__u16 event_datalen;
	__u32 event_num;
	__u32 event_code;
	union {
		__u32 event_data;
		__DECLARE_FLEX_ARRAY(__u8, event_data_flex);
	};
} __attribute__((aligned(sizeof(__u64))));