| From ee7a762c5ffda299f228b85544545489cc30e3fd Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 10 Jul 2020 16:41:39 +0300 |
| Subject: mlxsw: pci: Fix use-after-free in case of failed devlink reload |
| |
| From: Ido Schimmel <idosch@mellanox.com> |
| |
| [ Upstream commit c4317b11675b99af6641662ebcbd3c6010600e64 ] |
| |
| In case devlink reload failed, it is possible to trigger a |
| use-after-free when querying the kernel for device info via 'devlink dev |
| info' [1]. |
| |
| This happens because as part of the reload error path the PCI command |
| interface is de-initialized and its mailboxes are freed. When the |
| devlink '->info_get()' callback is invoked the device is queried via the |
| command interface and the freed mailboxes are accessed. |
| |
| Fix this by initializing the command interface once during probe and not |
| during every reload. |
| |
| This is consistent with the other bus used by mlxsw (i.e., 'mlxsw_i2c') |
| and also allows user space to query the running firmware version (for |
| example) from the device after a failed reload. |
| |
| [1] |
| BUG: KASAN: use-after-free in memcpy include/linux/string.h:406 [inline] |
| BUG: KASAN: use-after-free in mlxsw_pci_cmd_exec+0x177/0xa60 drivers/net/ethernet/mellanox/mlxsw/pci.c:1675 |
| Write of size 4096 at addr ffff88810ae32000 by task syz-executor.1/2355 |
| |
| CPU: 1 PID: 2355 Comm: syz-executor.1 Not tainted 5.8.0-rc2+ #29 |
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 |
| Call Trace: |
| __dump_stack lib/dump_stack.c:77 [inline] |
| dump_stack+0xf6/0x16e lib/dump_stack.c:118 |
| print_address_description.constprop.0+0x1c/0x250 mm/kasan/report.c:383 |
| __kasan_report mm/kasan/report.c:513 [inline] |
| kasan_report.cold+0x1f/0x37 mm/kasan/report.c:530 |
| check_memory_region_inline mm/kasan/generic.c:186 [inline] |
| check_memory_region+0x14e/0x1b0 mm/kasan/generic.c:192 |
| memcpy+0x39/0x60 mm/kasan/common.c:106 |
| memcpy include/linux/string.h:406 [inline] |
| mlxsw_pci_cmd_exec+0x177/0xa60 drivers/net/ethernet/mellanox/mlxsw/pci.c:1675 |
| mlxsw_cmd_exec+0x249/0x550 drivers/net/ethernet/mellanox/mlxsw/core.c:2335 |
| mlxsw_cmd_access_reg drivers/net/ethernet/mellanox/mlxsw/cmd.h:859 [inline] |
| mlxsw_core_reg_access_cmd drivers/net/ethernet/mellanox/mlxsw/core.c:1938 [inline] |
| mlxsw_core_reg_access+0x2f6/0x540 drivers/net/ethernet/mellanox/mlxsw/core.c:1985 |
| mlxsw_reg_query drivers/net/ethernet/mellanox/mlxsw/core.c:2000 [inline] |
| mlxsw_devlink_info_get+0x17f/0x6e0 drivers/net/ethernet/mellanox/mlxsw/core.c:1090 |
| devlink_nl_info_fill.constprop.0+0x13c/0x2d0 net/core/devlink.c:4588 |
| devlink_nl_cmd_info_get_dumpit+0x246/0x460 net/core/devlink.c:4648 |
| genl_lock_dumpit+0x85/0xc0 net/netlink/genetlink.c:575 |
| netlink_dump+0x515/0xe50 net/netlink/af_netlink.c:2245 |
| __netlink_dump_start+0x53d/0x830 net/netlink/af_netlink.c:2353 |
| genl_family_rcv_msg_dumpit.isra.0+0x296/0x300 net/netlink/genetlink.c:638 |
| genl_family_rcv_msg net/netlink/genetlink.c:733 [inline] |
| genl_rcv_msg+0x78d/0x9d0 net/netlink/genetlink.c:753 |
| netlink_rcv_skb+0x152/0x440 net/netlink/af_netlink.c:2469 |
| genl_rcv+0x24/0x40 net/netlink/genetlink.c:764 |
| netlink_unicast_kernel net/netlink/af_netlink.c:1303 [inline] |
| netlink_unicast+0x53a/0x750 net/netlink/af_netlink.c:1329 |
| netlink_sendmsg+0x850/0xd90 net/netlink/af_netlink.c:1918 |
| sock_sendmsg_nosec net/socket.c:652 [inline] |
| sock_sendmsg+0x150/0x190 net/socket.c:672 |
| ____sys_sendmsg+0x6d8/0x840 net/socket.c:2363 |
| ___sys_sendmsg+0xff/0x170 net/socket.c:2417 |
| __sys_sendmsg+0xe5/0x1b0 net/socket.c:2450 |
| do_syscall_64+0x56/0xa0 arch/x86/entry/common.c:359 |
| entry_SYSCALL_64_after_hwframe+0x44/0xa9 |
| |
| Fixes: a9c8336f6544 ("mlxsw: core: Add support for devlink info command") |
| Signed-off-by: Ido Schimmel <idosch@mellanox.com> |
| Reviewed-by: Jiri Pirko <jiri@mellanox.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/mellanox/mlxsw/pci.c | 54 ++++++++++++++++------- |
| 1 file changed, 38 insertions(+), 16 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c |
| index f3d1f9411d104..aa4fef7890841 100644 |
| --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c |
| +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c |
| @@ -1401,23 +1401,12 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, |
| u16 num_pages; |
| int err; |
| |
| - mutex_init(&mlxsw_pci->cmd.lock); |
| - init_waitqueue_head(&mlxsw_pci->cmd.wait); |
| - |
| mlxsw_pci->core = mlxsw_core; |
| |
| mbox = mlxsw_cmd_mbox_alloc(); |
| if (!mbox) |
| return -ENOMEM; |
| |
| - err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
| - if (err) |
| - goto mbox_put; |
| - |
| - err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
| - if (err) |
| - goto err_out_mbox_alloc; |
| - |
| err = mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id); |
| if (err) |
| goto err_sw_reset; |
| @@ -1524,9 +1513,6 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, |
| mlxsw_pci_free_irq_vectors(mlxsw_pci); |
| err_alloc_irq: |
| err_sw_reset: |
| - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
| -err_out_mbox_alloc: |
| - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
| mbox_put: |
| mlxsw_cmd_mbox_free(mbox); |
| return err; |
| @@ -1540,8 +1526,6 @@ static void mlxsw_pci_fini(void *bus_priv) |
| mlxsw_pci_aqs_fini(mlxsw_pci); |
| mlxsw_pci_fw_area_fini(mlxsw_pci); |
| mlxsw_pci_free_irq_vectors(mlxsw_pci); |
| - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
| - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
| } |
| |
| static struct mlxsw_pci_queue * |
| @@ -1755,6 +1739,37 @@ static const struct mlxsw_bus mlxsw_pci_bus = { |
| .features = MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET, |
| }; |
| |
| +static int mlxsw_pci_cmd_init(struct mlxsw_pci *mlxsw_pci) |
| +{ |
| + int err; |
| + |
| + mutex_init(&mlxsw_pci->cmd.lock); |
| + init_waitqueue_head(&mlxsw_pci->cmd.wait); |
| + |
| + err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
| + if (err) |
| + goto err_in_mbox_alloc; |
| + |
| + err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
| + if (err) |
| + goto err_out_mbox_alloc; |
| + |
| + return 0; |
| + |
| +err_out_mbox_alloc: |
| + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
| +err_in_mbox_alloc: |
| + mutex_destroy(&mlxsw_pci->cmd.lock); |
| + return err; |
| +} |
| + |
| +static void mlxsw_pci_cmd_fini(struct mlxsw_pci *mlxsw_pci) |
| +{ |
| + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
| + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
| + mutex_destroy(&mlxsw_pci->cmd.lock); |
| +} |
| + |
| static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| { |
| const char *driver_name = pdev->driver->name; |
| @@ -1810,6 +1825,10 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| mlxsw_pci->pdev = pdev; |
| pci_set_drvdata(pdev, mlxsw_pci); |
| |
| + err = mlxsw_pci_cmd_init(mlxsw_pci); |
| + if (err) |
| + goto err_pci_cmd_init; |
| + |
| mlxsw_pci->bus_info.device_kind = driver_name; |
| mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); |
| mlxsw_pci->bus_info.dev = &pdev->dev; |
| @@ -1827,6 +1846,8 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| return 0; |
| |
| err_bus_device_register: |
| + mlxsw_pci_cmd_fini(mlxsw_pci); |
| +err_pci_cmd_init: |
| iounmap(mlxsw_pci->hw_addr); |
| err_ioremap: |
| err_pci_resource_len_check: |
| @@ -1844,6 +1865,7 @@ static void mlxsw_pci_remove(struct pci_dev *pdev) |
| struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); |
| |
| mlxsw_core_bus_device_unregister(mlxsw_pci->core, false); |
| + mlxsw_pci_cmd_fini(mlxsw_pci); |
| iounmap(mlxsw_pci->hw_addr); |
| pci_release_regions(mlxsw_pci->pdev); |
| pci_disable_device(mlxsw_pci->pdev); |
| -- |
| 2.25.1 |
| |