Commit 7e66208d authored by Dexuan Cui's avatar Dexuan Cui Committed by Greg Kroah-Hartman

Drivers: hv: vmbus: Check for ring when getting debug info

commit ba50bf1c upstream.

fc96df16 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: fc96df16 ("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: 's avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: 's avatarDexuan Cui <decui@microsoft.com>
Signed-off-by: 's avatarSasha Levin <sashal@kernel.org>
Signed-off-by: 's avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cdc5dc5b
...@@ -164,26 +164,25 @@ hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi, ...@@ -164,26 +164,25 @@ hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi,
} }
/* Get various debug metrics for the specified ring buffer. */ /* Get various debug metrics for the specified ring buffer. */
void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info) struct hv_ring_buffer_debug_info *debug_info)
{ {
u32 bytes_avail_towrite; u32 bytes_avail_towrite;
u32 bytes_avail_toread; u32 bytes_avail_toread;
if (ring_info->ring_buffer) { if (!ring_info->ring_buffer)
hv_get_ringbuffer_availbytes(ring_info, return -EINVAL;
&bytes_avail_toread,
&bytes_avail_towrite); hv_get_ringbuffer_availbytes(ring_info,
&bytes_avail_toread,
debug_info->bytes_avail_toread = bytes_avail_toread; &bytes_avail_towrite);
debug_info->bytes_avail_towrite = bytes_avail_towrite; debug_info->bytes_avail_toread = bytes_avail_toread;
debug_info->current_read_index = debug_info->bytes_avail_towrite = bytes_avail_towrite;
ring_info->ring_buffer->read_index; debug_info->current_read_index = ring_info->ring_buffer->read_index;
debug_info->current_write_index = debug_info->current_write_index = ring_info->ring_buffer->write_index;
ring_info->ring_buffer->write_index; debug_info->current_interrupt_mask
debug_info->current_interrupt_mask = = ring_info->ring_buffer->interrupt_mask;
ring_info->ring_buffer->interrupt_mask; return 0;
}
} }
EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo);
......
...@@ -313,12 +313,16 @@ static ssize_t out_intr_mask_show(struct device *dev, ...@@ -313,12 +313,16 @@ static ssize_t out_intr_mask_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info outbound; struct hv_ring_buffer_debug_info outbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); &outbound);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", outbound.current_interrupt_mask); return sprintf(buf, "%d\n", outbound.current_interrupt_mask);
} }
static DEVICE_ATTR_RO(out_intr_mask); static DEVICE_ATTR_RO(out_intr_mask);
...@@ -328,12 +332,15 @@ static ssize_t out_read_index_show(struct device *dev, ...@@ -328,12 +332,15 @@ static ssize_t out_read_index_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info outbound; struct hv_ring_buffer_debug_info outbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); &outbound);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", outbound.current_read_index); return sprintf(buf, "%d\n", outbound.current_read_index);
} }
static DEVICE_ATTR_RO(out_read_index); static DEVICE_ATTR_RO(out_read_index);
...@@ -344,12 +351,15 @@ static ssize_t out_write_index_show(struct device *dev, ...@@ -344,12 +351,15 @@ static ssize_t out_write_index_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info outbound; struct hv_ring_buffer_debug_info outbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); &outbound);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", outbound.current_write_index); return sprintf(buf, "%d\n", outbound.current_write_index);
} }
static DEVICE_ATTR_RO(out_write_index); static DEVICE_ATTR_RO(out_write_index);
...@@ -360,12 +370,15 @@ static ssize_t out_read_bytes_avail_show(struct device *dev, ...@@ -360,12 +370,15 @@ static ssize_t out_read_bytes_avail_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info outbound; struct hv_ring_buffer_debug_info outbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); &outbound);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", outbound.bytes_avail_toread); return sprintf(buf, "%d\n", outbound.bytes_avail_toread);
} }
static DEVICE_ATTR_RO(out_read_bytes_avail); static DEVICE_ATTR_RO(out_read_bytes_avail);
...@@ -376,12 +389,15 @@ static ssize_t out_write_bytes_avail_show(struct device *dev, ...@@ -376,12 +389,15 @@ static ssize_t out_write_bytes_avail_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info outbound; struct hv_ring_buffer_debug_info outbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); &outbound);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", outbound.bytes_avail_towrite); return sprintf(buf, "%d\n", outbound.bytes_avail_towrite);
} }
static DEVICE_ATTR_RO(out_write_bytes_avail); static DEVICE_ATTR_RO(out_write_bytes_avail);
...@@ -391,12 +407,15 @@ static ssize_t in_intr_mask_show(struct device *dev, ...@@ -391,12 +407,15 @@ static ssize_t in_intr_mask_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info inbound; struct hv_ring_buffer_debug_info inbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); if (ret < 0)
return ret;
return sprintf(buf, "%d\n", inbound.current_interrupt_mask); return sprintf(buf, "%d\n", inbound.current_interrupt_mask);
} }
static DEVICE_ATTR_RO(in_intr_mask); static DEVICE_ATTR_RO(in_intr_mask);
...@@ -406,12 +425,15 @@ static ssize_t in_read_index_show(struct device *dev, ...@@ -406,12 +425,15 @@ static ssize_t in_read_index_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info inbound; struct hv_ring_buffer_debug_info inbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); if (ret < 0)
return ret;
return sprintf(buf, "%d\n", inbound.current_read_index); return sprintf(buf, "%d\n", inbound.current_read_index);
} }
static DEVICE_ATTR_RO(in_read_index); static DEVICE_ATTR_RO(in_read_index);
...@@ -421,12 +443,15 @@ static ssize_t in_write_index_show(struct device *dev, ...@@ -421,12 +443,15 @@ static ssize_t in_write_index_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info inbound; struct hv_ring_buffer_debug_info inbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); if (ret < 0)
return ret;
return sprintf(buf, "%d\n", inbound.current_write_index); return sprintf(buf, "%d\n", inbound.current_write_index);
} }
static DEVICE_ATTR_RO(in_write_index); static DEVICE_ATTR_RO(in_write_index);
...@@ -437,12 +462,15 @@ static ssize_t in_read_bytes_avail_show(struct device *dev, ...@@ -437,12 +462,15 @@ static ssize_t in_read_bytes_avail_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info inbound; struct hv_ring_buffer_debug_info inbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); if (ret < 0)
return ret;
return sprintf(buf, "%d\n", inbound.bytes_avail_toread); return sprintf(buf, "%d\n", inbound.bytes_avail_toread);
} }
static DEVICE_ATTR_RO(in_read_bytes_avail); static DEVICE_ATTR_RO(in_read_bytes_avail);
...@@ -453,12 +481,15 @@ static ssize_t in_write_bytes_avail_show(struct device *dev, ...@@ -453,12 +481,15 @@ static ssize_t in_write_bytes_avail_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_device *hv_dev = device_to_hv_device(dev);
struct hv_ring_buffer_debug_info inbound; struct hv_ring_buffer_debug_info inbound;
int ret;
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
return -EINVAL; ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); if (ret < 0)
return ret;
return sprintf(buf, "%d\n", inbound.bytes_avail_towrite); return sprintf(buf, "%d\n", inbound.bytes_avail_towrite);
} }
static DEVICE_ATTR_RO(in_write_bytes_avail); static DEVICE_ATTR_RO(in_write_bytes_avail);
......
...@@ -1176,8 +1176,9 @@ struct hv_ring_buffer_debug_info { ...@@ -1176,8 +1176,9 @@ struct hv_ring_buffer_debug_info {
u32 bytes_avail_towrite; 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 */ /* Vmbus interface */
#define vmbus_driver_register(driver) \ #define vmbus_driver_register(driver) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment