[PATCH] regmap: mmio: Fix the bug of 'offset' value parsing.

From: Xiubo Li
Date: Mon Mar 31 2014 - 03:16:28 EST


'offset = *(u32 *)reg;', this will be okey for 32/64-bit register, but
for 8/16-bit register, the 'offset' value will overflow.

++++++++++++
XX_mmio_YY_write: ctx->regs = 0x888c0000, offset1 = *(u32 *)reg = 0x77310000
XX_mmio_YY_write: ctx->regs = 0x888c0000, offset2 = *(u16 *)reg = 0x0
XX_mmio_YY_write: ctx->regs + offset1 = 0xffbd0000 --> but should be 0x888c0000
-----------
The core trace:
===============
Unable to handle kernel paging request at virtual address ffbd0000
pgd = 871e8000
[ffbd0000] *pgd=00000000
Internal error: Oops: 805 [#1] ARM
Modules linked in:
CPU: 0 PID: 1004 Comm: sh Not tainted 3.14.0-rc6+ #990
task: 871baa40 ti: 87090000 task.ti: 87090000
PC is at regmap_mmio_gather_write.part.4+0xd0/0x16c
LR is at regmap_mmio_gather_write.part.4+0xc4/0x16c
pc : [<8049ecac>] lr : [<8049eca0>] psr: a0000093
sp : 87091c10 ip : 87091c10 fp : 87091c3c
r10: 87ac43c0 r9 : 00000001 r8 : 8075801c
r7 : 87ac43c2 r6 : 00000002 r5 : 77310000 r4 : 87ac4340
r3 : ffbd0000 r2 : 00007731 r1 : 00000000 r0 : 00000042
Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c53c7d Table: 871e8059 DAC: 00000015
Process sh (pid: 1004, stack limit = 0x87090238)
Stack: (0x87091c10 to 0x87092000)
1c00: 00000000 87091c20 87ac4340 87ac43c2
1c20: 87ac43c0 00000002 00000000 fffffdf4 87091c5c 87091c40 802992d0 8049ebe8
...
1fc0: 000af2ac 00000001 00000000 00000005 000af2ac 00000000 ffffffff 00000000
1fe0: 000ac7ac 7ec1a570 000421a4 76ef1c10 60000010 000af2ac 00000000 00000000
Backtrace:
[<8049ebdc>] (regmap_mmio_gather_write.part.4) from [<802992d0>] (regmap_mmio_gather_write+0x60/0x64)
r10:fffffdf4 r8:00000000 r7:00000002 r6:87ac43c0 r5:87ac43c2 r4:87ac4340
[<80299270>] (regmap_mmio_gather_write) from [<8029930c>] (regmap_mmio_write+0x38/0x44)
r6:87ac43c2 r5:00000000 r4:87ac0c00 r3:87ac43c2
[<802992d4>] (regmap_mmio_write) from [<802959f4>] (_regmap_raw_write+0x5ac/0x5d8)
[<80295448>] (_regmap_raw_write) from [<80295bc0>] (_regmap_bus_raw_write+0x74/0x9c)
r10:8076ff88 r9:804c8954 r8:8076b04c r7:87ac0c00 r6:00007731 r5:00000000
r4:87ac0c00
[<80295b4c>] (_regmap_bus_raw_write) from [<80294a80>] (_regmap_write+0x60/0x9c)
r5:00000000 r4:87ac0c00
[<80294a20>] (_regmap_write) from [<80295fd4>] (regmap_write+0x4c/0x64)
r7:871be988 r6:00007731 r5:00000000 r4:87ac0c00
[<80295f88>] (regmap_write) from [<8030616c>] (imx2_wdt_start+0x88/0xf4)
r6:87b7f540 r5:87813400 r4:807f9e68 r3:00000031
[<803060e4>] (imx2_wdt_start) from [<80306214>] (imx2_wdt_open+0x3c/0x58)
r5:871be988 r4:87b7f540
[<803061d8>] (imx2_wdt_open) from [<80288b48>] (misc_open+0xc0/0x160)
r5:00000082 r4:803061d8
[<80288a88>] (misc_open) from [<80096d88>] (chrdev_open+0xa4/0x144)
r10:871bea38 r9:00000000 r8:804c0dd4 r7:00000000 r6:8789b240 r5:87b7f540
r4:871be988 r3:80288a88
[<80096ce4>] (chrdev_open) from [<800916f4>] (do_dentry_open.isra.17+0x1b0/0x270)
r8:00000000 r7:80096ce4 r6:87b7f548 r5:871be988 r4:87b7f540
[<80091544>] (do_dentry_open.isra.17) from [<800917dc>] (finish_open+0x28/0x40)
r10:00000000 r8:00000000 r7:87091e80 r6:00020241 r5:87091f5c r4:87091e94
[<800917b4>] (finish_open) from [<800a0044>] (do_last.isra.68+0x3ac/0x5a8)
r4:87091ed0 r3:87091e94
[<8009fc98>] (do_last.isra.68) from [<800a02fc>] (path_openat+0xbc/0x448)
r10:87091e80 r9:87090000 r8:00000000 r7:00000000 r6:87091f5c r5:87b7f540
r4:87091ed0
[<800a0240>] (path_openat) from [<800a09c0>] (do_filp_open+0x34/0x88)
r10:00000000 r9:87090000 r8:8000e5c4 r7:87219000 r6:ffffff9c r5:00000001
r4:87091f5c
[<800a098c>] (do_filp_open) from [<80092998>] (do_sys_open+0x128/0x1d8)
r7:00000005 r6:ffffff9c r5:87219000 r4:00000003
[<80092870>] (do_sys_open) from [<80092a6c>] (SyS_open+0x24/0x28)
r10:00000000 r8:8000e5c4 r7:00000005 r6:00000000 r5:00000001 r4:000af2ac
[<80092a48>] (SyS_open) from [<8000e440>] (ret_fast_syscall+0x0/0x30)

Signed-off-by: Xiubo Li <Li.Xiubo@xxxxxxxxxxxxx>
---
drivers/base/regmap/regmap-mmio.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 5c36851..83532b7 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -61,17 +61,37 @@ static inline int regmap_mmio_reg_bits_check(size_t reg_bits)
return -EINVAL;
}
}
+
static inline void regmap_mmio_count_check(size_t count)
{
BUG_ON(count % 2 != 0);
}

+static inline unsigned int regmap_mmio_get_offset(const void *reg,
+ size_t reg_size)
+{
+ switch (reg_size) {
+ case 1:
+ return *(u8 *)reg;
+ case 2:
+ return *(u16 *)reg;
+ case 4:
+ return *(u32 *)reg;
+#ifdef CONFIG_64BIT
+ case 8:
+ return *(u64 *)reg;
+#endif
+ default:
+ BUG();
+ }
+}
+
static int regmap_mmio_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
struct regmap_mmio_context *ctx = context;
- u32 offset;
+ unsigned int offset;
int ret;

regmap_mmio_reg_size_check(reg_size);
@@ -82,7 +102,7 @@ static int regmap_mmio_gather_write(void *context,
return ret;
}

- offset = *(u32 *)reg;
+ offset = regmap_mmio_get_offset(reg, reg_size);

while (val_size) {
switch (ctx->val_bytes) {
@@ -131,7 +151,7 @@ static int regmap_mmio_read(void *context,
void *val, size_t val_size)
{
struct regmap_mmio_context *ctx = context;
- u32 offset;
+ unsigned int offset;
int ret;

regmap_mmio_reg_size_check(reg_size);
@@ -142,7 +162,7 @@ static int regmap_mmio_read(void *context,
return ret;
}

- offset = *(u32 *)reg;
+ offset = regmap_mmio_get_offset(reg, reg_size);

while (val_size) {
switch (ctx->val_bytes) {
--
1.8.4


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/