s390x: css: report errors from ccw_dstream_read/write
ccw_dstream_read/write functions returned values are sometime not taking into account and reported back to the upper level of interpretation of CCW instructions. It follows that accessing an invalid address does not trigger a subchannel status program check to the guest as it should. Let's test the return values of ccw_dstream_write[_buf] and ccw_dstream_read[_buf] and report it to the caller. Cc: qemu-stable@nongnu.org Signed-off-by: Pierre Morel <pmorel@linux.ibm.com> Acked-by: Halil Pasic <pasic@linux.ibm.com> Message-Id: <1617899529-9329-2-git-send-email-pmorel@linux.ibm.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
		
							parent
							
								
									d8724020dd
								
							
						
					
					
						commit
						d895d25ae2
					
				@ -200,9 +200,13 @@ static int read_payload_3270(EmulatedCcw3270Device *dev)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    Terminal3270 *t = TERMINAL_3270(dev);
 | 
					    Terminal3270 *t = TERMINAL_3270(dev);
 | 
				
			||||||
    int len;
 | 
					    int len;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    len = MIN(ccw_dstream_avail(get_cds(t)), t->in_len);
 | 
					    len = MIN(ccw_dstream_avail(get_cds(t)), t->in_len);
 | 
				
			||||||
    ccw_dstream_write_buf(get_cds(t), t->inv, len);
 | 
					    ret = ccw_dstream_write_buf(get_cds(t), t->inv, len);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    t->in_len -= len;
 | 
					    t->in_len -= len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return len;
 | 
					    return len;
 | 
				
			||||||
@ -260,7 +264,10 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    t->outv[out_len++] = cmd;
 | 
					    t->outv[out_len++] = cmd;
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
        ccw_dstream_read_buf(get_cds(t), &t->outv[out_len], len);
 | 
					        retval = ccw_dstream_read_buf(get_cds(t), &t->outv[out_len], len);
 | 
				
			||||||
 | 
					        if (retval < 0) {
 | 
				
			||||||
 | 
					            return retval;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        count = ccw_dstream_avail(get_cds(t));
 | 
					        count = ccw_dstream_avail(get_cds(t));
 | 
				
			||||||
        out_len += len;
 | 
					        out_len += len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,9 @@ static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    len = ck->read_payload_3270(dev);
 | 
					    len = ck->read_payload_3270(dev);
 | 
				
			||||||
 | 
					    if (len < 0) {
 | 
				
			||||||
 | 
					        return len;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
 | 
					    ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@ -50,7 +53,7 @@ static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
 | 
				
			|||||||
    len = ck->write_payload_3270(dev, ccw->cmd_code);
 | 
					    len = ck->write_payload_3270(dev, ccw->cmd_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (len <= 0) {
 | 
					    if (len <= 0) {
 | 
				
			||||||
        return -EIO;
 | 
					        return len ? len : -EIO;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
 | 
					    ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
 | 
				
			||||||
 | 
				
			|||||||
@ -1055,10 +1055,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        len = MIN(ccw.count, sizeof(sch->sense_data));
 | 
					        len = MIN(ccw.count, sizeof(sch->sense_data));
 | 
				
			||||||
        ccw_dstream_write_buf(&sch->cds, sch->sense_data, len);
 | 
					        ret = ccw_dstream_write_buf(&sch->cds, sch->sense_data, len);
 | 
				
			||||||
        sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
 | 
					        sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
 | 
				
			||||||
 | 
					        if (!ret) {
 | 
				
			||||||
            memset(sch->sense_data, 0, sizeof(sch->sense_data));
 | 
					            memset(sch->sense_data, 0, sizeof(sch->sense_data));
 | 
				
			||||||
        ret = 0;
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case CCW_CMD_SENSE_ID:
 | 
					    case CCW_CMD_SENSE_ID:
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -1083,9 +1084,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            sense_id[0] = 0;
 | 
					            sense_id[0] = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ccw_dstream_write_buf(&sch->cds, sense_id, len);
 | 
					        ret = ccw_dstream_write_buf(&sch->cds, sense_id, len);
 | 
				
			||||||
 | 
					        if (!ret) {
 | 
				
			||||||
            sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
 | 
					            sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
 | 
				
			||||||
        ret = 0;
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case CCW_CMD_TIC:
 | 
					    case CCW_CMD_TIC:
 | 
				
			||||||
 | 
				
			|||||||
@ -288,14 +288,20 @@ static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len,
 | 
				
			|||||||
        return -EFAULT;
 | 
					        return -EFAULT;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (is_legacy) {
 | 
					    if (is_legacy) {
 | 
				
			||||||
        ccw_dstream_read(&sch->cds, linfo);
 | 
					        ret = ccw_dstream_read(&sch->cds, linfo);
 | 
				
			||||||
 | 
					        if (ret) {
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        linfo.queue = be64_to_cpu(linfo.queue);
 | 
					        linfo.queue = be64_to_cpu(linfo.queue);
 | 
				
			||||||
        linfo.align = be32_to_cpu(linfo.align);
 | 
					        linfo.align = be32_to_cpu(linfo.align);
 | 
				
			||||||
        linfo.index = be16_to_cpu(linfo.index);
 | 
					        linfo.index = be16_to_cpu(linfo.index);
 | 
				
			||||||
        linfo.num = be16_to_cpu(linfo.num);
 | 
					        linfo.num = be16_to_cpu(linfo.num);
 | 
				
			||||||
        ret = virtio_ccw_set_vqs(sch, NULL, &linfo);
 | 
					        ret = virtio_ccw_set_vqs(sch, NULL, &linfo);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ccw_dstream_read(&sch->cds, info);
 | 
					        ret = ccw_dstream_read(&sch->cds, info);
 | 
				
			||||||
 | 
					        if (ret) {
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        info.desc = be64_to_cpu(info.desc);
 | 
					        info.desc = be64_to_cpu(info.desc);
 | 
				
			||||||
        info.index = be16_to_cpu(info.index);
 | 
					        info.index = be16_to_cpu(info.index);
 | 
				
			||||||
        info.num = be16_to_cpu(info.num);
 | 
					        info.num = be16_to_cpu(info.num);
 | 
				
			||||||
@ -371,7 +377,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
            VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
 | 
					            VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ccw_dstream_advance(&sch->cds, sizeof(features.features));
 | 
					            ccw_dstream_advance(&sch->cds, sizeof(features.features));
 | 
				
			||||||
            ccw_dstream_read(&sch->cds, features.index);
 | 
					            ret = ccw_dstream_read(&sch->cds, features.index);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            if (features.index == 0) {
 | 
					            if (features.index == 0) {
 | 
				
			||||||
                if (dev->revision >= 1) {
 | 
					                if (dev->revision >= 1) {
 | 
				
			||||||
                    /* Don't offer legacy features for modern devices. */
 | 
					                    /* Don't offer legacy features for modern devices. */
 | 
				
			||||||
@ -392,9 +401,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            ccw_dstream_rewind(&sch->cds);
 | 
					            ccw_dstream_rewind(&sch->cds);
 | 
				
			||||||
            features.features = cpu_to_le32(features.features);
 | 
					            features.features = cpu_to_le32(features.features);
 | 
				
			||||||
            ccw_dstream_write(&sch->cds, features.features);
 | 
					            ret = ccw_dstream_write(&sch->cds, features.features);
 | 
				
			||||||
 | 
					            if (!ret) {
 | 
				
			||||||
                sch->curr_status.scsw.count = ccw.count - sizeof(features);
 | 
					                sch->curr_status.scsw.count = ccw.count - sizeof(features);
 | 
				
			||||||
            ret = 0;
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case CCW_CMD_WRITE_FEAT:
 | 
					    case CCW_CMD_WRITE_FEAT:
 | 
				
			||||||
@ -411,7 +421,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
        if (!ccw.cda) {
 | 
					        if (!ccw.cda) {
 | 
				
			||||||
            ret = -EFAULT;
 | 
					            ret = -EFAULT;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            ccw_dstream_read(&sch->cds, features);
 | 
					            ret = ccw_dstream_read(&sch->cds, features);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            features.features = le32_to_cpu(features.features);
 | 
					            features.features = le32_to_cpu(features.features);
 | 
				
			||||||
            if (features.index == 0) {
 | 
					            if (features.index == 0) {
 | 
				
			||||||
                virtio_set_features(vdev,
 | 
					                virtio_set_features(vdev,
 | 
				
			||||||
@ -454,9 +467,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
            ret = -EFAULT;
 | 
					            ret = -EFAULT;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            virtio_bus_get_vdev_config(&dev->bus, vdev->config);
 | 
					            virtio_bus_get_vdev_config(&dev->bus, vdev->config);
 | 
				
			||||||
            ccw_dstream_write_buf(&sch->cds, vdev->config, len);
 | 
					            ret = ccw_dstream_write_buf(&sch->cds, vdev->config, len);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
                sch->curr_status.scsw.count = ccw.count - len;
 | 
					                sch->curr_status.scsw.count = ccw.count - len;
 | 
				
			||||||
            ret = 0;
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case CCW_CMD_WRITE_CONF:
 | 
					    case CCW_CMD_WRITE_CONF:
 | 
				
			||||||
@ -511,7 +525,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
        if (!ccw.cda) {
 | 
					        if (!ccw.cda) {
 | 
				
			||||||
            ret = -EFAULT;
 | 
					            ret = -EFAULT;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            ccw_dstream_read(&sch->cds, status);
 | 
					            ret = ccw_dstream_read(&sch->cds, status);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
 | 
					            if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
 | 
				
			||||||
                virtio_ccw_stop_ioeventfd(dev);
 | 
					                virtio_ccw_stop_ioeventfd(dev);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -554,7 +571,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
        if (!ccw.cda) {
 | 
					        if (!ccw.cda) {
 | 
				
			||||||
            ret = -EFAULT;
 | 
					            ret = -EFAULT;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            ccw_dstream_read(&sch->cds, indicators);
 | 
					            ret = ccw_dstream_read(&sch->cds, indicators);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            indicators = be64_to_cpu(indicators);
 | 
					            indicators = be64_to_cpu(indicators);
 | 
				
			||||||
            dev->indicators = get_indicator(indicators, sizeof(uint64_t));
 | 
					            dev->indicators = get_indicator(indicators, sizeof(uint64_t));
 | 
				
			||||||
            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
 | 
					            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
 | 
				
			||||||
@ -575,7 +595,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
        if (!ccw.cda) {
 | 
					        if (!ccw.cda) {
 | 
				
			||||||
            ret = -EFAULT;
 | 
					            ret = -EFAULT;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            ccw_dstream_read(&sch->cds, indicators);
 | 
					            ret = ccw_dstream_read(&sch->cds, indicators);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            indicators = be64_to_cpu(indicators);
 | 
					            indicators = be64_to_cpu(indicators);
 | 
				
			||||||
            dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
 | 
					            dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
 | 
				
			||||||
            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
 | 
					            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
 | 
				
			||||||
@ -596,7 +619,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
        if (!ccw.cda) {
 | 
					        if (!ccw.cda) {
 | 
				
			||||||
            ret = -EFAULT;
 | 
					            ret = -EFAULT;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            ccw_dstream_read(&sch->cds, vq_config.index);
 | 
					            ret = ccw_dstream_read(&sch->cds, vq_config.index);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            vq_config.index = be16_to_cpu(vq_config.index);
 | 
					            vq_config.index = be16_to_cpu(vq_config.index);
 | 
				
			||||||
            if (vq_config.index >= VIRTIO_QUEUE_MAX) {
 | 
					            if (vq_config.index >= VIRTIO_QUEUE_MAX) {
 | 
				
			||||||
                ret = -EINVAL;
 | 
					                ret = -EINVAL;
 | 
				
			||||||
@ -605,9 +631,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
            vq_config.num_max = virtio_queue_get_num(vdev,
 | 
					            vq_config.num_max = virtio_queue_get_num(vdev,
 | 
				
			||||||
                                                     vq_config.index);
 | 
					                                                     vq_config.index);
 | 
				
			||||||
            vq_config.num_max = cpu_to_be16(vq_config.num_max);
 | 
					            vq_config.num_max = cpu_to_be16(vq_config.num_max);
 | 
				
			||||||
            ccw_dstream_write(&sch->cds, vq_config.num_max);
 | 
					            ret = ccw_dstream_write(&sch->cds, vq_config.num_max);
 | 
				
			||||||
 | 
					            if (!ret) {
 | 
				
			||||||
                sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
 | 
					                sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
 | 
				
			||||||
            ret = 0;
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case CCW_CMD_SET_IND_ADAPTER:
 | 
					    case CCW_CMD_SET_IND_ADAPTER:
 | 
				
			||||||
@ -664,7 +691,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
 | 
				
			|||||||
            ret = -EFAULT;
 | 
					            ret = -EFAULT;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ccw_dstream_read_buf(&sch->cds, &revinfo, 4);
 | 
					        ret = ccw_dstream_read_buf(&sch->cds, &revinfo, 4);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        revinfo.revision = be16_to_cpu(revinfo.revision);
 | 
					        revinfo.revision = be16_to_cpu(revinfo.revision);
 | 
				
			||||||
        revinfo.length = be16_to_cpu(revinfo.length);
 | 
					        revinfo.length = be16_to_cpu(revinfo.length);
 | 
				
			||||||
        if (ccw.count < len + revinfo.length ||
 | 
					        if (ccw.count < len + revinfo.length ||
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user