mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-21 10:01:00 +00:00
5d39cd2059
[ Upstream commitbaaf965f94
] The following KASAN BUG is observed when testing the rpc-if driver on rcar-gen3: root@rcar-gen3:~# modprobe -r rpc-if [ 101.930146] ================================================================== [ 101.937408] BUG: KASAN: slab-out-of-bounds in __lock_acquire+0x518/0x25d0 [ 101.944240] Read of size 8 at addr ffff0004c5be2750 by task modprobe/664 [ 101.950959] [ 101.952466] CPU: 2 PID: 664 Comm: modprobe Not tainted 5.14.0-rc1-00342-g1a1464d7aa31 #1 [ 101.960578] Hardware name: Renesas H3ULCB board based on r8a77951 (DT) [ 101.967120] Call trace: [ 101.969580] dump_backtrace+0x0/0x2c0 [ 101.973275] show_stack+0x1c/0x30 [ 101.976616] dump_stack_lvl+0x9c/0xd8 [ 101.980301] print_address_description.constprop.0+0x74/0x2b8 [ 101.986071] kasan_report+0x1f4/0x26c [ 101.989757] __asan_load8+0x98/0xd4 [ 101.993266] __lock_acquire+0x518/0x25d0 [ 101.997215] lock_acquire.part.0+0x18c/0x360 [ 102.001506] lock_acquire+0x74/0x90 [ 102.005013] _raw_spin_lock_irq+0x98/0x130 [ 102.009131] __pm_runtime_disable+0x30/0x210 [ 102.013427] rpcif_hb_remove+0x5c/0x70 [rpc_if] [ 102.018001] platform_remove+0x40/0x80 [ 102.021771] __device_release_driver+0x234/0x350 [ 102.026412] driver_detach+0x158/0x20c [ 102.030179] bus_remove_driver+0xa0/0x140 [ 102.034212] driver_unregister+0x48/0x80 [ 102.038153] platform_driver_unregister+0x18/0x24 [ 102.042879] rpcif_platform_driver_exit+0x1c/0x34 [rpc_if] [ 102.048400] __arm64_sys_delete_module+0x210/0x310 [ 102.053212] invoke_syscall+0x60/0x190 [ 102.056986] el0_svc_common+0x12c/0x144 [ 102.060844] do_el0_svc+0x88/0xac [ 102.064181] el0_svc+0x24/0x3c [ 102.067257] el0t_64_sync_handler+0x1a8/0x1b0 [ 102.071634] el0t_64_sync+0x198/0x19c [ 102.075315] [ 102.076815] Allocated by task 628: [ 102.080781] [ 102.082280] Last potentially related work creation: [ 102.087524] [ 102.089022] The buggy address belongs to the object at ffff0004c5be2000 [ 102.089022] which belongs to the cache kmalloc-2k of size 2048 [ 102.101555] The buggy address is located 1872 bytes inside of [ 102.101555] 2048-byte region [ffff0004c5be2000, ffff0004c5be2800) [ 102.113486] The buggy address belongs to the page: [ 102.118409] [ 102.119908] Memory state around the buggy address: [ 102.124711] ffff0004c5be2600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.131947] ffff0004c5be2680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.139181] >ffff0004c5be2700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.146412] ^ [ 102.152257] ffff0004c5be2780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.159491] ffff0004c5be2800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.166723] ================================================================== The above bug is caused by use of the wrong pointer in the rpcif_disable_rpm() call. Fix the bug by using the correct pointer. Fixes:5de15b610f
("mtd: hyperbus: add Renesas RPC-IF driver") Signed-off-by: George G. Davis <davis.george@siemens.com> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Link: https://lore.kernel.org/r/20210716204935.25859-1-george_davis@mentor.com Signed-off-by: Sasha Levin <sashal@kernel.org>
172 lines
3.8 KiB
C
172 lines
3.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Linux driver for RPC-IF HyperFlash
|
|
*
|
|
* Copyright (C) 2019-2020 Cogent Embedded, Inc.
|
|
*/
|
|
|
|
#include <linux/err.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mtd/hyperbus.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mux/consumer.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/types.h>
|
|
|
|
#include <memory/renesas-rpc-if.h>
|
|
|
|
struct rpcif_hyperbus {
|
|
struct rpcif rpc;
|
|
struct hyperbus_ctlr ctlr;
|
|
struct hyperbus_device hbdev;
|
|
};
|
|
|
|
static const struct rpcif_op rpcif_op_tmpl = {
|
|
.cmd = {
|
|
.buswidth = 8,
|
|
.ddr = true,
|
|
},
|
|
.ocmd = {
|
|
.buswidth = 8,
|
|
.ddr = true,
|
|
},
|
|
.addr = {
|
|
.nbytes = 1,
|
|
.buswidth = 8,
|
|
.ddr = true,
|
|
},
|
|
.data = {
|
|
.buswidth = 8,
|
|
.ddr = true,
|
|
},
|
|
};
|
|
|
|
static void rpcif_hb_prepare_read(struct rpcif *rpc, void *to,
|
|
unsigned long from, ssize_t len)
|
|
{
|
|
struct rpcif_op op = rpcif_op_tmpl;
|
|
|
|
op.cmd.opcode = HYPERBUS_RW_READ | HYPERBUS_AS_MEM;
|
|
op.addr.val = from >> 1;
|
|
op.dummy.buswidth = 1;
|
|
op.dummy.ncycles = 15;
|
|
op.data.dir = RPCIF_DATA_IN;
|
|
op.data.nbytes = len;
|
|
op.data.buf.in = to;
|
|
|
|
rpcif_prepare(rpc, &op, NULL, NULL);
|
|
}
|
|
|
|
static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to,
|
|
void *from, ssize_t len)
|
|
{
|
|
struct rpcif_op op = rpcif_op_tmpl;
|
|
|
|
op.cmd.opcode = HYPERBUS_RW_WRITE | HYPERBUS_AS_MEM;
|
|
op.addr.val = to >> 1;
|
|
op.data.dir = RPCIF_DATA_OUT;
|
|
op.data.nbytes = len;
|
|
op.data.buf.out = from;
|
|
|
|
rpcif_prepare(rpc, &op, NULL, NULL);
|
|
}
|
|
|
|
static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr)
|
|
{
|
|
struct rpcif_hyperbus *hyperbus =
|
|
container_of(hbdev, struct rpcif_hyperbus, hbdev);
|
|
map_word data;
|
|
|
|
rpcif_hb_prepare_read(&hyperbus->rpc, &data, addr, 2);
|
|
|
|
rpcif_manual_xfer(&hyperbus->rpc);
|
|
|
|
return data.x[0];
|
|
}
|
|
|
|
static void rpcif_hb_write16(struct hyperbus_device *hbdev, unsigned long addr,
|
|
u16 data)
|
|
{
|
|
struct rpcif_hyperbus *hyperbus =
|
|
container_of(hbdev, struct rpcif_hyperbus, hbdev);
|
|
|
|
rpcif_hb_prepare_write(&hyperbus->rpc, addr, &data, 2);
|
|
|
|
rpcif_manual_xfer(&hyperbus->rpc);
|
|
}
|
|
|
|
static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to,
|
|
unsigned long from, ssize_t len)
|
|
{
|
|
struct rpcif_hyperbus *hyperbus =
|
|
container_of(hbdev, struct rpcif_hyperbus, hbdev);
|
|
|
|
rpcif_hb_prepare_read(&hyperbus->rpc, to, from, len);
|
|
|
|
rpcif_dirmap_read(&hyperbus->rpc, from, len, to);
|
|
}
|
|
|
|
static const struct hyperbus_ops rpcif_hb_ops = {
|
|
.read16 = rpcif_hb_read16,
|
|
.write16 = rpcif_hb_write16,
|
|
.copy_from = rpcif_hb_copy_from,
|
|
};
|
|
|
|
static int rpcif_hb_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct rpcif_hyperbus *hyperbus;
|
|
int error;
|
|
|
|
hyperbus = devm_kzalloc(dev, sizeof(*hyperbus), GFP_KERNEL);
|
|
if (!hyperbus)
|
|
return -ENOMEM;
|
|
|
|
error = rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent);
|
|
if (error)
|
|
return error;
|
|
|
|
platform_set_drvdata(pdev, hyperbus);
|
|
|
|
rpcif_enable_rpm(&hyperbus->rpc);
|
|
|
|
rpcif_hw_init(&hyperbus->rpc, true);
|
|
|
|
hyperbus->hbdev.map.size = hyperbus->rpc.size;
|
|
hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
|
|
|
|
hyperbus->ctlr.dev = dev;
|
|
hyperbus->ctlr.ops = &rpcif_hb_ops;
|
|
hyperbus->hbdev.ctlr = &hyperbus->ctlr;
|
|
hyperbus->hbdev.np = of_get_next_child(pdev->dev.parent->of_node, NULL);
|
|
error = hyperbus_register_device(&hyperbus->hbdev);
|
|
if (error)
|
|
rpcif_disable_rpm(&hyperbus->rpc);
|
|
|
|
return error;
|
|
}
|
|
|
|
static int rpcif_hb_remove(struct platform_device *pdev)
|
|
{
|
|
struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev);
|
|
int error = hyperbus_unregister_device(&hyperbus->hbdev);
|
|
|
|
rpcif_disable_rpm(&hyperbus->rpc);
|
|
|
|
return error;
|
|
}
|
|
|
|
static struct platform_driver rpcif_platform_driver = {
|
|
.probe = rpcif_hb_probe,
|
|
.remove = rpcif_hb_remove,
|
|
.driver = {
|
|
.name = "rpc-if-hyperflash",
|
|
},
|
|
};
|
|
|
|
module_platform_driver(rpcif_platform_driver);
|
|
|
|
MODULE_DESCRIPTION("Renesas RPC-IF HyperFlash driver");
|
|
MODULE_LICENSE("GPL v2");
|