diff options
author | Dexuan Cui <decui@microsoft.com> | 2018-12-17 15:16:09 -0500 |
---|---|---|
committer | Sasha Levin <sashal@kernel.org> | 2019-01-09 14:20:47 -0500 |
commit | ba50bf1ce9a51fc97db58b96d01306aa70bc3979 (patch) | |
tree | e43d0dce0b0db7d34d931254351210ab1a4e2fc1 /drivers/hv | |
parent | bfeffd155283772bbe78c6a05dec7c0128ee500c (diff) |
Drivers: hv: vmbus: Check for ring when getting debug info
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>
Diffstat (limited to 'drivers/hv')
-rw-r--r-- | drivers/hv/ring_buffer.c | 31 | ||||
-rw-r--r-- | drivers/hv/vmbus_drv.c | 91 |
2 files changed, 76 insertions, 46 deletions
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 64d0c85d5161..1f1a55e07733 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c | |||
@@ -164,26 +164,25 @@ hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi, | |||
164 | } | 164 | } |
165 | 165 | ||
166 | /* Get various debug metrics for the specified ring buffer. */ | 166 | /* Get various debug metrics for the specified ring buffer. */ |
167 | void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, | 167 | int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, |
168 | struct hv_ring_buffer_debug_info *debug_info) | 168 | struct hv_ring_buffer_debug_info *debug_info) |
169 | { | 169 | { |
170 | u32 bytes_avail_towrite; | 170 | u32 bytes_avail_towrite; |
171 | u32 bytes_avail_toread; | 171 | u32 bytes_avail_toread; |
172 | 172 | ||
173 | if (ring_info->ring_buffer) { | 173 | if (!ring_info->ring_buffer) |
174 | hv_get_ringbuffer_availbytes(ring_info, | 174 | return -EINVAL; |
175 | &bytes_avail_toread, | 175 | |
176 | &bytes_avail_towrite); | 176 | hv_get_ringbuffer_availbytes(ring_info, |
177 | 177 | &bytes_avail_toread, | |
178 | debug_info->bytes_avail_toread = bytes_avail_toread; | 178 | &bytes_avail_towrite); |
179 | debug_info->bytes_avail_towrite = bytes_avail_towrite; | 179 | debug_info->bytes_avail_toread = bytes_avail_toread; |
180 | debug_info->current_read_index = | 180 | debug_info->bytes_avail_towrite = bytes_avail_towrite; |
181 | ring_info->ring_buffer->read_index; | 181 | debug_info->current_read_index = ring_info->ring_buffer->read_index; |
182 | debug_info->current_write_index = | 182 | debug_info->current_write_index = ring_info->ring_buffer->write_index; |
183 | ring_info->ring_buffer->write_index; | 183 | debug_info->current_interrupt_mask |
184 | debug_info->current_interrupt_mask = | 184 | = ring_info->ring_buffer->interrupt_mask; |
185 | ring_info->ring_buffer->interrupt_mask; | 185 | return 0; |
186 | } | ||
187 | } | 186 | } |
188 | EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); | 187 | EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); |
189 | 188 | ||
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index d0ff65675292..403fee01572c 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
@@ -313,12 +313,16 @@ static ssize_t out_intr_mask_show(struct device *dev, | |||
313 | { | 313 | { |
314 | struct hv_device *hv_dev = device_to_hv_device(dev); | 314 | struct hv_device *hv_dev = device_to_hv_device(dev); |
315 | struct hv_ring_buffer_debug_info outbound; | 315 | struct hv_ring_buffer_debug_info outbound; |
316 | int ret; | ||
316 | 317 | ||
317 | if (!hv_dev->channel) | 318 | if (!hv_dev->channel) |
318 | return -ENODEV; | 319 | return -ENODEV; |
319 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 320 | |
320 | return -EINVAL; | 321 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
321 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | 322 | &outbound); |
323 | if (ret < 0) | ||
324 | return ret; | ||
325 | |||
322 | return sprintf(buf, "%d\n", outbound.current_interrupt_mask); | 326 | return sprintf(buf, "%d\n", outbound.current_interrupt_mask); |
323 | } | 327 | } |
324 | static DEVICE_ATTR_RO(out_intr_mask); | 328 | static DEVICE_ATTR_RO(out_intr_mask); |
@@ -328,12 +332,15 @@ static ssize_t out_read_index_show(struct device *dev, | |||
328 | { | 332 | { |
329 | struct hv_device *hv_dev = device_to_hv_device(dev); | 333 | struct hv_device *hv_dev = device_to_hv_device(dev); |
330 | struct hv_ring_buffer_debug_info outbound; | 334 | struct hv_ring_buffer_debug_info outbound; |
335 | int ret; | ||
331 | 336 | ||
332 | if (!hv_dev->channel) | 337 | if (!hv_dev->channel) |
333 | return -ENODEV; | 338 | return -ENODEV; |
334 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 339 | |
335 | return -EINVAL; | 340 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
336 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | 341 | &outbound); |
342 | if (ret < 0) | ||
343 | return ret; | ||
337 | return sprintf(buf, "%d\n", outbound.current_read_index); | 344 | return sprintf(buf, "%d\n", outbound.current_read_index); |
338 | } | 345 | } |
339 | static DEVICE_ATTR_RO(out_read_index); | 346 | static DEVICE_ATTR_RO(out_read_index); |
@@ -344,12 +351,15 @@ static ssize_t out_write_index_show(struct device *dev, | |||
344 | { | 351 | { |
345 | struct hv_device *hv_dev = device_to_hv_device(dev); | 352 | struct hv_device *hv_dev = device_to_hv_device(dev); |
346 | struct hv_ring_buffer_debug_info outbound; | 353 | struct hv_ring_buffer_debug_info outbound; |
354 | int ret; | ||
347 | 355 | ||
348 | if (!hv_dev->channel) | 356 | if (!hv_dev->channel) |
349 | return -ENODEV; | 357 | return -ENODEV; |
350 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 358 | |
351 | return -EINVAL; | 359 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
352 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | 360 | &outbound); |
361 | if (ret < 0) | ||
362 | return ret; | ||
353 | return sprintf(buf, "%d\n", outbound.current_write_index); | 363 | return sprintf(buf, "%d\n", outbound.current_write_index); |
354 | } | 364 | } |
355 | static DEVICE_ATTR_RO(out_write_index); | 365 | static DEVICE_ATTR_RO(out_write_index); |
@@ -360,12 +370,15 @@ static ssize_t out_read_bytes_avail_show(struct device *dev, | |||
360 | { | 370 | { |
361 | struct hv_device *hv_dev = device_to_hv_device(dev); | 371 | struct hv_device *hv_dev = device_to_hv_device(dev); |
362 | struct hv_ring_buffer_debug_info outbound; | 372 | struct hv_ring_buffer_debug_info outbound; |
373 | int ret; | ||
363 | 374 | ||
364 | if (!hv_dev->channel) | 375 | if (!hv_dev->channel) |
365 | return -ENODEV; | 376 | return -ENODEV; |
366 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 377 | |
367 | return -EINVAL; | 378 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
368 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | 379 | &outbound); |
380 | if (ret < 0) | ||
381 | return ret; | ||
369 | return sprintf(buf, "%d\n", outbound.bytes_avail_toread); | 382 | return sprintf(buf, "%d\n", outbound.bytes_avail_toread); |
370 | } | 383 | } |
371 | static DEVICE_ATTR_RO(out_read_bytes_avail); | 384 | static DEVICE_ATTR_RO(out_read_bytes_avail); |
@@ -376,12 +389,15 @@ static ssize_t out_write_bytes_avail_show(struct device *dev, | |||
376 | { | 389 | { |
377 | struct hv_device *hv_dev = device_to_hv_device(dev); | 390 | struct hv_device *hv_dev = device_to_hv_device(dev); |
378 | struct hv_ring_buffer_debug_info outbound; | 391 | struct hv_ring_buffer_debug_info outbound; |
392 | int ret; | ||
379 | 393 | ||
380 | if (!hv_dev->channel) | 394 | if (!hv_dev->channel) |
381 | return -ENODEV; | 395 | return -ENODEV; |
382 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 396 | |
383 | return -EINVAL; | 397 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, |
384 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | 398 | &outbound); |
399 | if (ret < 0) | ||
400 | return ret; | ||
385 | return sprintf(buf, "%d\n", outbound.bytes_avail_towrite); | 401 | return sprintf(buf, "%d\n", outbound.bytes_avail_towrite); |
386 | } | 402 | } |
387 | static DEVICE_ATTR_RO(out_write_bytes_avail); | 403 | static DEVICE_ATTR_RO(out_write_bytes_avail); |
@@ -391,12 +407,15 @@ static ssize_t in_intr_mask_show(struct device *dev, | |||
391 | { | 407 | { |
392 | struct hv_device *hv_dev = device_to_hv_device(dev); | 408 | struct hv_device *hv_dev = device_to_hv_device(dev); |
393 | struct hv_ring_buffer_debug_info inbound; | 409 | struct hv_ring_buffer_debug_info inbound; |
410 | int ret; | ||
394 | 411 | ||
395 | if (!hv_dev->channel) | 412 | if (!hv_dev->channel) |
396 | return -ENODEV; | 413 | return -ENODEV; |
397 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 414 | |
398 | return -EINVAL; | 415 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
399 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | 416 | if (ret < 0) |
417 | return ret; | ||
418 | |||
400 | return sprintf(buf, "%d\n", inbound.current_interrupt_mask); | 419 | return sprintf(buf, "%d\n", inbound.current_interrupt_mask); |
401 | } | 420 | } |
402 | static DEVICE_ATTR_RO(in_intr_mask); | 421 | static DEVICE_ATTR_RO(in_intr_mask); |
@@ -406,12 +425,15 @@ static ssize_t in_read_index_show(struct device *dev, | |||
406 | { | 425 | { |
407 | struct hv_device *hv_dev = device_to_hv_device(dev); | 426 | struct hv_device *hv_dev = device_to_hv_device(dev); |
408 | struct hv_ring_buffer_debug_info inbound; | 427 | struct hv_ring_buffer_debug_info inbound; |
428 | int ret; | ||
409 | 429 | ||
410 | if (!hv_dev->channel) | 430 | if (!hv_dev->channel) |
411 | return -ENODEV; | 431 | return -ENODEV; |
412 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 432 | |
413 | return -EINVAL; | 433 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
414 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | 434 | if (ret < 0) |
435 | return ret; | ||
436 | |||
415 | return sprintf(buf, "%d\n", inbound.current_read_index); | 437 | return sprintf(buf, "%d\n", inbound.current_read_index); |
416 | } | 438 | } |
417 | static DEVICE_ATTR_RO(in_read_index); | 439 | static DEVICE_ATTR_RO(in_read_index); |
@@ -421,12 +443,15 @@ static ssize_t in_write_index_show(struct device *dev, | |||
421 | { | 443 | { |
422 | struct hv_device *hv_dev = device_to_hv_device(dev); | 444 | struct hv_device *hv_dev = device_to_hv_device(dev); |
423 | struct hv_ring_buffer_debug_info inbound; | 445 | struct hv_ring_buffer_debug_info inbound; |
446 | int ret; | ||
424 | 447 | ||
425 | if (!hv_dev->channel) | 448 | if (!hv_dev->channel) |
426 | return -ENODEV; | 449 | return -ENODEV; |
427 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 450 | |
428 | return -EINVAL; | 451 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
429 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | 452 | if (ret < 0) |
453 | return ret; | ||
454 | |||
430 | return sprintf(buf, "%d\n", inbound.current_write_index); | 455 | return sprintf(buf, "%d\n", inbound.current_write_index); |
431 | } | 456 | } |
432 | static DEVICE_ATTR_RO(in_write_index); | 457 | static DEVICE_ATTR_RO(in_write_index); |
@@ -437,12 +462,15 @@ static ssize_t in_read_bytes_avail_show(struct device *dev, | |||
437 | { | 462 | { |
438 | struct hv_device *hv_dev = device_to_hv_device(dev); | 463 | struct hv_device *hv_dev = device_to_hv_device(dev); |
439 | struct hv_ring_buffer_debug_info inbound; | 464 | struct hv_ring_buffer_debug_info inbound; |
465 | int ret; | ||
440 | 466 | ||
441 | if (!hv_dev->channel) | 467 | if (!hv_dev->channel) |
442 | return -ENODEV; | 468 | return -ENODEV; |
443 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 469 | |
444 | return -EINVAL; | 470 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
445 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | 471 | if (ret < 0) |
472 | return ret; | ||
473 | |||
446 | return sprintf(buf, "%d\n", inbound.bytes_avail_toread); | 474 | return sprintf(buf, "%d\n", inbound.bytes_avail_toread); |
447 | } | 475 | } |
448 | static DEVICE_ATTR_RO(in_read_bytes_avail); | 476 | static DEVICE_ATTR_RO(in_read_bytes_avail); |
@@ -453,12 +481,15 @@ static ssize_t in_write_bytes_avail_show(struct device *dev, | |||
453 | { | 481 | { |
454 | struct hv_device *hv_dev = device_to_hv_device(dev); | 482 | struct hv_device *hv_dev = device_to_hv_device(dev); |
455 | struct hv_ring_buffer_debug_info inbound; | 483 | struct hv_ring_buffer_debug_info inbound; |
484 | int ret; | ||
456 | 485 | ||
457 | if (!hv_dev->channel) | 486 | if (!hv_dev->channel) |
458 | return -ENODEV; | 487 | return -ENODEV; |
459 | if (hv_dev->channel->state != CHANNEL_OPENED_STATE) | 488 | |
460 | return -EINVAL; | 489 | ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); |
461 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | 490 | if (ret < 0) |
491 | return ret; | ||
492 | |||
462 | return sprintf(buf, "%d\n", inbound.bytes_avail_towrite); | 493 | return sprintf(buf, "%d\n", inbound.bytes_avail_towrite); |
463 | } | 494 | } |
464 | static DEVICE_ATTR_RO(in_write_bytes_avail); | 495 | static DEVICE_ATTR_RO(in_write_bytes_avail); |