> On 22-Sep-2022, at 2:13 AM, Kees Cook <keescook@xxxxxxxxxxxx> wrote: > > On Wed, Sep 21, 2022 at 09:21:52PM +0530, Sachin Sant wrote: >> While booting recent linux-next kernel on a Power server following >> warning is seen: >> >> [ 6.427054] lpfc 0022:01:00.0: 0:6468 Set host date / time: Status x10: >> [ 6.471457] lpfc 0022:01:00.0: 0:6448 Dual Dump is enabled >> [ 7.432161] ------------[ cut here ]------------ >> [ 7.432178] memcpy: detected field-spanning write (size 8) of single field "&event->event_data" at drivers/scsi/scsi_transport_fc.c:581 (size 4) > > Interesting! > > The memcpy() is this one: > > memcpy(&event->event_data, data_buf, data_len); > > The struct member, "event_data" is defined as u32: > > ... > * 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 > ... > struct fc_nl_event { > struct scsi_nl_hdr snlh; /* must be 1st element ! */ > __u64 seconds; > __u64 vendor_id; > __u16 host_no; > __u16 event_datalen; > __u32 event_num; > __u32 event_code; > __u32 event_data; > } __attribute__((aligned(sizeof(__u64)))); > > The warning says memcpy is trying to write 8 bytes into the 4 byte > member, so the compiler is seeing it "correctly", but I think this is > partially a false positive. It looks like there is also a small bug in > the allocation size calculation and therefore a small leak of kernel > heap memory contents. My notes: > > void > fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number, > enum fc_host_event_code event_code, > u32 data_len, char *data_buf, u64 vendor_id) > { > ... > struct fc_nl_event *event; > ... > if (!data_buf || data_len < 4) > data_len = 0; > > This wants a data_buf and a data_len >= 4, so it does look like it's > expected to be variable sized. There does appear to be an alignment > and padding expectation, though: > > /* macro to round up message lengths to 8byte boundary */ > #define FC_NL_MSGALIGN(len) (((len) + 7) & ~7) > > ... > len = FC_NL_MSGALIGN(sizeof(*event) + data_len); > > But this is immediately suspicious: sizeof(*event) _includes_ event_data, > so the alignment is going to be bumped up incorrectly. Note that > struct fc_nl_event is 8 * 5 == 40 bytes, which allows for 4 bytes in > event_data. But setting data_len to 4 (i.e. no "overflow") means we're > asking for 44 bytes, which is aligned to 48. > > So, in all cases, there is uninitialized memory being sent... > > skb = nlmsg_new(len, GFP_KERNEL); > ... > nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0); > ... > event = nlmsg_data(nlh); > ... > event->event_datalen = data_len; /* bytes */ > > Comments in the struct say this is counting from start of event_data. > > ... > if (data_len) > memcpy(&event->event_data, data_buf, data_len); > > And here is the reported memcpy(). > > The callers of fc_host_post_fc_event() are: > > fc_host_post_fc_event(shost, event_number, event_code, > (u32)sizeof(u32), (char *)&event_data, 0); > > Fixed-size of 4 bytes: no "overflow". > > fc_host_post_fc_event(shost, event_number, FCH_EVT_VENDOR_UNIQUE, > data_len, data_buf, vendor_id); > > fc_host_post_fc_event(shost, fc_get_event_number(), > FCH_EVT_LINK_FPIN, fpin_len, fpin_buf, 0); > > These two appear to be of arbitrary length, but I didn't look more > deeply. > > Given that the only user of struct fc_nl_event is fc_host_post_fc_event() > in drivers/scsi/scsi_transport_fc.c, it looks safe to say that changing > the struct to use a flexible array is the thing to do in the kernel, but > we can't actually change the size or layout because it's a UAPI header. > > Are you able to test this patch: Thank you for the detailed analysis. With this patch applied I don’t see the warning. Thanks - Sachin