| From ba50bf1ce9a51fc97db58b96d01306aa70bc3979 Mon Sep 17 00:00:00 2001 |
| From: Dexuan Cui <decui@microsoft.com> |
| Date: Mon, 17 Dec 2018 20:16:09 +0000 |
| Subject: Drivers: hv: vmbus: Check for ring when getting debug info |
| |
| From: Dexuan Cui <decui@microsoft.com> |
| |
| commit ba50bf1ce9a51fc97db58b96d01306aa70bc3979 upstream. |
| |
| fc96df16a1ce is good and can already fix the "return stack garbage" issue, |
| but let's also improve hv_ringbuffer_get_debuginfo(), which would silently |
| return stack garbage, if people forget to check channel->state or |
| ring_info->ring_buffer, when using the function in the future. |
| |
| Having an error check in the function would eliminate the potential risk. |
| |
| Add a Fixes tag to indicate the patch depdendency. |
| |
| Fixes: fc96df16a1ce ("Drivers: hv: vmbus: Return -EINVAL for the sys files for unopened channels") |
| Cc: stable@vger.kernel.org |
| Cc: K. Y. Srinivasan <kys@microsoft.com> |
| Cc: Haiyang Zhang <haiyangz@microsoft.com> |
| Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> |
| Signed-off-by: Dexuan Cui <decui@microsoft.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/hv/ring_buffer.c | 29 +++++++------- |
| drivers/hv/vmbus_drv.c | 91 +++++++++++++++++++++++++++++++---------------- |
| include/linux/hyperv.h | 5 +- |
| 3 files changed, 78 insertions(+), 47 deletions(-) |
| |
| --- a/drivers/hv/ring_buffer.c |
| +++ b/drivers/hv/ring_buffer.c |
| @@ -141,26 +141,25 @@ static u32 hv_copyto_ringbuffer( |
| } |
| |
| /* Get various debug metrics for the specified ring buffer. */ |
| -void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, |
| - struct hv_ring_buffer_debug_info *debug_info) |
| +int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, |
| + struct hv_ring_buffer_debug_info *debug_info) |
| { |
| u32 bytes_avail_towrite; |
| u32 bytes_avail_toread; |
| |
| - if (ring_info->ring_buffer) { |
| - hv_get_ringbuffer_availbytes(ring_info, |
| - &bytes_avail_toread, |
| - &bytes_avail_towrite); |
| + if (!ring_info->ring_buffer) |
| + return -EINVAL; |
| |
| - debug_info->bytes_avail_toread = bytes_avail_toread; |
| - debug_info->bytes_avail_towrite = bytes_avail_towrite; |
| - debug_info->current_read_index = |
| - ring_info->ring_buffer->read_index; |
| - debug_info->current_write_index = |
| - ring_info->ring_buffer->write_index; |
| - debug_info->current_interrupt_mask = |
| - ring_info->ring_buffer->interrupt_mask; |
| - } |
| + hv_get_ringbuffer_availbytes(ring_info, |
| + &bytes_avail_toread, |
| + &bytes_avail_towrite); |
| + debug_info->bytes_avail_toread = bytes_avail_toread; |
| + debug_info->bytes_avail_towrite = bytes_avail_towrite; |
| + debug_info->current_read_index = ring_info->ring_buffer->read_index; |
| + debug_info->current_write_index = ring_info->ring_buffer->write_index; |
| + debug_info->current_interrupt_mask |
| + = ring_info->ring_buffer->interrupt_mask; |
| + return 0; |
| } |
| EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); |
| |
| --- a/drivers/hv/vmbus_drv.c |
| +++ b/drivers/hv/vmbus_drv.c |
| @@ -297,12 +297,16 @@ static ssize_t out_intr_mask_show(struct |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info outbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
| + &outbound); |
| + if (ret < 0) |
| + return ret; |
| + |
| return sprintf(buf, "%d\n", outbound.current_interrupt_mask); |
| } |
| static DEVICE_ATTR_RO(out_intr_mask); |
| @@ -312,12 +316,15 @@ static ssize_t out_read_index_show(struc |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info outbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
| + &outbound); |
| + if (ret < 0) |
| + return ret; |
| return sprintf(buf, "%d\n", outbound.current_read_index); |
| } |
| static DEVICE_ATTR_RO(out_read_index); |
| @@ -328,12 +335,15 @@ static ssize_t out_write_index_show(stru |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info outbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
| + &outbound); |
| + if (ret < 0) |
| + return ret; |
| return sprintf(buf, "%d\n", outbound.current_write_index); |
| } |
| static DEVICE_ATTR_RO(out_write_index); |
| @@ -344,12 +354,15 @@ static ssize_t out_read_bytes_avail_show |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info outbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
| + &outbound); |
| + if (ret < 0) |
| + return ret; |
| return sprintf(buf, "%d\n", outbound.bytes_avail_toread); |
| } |
| static DEVICE_ATTR_RO(out_read_bytes_avail); |
| @@ -360,12 +373,15 @@ static ssize_t out_write_bytes_avail_sho |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info outbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
| + &outbound); |
| + if (ret < 0) |
| + return ret; |
| return sprintf(buf, "%d\n", outbound.bytes_avail_towrite); |
| } |
| static DEVICE_ATTR_RO(out_write_bytes_avail); |
| @@ -375,12 +391,15 @@ static ssize_t in_intr_mask_show(struct |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info inbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + if (ret < 0) |
| + return ret; |
| + |
| return sprintf(buf, "%d\n", inbound.current_interrupt_mask); |
| } |
| static DEVICE_ATTR_RO(in_intr_mask); |
| @@ -390,12 +409,15 @@ static ssize_t in_read_index_show(struct |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info inbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + if (ret < 0) |
| + return ret; |
| + |
| return sprintf(buf, "%d\n", inbound.current_read_index); |
| } |
| static DEVICE_ATTR_RO(in_read_index); |
| @@ -405,12 +427,15 @@ static ssize_t in_write_index_show(struc |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info inbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + if (ret < 0) |
| + return ret; |
| + |
| return sprintf(buf, "%d\n", inbound.current_write_index); |
| } |
| static DEVICE_ATTR_RO(in_write_index); |
| @@ -421,12 +446,15 @@ static ssize_t in_read_bytes_avail_show( |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info inbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + if (ret < 0) |
| + return ret; |
| + |
| return sprintf(buf, "%d\n", inbound.bytes_avail_toread); |
| } |
| static DEVICE_ATTR_RO(in_read_bytes_avail); |
| @@ -437,12 +465,15 @@ static ssize_t in_write_bytes_avail_show |
| { |
| struct hv_device *hv_dev = device_to_hv_device(dev); |
| struct hv_ring_buffer_debug_info inbound; |
| + int ret; |
| |
| if (!hv_dev->channel) |
| return -ENODEV; |
| - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) |
| - return -EINVAL; |
| - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + |
| + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
| + if (ret < 0) |
| + return ret; |
| + |
| return sprintf(buf, "%d\n", inbound.bytes_avail_towrite); |
| } |
| static DEVICE_ATTR_RO(in_write_bytes_avail); |
| --- a/include/linux/hyperv.h |
| +++ b/include/linux/hyperv.h |
| @@ -1130,8 +1130,9 @@ struct hv_ring_buffer_debug_info { |
| u32 bytes_avail_towrite; |
| }; |
| |
| -void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, |
| - struct hv_ring_buffer_debug_info *debug_info); |
| + |
| +int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, |
| + struct hv_ring_buffer_debug_info *debug_info); |
| |
| /* Vmbus interface */ |
| #define vmbus_driver_register(driver) \ |