Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sdio: deploy error handling instead of triggering BUG_ON

When using mmc_io_rw_extended, it's intent to avoid null
pointer of card and invalid func number. But actually it
didn't prevent that as the seg_size already use the card.
Currently the wrapper function sdio_io_rw_ext_helper already
use card before calling mmc_io_rw_extended, so we should move
this check to there. As to the func number, it was token from
'(ocr & 0x70000000) >> 28' which should be enough to guarantee
that it won't be larger than 7. But we should prevent the
caller like wifi drivers modify this value. So let's move this
check into sdio_io_rw_ext_helper either.

Also we remove the BUG_ON for mmc_send_io_op_cond since all
possible paths calling this function are protected by checking
the arguments in advance. After deploying these changes, we
could not see any panic within SDIO API even if func drivers
abuse the SDIO func APIs.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Shawn Lin and committed by
Ulf Hansson
923dff87 96e52daa

+33 -23
+31 -16
drivers/mmc/core/sdio_io.c
··· 26 26 */ 27 27 void sdio_claim_host(struct sdio_func *func) 28 28 { 29 - BUG_ON(!func); 30 - BUG_ON(!func->card); 29 + if (WARN_ON(!func)) 30 + return; 31 31 32 32 mmc_claim_host(func->card->host); 33 33 } ··· 42 42 */ 43 43 void sdio_release_host(struct sdio_func *func) 44 44 { 45 - BUG_ON(!func); 46 - BUG_ON(!func->card); 45 + if (WARN_ON(!func)) 46 + return; 47 47 48 48 mmc_release_host(func->card->host); 49 49 } ··· 62 62 unsigned char reg; 63 63 unsigned long timeout; 64 64 65 - BUG_ON(!func); 66 - BUG_ON(!func->card); 65 + if (!func) 66 + return -EINVAL; 67 67 68 68 pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func)); 69 69 ··· 112 112 int ret; 113 113 unsigned char reg; 114 114 115 - BUG_ON(!func); 116 - BUG_ON(!func->card); 115 + if (!func) 116 + return -EINVAL; 117 117 118 118 pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func)); 119 119 ··· 307 307 unsigned max_blocks; 308 308 int ret; 309 309 310 + if (!func || (func->num > 7)) 311 + return -EINVAL; 312 + 310 313 /* Do the bulk of the transfer using block mode (if supported). */ 311 314 if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) { 312 315 /* Blocks per command is limited by host count, host transfer ··· 370 367 int ret; 371 368 u8 val; 372 369 373 - BUG_ON(!func); 370 + if (!func) { 371 + *err_ret = -EINVAL; 372 + return 0xFF; 373 + } 374 374 375 375 if (err_ret) 376 376 *err_ret = 0; ··· 404 398 { 405 399 int ret; 406 400 407 - BUG_ON(!func); 401 + if (!func) { 402 + *err_ret = -EINVAL; 403 + return; 404 + } 408 405 409 406 ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL); 410 407 if (err_ret) ··· 632 623 int ret; 633 624 unsigned char val; 634 625 635 - BUG_ON(!func); 626 + if (!func) { 627 + *err_ret = -EINVAL; 628 + return 0xFF; 629 + } 636 630 637 631 if (err_ret) 638 632 *err_ret = 0; ··· 670 658 { 671 659 int ret; 672 660 673 - BUG_ON(!func); 661 + if (!func) { 662 + *err_ret = -EINVAL; 663 + return; 664 + } 674 665 675 666 if ((addr < 0xF0 || addr > 0xFF) && (!mmc_card_lenient_fn0(func->card))) { 676 667 if (err_ret) ··· 699 684 */ 700 685 mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func) 701 686 { 702 - BUG_ON(!func); 703 - BUG_ON(!func->card); 687 + if (!func) 688 + return 0; 704 689 705 690 return func->card->host->pm_caps; 706 691 } ··· 722 707 { 723 708 struct mmc_host *host; 724 709 725 - BUG_ON(!func); 726 - BUG_ON(!func->card); 710 + if (!func) 711 + return -EINVAL; 727 712 728 713 host = func->card->host; 729 714
+2 -7
drivers/mmc/core/sdio_ops.c
··· 24 24 struct mmc_command cmd = {0}; 25 25 int i, err = 0; 26 26 27 - BUG_ON(!host); 28 - 29 27 cmd.opcode = SD_IO_SEND_OP_COND; 30 28 cmd.arg = ocr; 31 29 cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR; ··· 69 71 struct mmc_command cmd = {0}; 70 72 int err; 71 73 72 - BUG_ON(!host); 73 - BUG_ON(fn > 7); 74 + if (fn > 7) 75 + return -EINVAL; 74 76 75 77 /* sanity check */ 76 78 if (addr & ~0x1FFFF) ··· 112 114 int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, 113 115 unsigned addr, u8 in, u8 *out) 114 116 { 115 - BUG_ON(!card); 116 117 return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out); 117 118 } 118 119 ··· 126 129 unsigned int nents, left_size, i; 127 130 unsigned int seg_size = card->host->max_seg_size; 128 131 129 - BUG_ON(!card); 130 - BUG_ON(fn > 7); 131 132 WARN_ON(blksz == 0); 132 133 133 134 /* sanity check */