From: Luca Boccassi Date: Fri, 10 Apr 2026 18:35:59 +0000 (+0100) Subject: udev/scsi-id: check for invalid header from kernel buffer X-Git-Tag: v261-rc1~516^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=06d3f37336ab8dea545521d95ebc6246b29241f0;p=thirdparty%2Fsystemd.git udev/scsi-id: check for invalid header from kernel buffer --- diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c index 7de99992578..23c3b7d786b 100644 --- a/src/udev/scsi_id/scsi_serial.c +++ b/src/udev/scsi_id/scsi_serial.c @@ -542,7 +542,9 @@ static int check_fill_0x83_prespc3(struct scsi_id_device *dev_scsi, /* serial has been memset to zero before */ j = strlen(serial); /* j = 1; */ - for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) { + /* Cap reported page length to buffer size in case of malformed responses */ + int page_len = MIN((int)page_83[3], SCSI_INQ_BUFF_LEN - 4); + for (i = 0; (i < page_len) && (j < max_len-3); ++i) { serial[j++] = hexchar(page_83[4+i] >> 4); serial[j++] = hexchar(page_83[4+i]); } @@ -610,12 +612,25 @@ static int do_scsi_page83_inquiry(struct scsi_id_device *dev_scsi, int fd, * Search for a match in the prioritized id_search_list - since WWN ids * come first we can pick up the WWN in check_fill_0x83_id(). */ + + /* Cap reported page length to buffer size in case of malformed responses. + * Below, j can equal page_end, and at that point page_83[j + 3] (the first descriptor data byte) + * must still be readable before the inner bounds check, so page_end + 4 < SCSI_INQ_BUFF_LEN + * requires page_end <= SCSI_INQ_BUFF_LEN - 5. */ + unsigned page_end = MIN(((unsigned)page_83[2] << 8) + (unsigned)page_83[3] + 3U, + (unsigned)SCSI_INQ_BUFF_LEN - 5U); + FOREACH_ELEMENT(search_value, id_search_list) { /* * Examine each descriptor returned. There is normally only * one or a small number of descriptors. */ - for (unsigned j = 4; j <= ((unsigned)page_83[2] << 8) + (unsigned)page_83[3] + 3; j += page_83[j + 3] + 4) { + for (unsigned j = 4; j <= page_end; j += page_83[j + 3] + 4) { + /* Ensure the full descriptor fits within the buffer, including + * fixed-offset accesses up to page_83[7] in the TGTGROUP path + * of check_fill_0x83_id(), so require at least 8 bytes from j */ + if (j + MAX(4U + (unsigned)page_83[j + 3], 8U) > (unsigned)SCSI_INQ_BUFF_LEN) + break; retval = check_fill_0x83_id(dev_scsi, page_83 + j, search_value, serial, serial_short, len, @@ -688,7 +703,9 @@ static int do_scsi_page83_prespc3_inquiry(struct scsi_id_device *dev_scsi, int f * using two bytes of ASCII for each byte * in the page_83. */ - while (i < (page_83[3]+4)) { + /* Cap reported page length to buffer size in case of malformed responses */ + int page_len = MIN((int)page_83[3] + 4, SCSI_INQ_BUFF_LEN); + while (i < page_len && j + 2 < len) { serial[j++] = hexchar(page_83[i] >> 4); serial[j++] = hexchar(page_83[i]); i++; @@ -725,7 +742,8 @@ static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd, * Prepend 'S' to avoid unlikely collision with page 0x83 vendor * specific type where we prepend '0' + vendor + model. */ - len = buf[3]; + /* Cap reported page length to buffer size in case of malformed responses */ + len = MIN((int)buf[3], SCSI_INQ_BUFF_LEN - 4); if (serial) { serial[0] = 'S'; ser_ind = append_vendor_model(dev_scsi, serial + 1); @@ -860,7 +878,10 @@ int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname, goto completed; } - for (ind = 4; ind <= page0[3] + 3; ind++) + /* Cap reported page length to buffer size in case of malformed responses */ + int page0_end = MIN((int)page0[3] + 3, SCSI_INQ_BUFF_LEN - 1); + + for (ind = 4; ind <= page0_end; ind++) if (page0[ind] == PAGE_83) if (!do_scsi_page83_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { @@ -871,7 +892,7 @@ int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname, goto completed; } - for (ind = 4; ind <= page0[3] + 3; ind++) + for (ind = 4; ind <= page0_end; ind++) if (page0[ind] == PAGE_80) if (!do_scsi_page80_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) {