Unverified Commit 3629ae98 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!6454 CVE-2021-47182

parents e15f5efb 907ea672
Loading
Loading
Loading
Loading
+53 −47
Original line number Diff line number Diff line
@@ -2645,7 +2645,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
/**
 *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
 *	@sdev:	SCSI device to be queried
 *	@dbd:	set if mode sense will allow block descriptors to be returned
 *	@dbd:	set to prevent mode sense from returning block descriptors
 *	@modepage: mode page being requested
 *	@buffer: request buffer (may not be smaller than eight bytes)
 *	@len:	length of request buffer.
@@ -2655,9 +2655,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
 *	@sshdr: place to put sense data (or NULL if no sense to be collected).
 *		must be SCSI_SENSE_BUFFERSIZE big.
 *
 *	Returns zero if unsuccessful, or the header offset (either 4
 *	or 8 depending on whether a six or ten byte command was
 *	issued) if successful.
 *	Returns zero if successful, or a negative error number on failure
 */
int
scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
@@ -2680,18 +2678,18 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
		sshdr = &my_sshdr;

 retry:
	use_10_for_ms = sdev->use_10_for_ms;
	use_10_for_ms = sdev->use_10_for_ms || len > 255;

	if (use_10_for_ms) {
		if (len < 8)
			len = 8;
		if (len < 8 || len > 65535)
			return -EINVAL;

		cmd[0] = MODE_SENSE_10;
		cmd[8] = len;
		put_unaligned_be16(len, &cmd[7]);
		header_length = 8;
	} else {
		if (len < 4)
			len = 4;
			return -EINVAL;

		cmd[0] = MODE_SENSE;
		cmd[4] = len;
@@ -2702,27 +2700,42 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,

	result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
				  sshdr, timeout, retries, NULL);
	if (result < 0)
		return result;

	/* This code looks awful: what it's doing is making sure an
	 * ILLEGAL REQUEST sense return identifies the actual command
	 * byte as the problem.  MODE_SENSE commands can return
	 * ILLEGAL REQUEST if the code page isn't supported */

	if (use_10_for_ms && !scsi_status_is_good(result) &&
	    driver_byte(result) == DRIVER_SENSE) {
		if (scsi_sense_valid(sshdr)) {
	if (!scsi_status_is_good(result)) {
		if (driver_byte(result) == DRIVER_SENSE &&
		    scsi_sense_valid(sshdr)) {
			if ((sshdr->sense_key == ILLEGAL_REQUEST) &&
			    (sshdr->asc == 0x20) && (sshdr->ascq == 0)) {
				/*
				 * Invalid command operation code
				 * Invalid command operation code: retry using
				 * MODE SENSE(6) if this was a MODE SENSE(10)
				 * request, except if the request mode page is
				 * too large for MODE SENSE single byte
				 * allocation length field.
				 */
				if (use_10_for_ms) {
					if (len > 255)
						return -EIO;
					sdev->use_10_for_ms = 0;
					goto retry;
				}
			}
			if ((status_byte(result) == CHECK_CONDITION) &&
			    sshdr->sense_key == UNIT_ATTENTION &&
			    retry_count) {
				retry_count--;
				goto retry;
			}
		}
		return -EIO;
	}

	if(scsi_status_is_good(result)) {
	if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b &&
		     (modepage == 6 || modepage == 8))) {
		/* Initio breakage? */
@@ -2733,12 +2746,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
		data->longlba = 0;
		data->block_descriptor_length = 0;
	} else if (use_10_for_ms) {
			data->length = buffer[0]*256 + buffer[1] + 2;
		data->length = get_unaligned_be16(&buffer[0]) + 2;
		data->medium_type = buffer[2];
		data->device_specific = buffer[3];
		data->longlba = buffer[4] & 0x01;
			data->block_descriptor_length = buffer[6]*256
				+ buffer[7];
		data->block_descriptor_length = get_unaligned_be16(&buffer[6]);
	} else {
		data->length = buffer[0] + 1;
		data->medium_type = buffer[1];
@@ -2746,14 +2758,8 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
		data->block_descriptor_length = buffer[3];
	}
	data->header_length = header_length;
	} else if ((status_byte(result) == CHECK_CONDITION) &&
		   scsi_sense_valid(sshdr) &&
		   sshdr->sense_key == UNIT_ATTENTION && retry_count) {
		retry_count--;
		goto retry;
	}

	return result;
	return 0;
}
EXPORT_SYMBOL(scsi_mode_sense);

+4 −5
Original line number Diff line number Diff line
@@ -1235,16 +1235,15 @@ int sas_read_port_mode_page(struct scsi_device *sdev)
	char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
	struct scsi_mode_data mode_data;
	int res, error;
	int error;

	if (!buffer)
		return -ENOMEM;

	res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
	error = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
				&mode_data, NULL);

	error = -EINVAL;
	if (!scsi_status_is_good(res))
	if (error)
		goto out;

	msdata = buffer +  mode_data.header_length +
+6 −6
Original line number Diff line number Diff line
@@ -2651,18 +2651,18 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
		 * 5: Illegal Request, Sense Code 24: Invalid field in
		 * CDB.
		 */
		if (!scsi_status_is_good(res))
		if (res < 0)
			res = sd_do_mode_sense(sdp, 0, 0, buffer, 4, &data, NULL);

		/*
		 * Third attempt: ask 255 bytes, as we did earlier.
		 */
		if (!scsi_status_is_good(res))
		if (res < 0)
			res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 255,
					       &data, NULL);
	}

	if (!scsi_status_is_good(res)) {
	if (res < 0) {
		sd_first_printk(KERN_WARNING, sdkp,
			  "Test WP failed, assume Write Enabled\n");
	} else {
@@ -2723,7 +2723,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
	res = sd_do_mode_sense(sdp, dbd, modepage, buffer, first_len,
			&data, &sshdr);

	if (!scsi_status_is_good(res))
	if (res < 0)
		goto bad_sense;

	if (!data.header_length) {
@@ -2755,7 +2755,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
		res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len,
				&data, &sshdr);

	if (scsi_status_is_good(res)) {
	if (!res) {
		int offset = data.header_length + data.block_descriptor_length;

		while (offset < len) {
@@ -2873,7 +2873,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
	res = scsi_mode_sense(sdp, 1, 0x0a, buffer, 36, SD_TIMEOUT,
			      SD_MAX_RETRIES, &data, &sshdr);

	if (!scsi_status_is_good(res) || !data.header_length ||
	if (res < 0 || !data.header_length ||
	    data.length < 6) {
		sd_first_printk(KERN_WARNING, sdkp,
			  "getting Control mode page failed, assume no ATO\n");
+1 −1
Original line number Diff line number Diff line
@@ -898,7 +898,7 @@ static void get_capabilities(struct scsi_cd *cd)
	rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len,
			     SR_TIMEOUT, 3, &data, NULL);

	if (!scsi_status_is_good(rc) || data.length > ms_len ||
	if (rc < 0 || data.length > ms_len ||
	    data.header_length + data.block_descriptor_length > data.length) {
		/* failed, drive doesn't have capabilities mode page */
		cd->cdi.speed = 1;