summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/apanic.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/misc/apanic.c b/drivers/misc/apanic.c
index 4a7e5add273b..f50881ba917d 100644
--- a/drivers/misc/apanic.c
+++ b/drivers/misc/apanic.c
@@ -81,7 +81,7 @@ static void set_bb(unsigned int block, unsigned int *bbt)
apanic_good_blocks--;
}
-static char get_bb(unsigned int block, unsigned int *bbt)
+static unsigned int get_bb(unsigned int block, unsigned int *bbt)
{
unsigned int flag;
@@ -111,14 +111,14 @@ static void scan_bbt(struct mtd_info *mtd, unsigned int *bbt)
}
}
+#define APANIC_INVALID_OFFSET 0xFFFFFFFF
+
static unsigned int phy_offset(struct mtd_info *mtd, unsigned int offset)
{
unsigned int logic_block = offset>>(mtd->erasesize_shift);
unsigned int phy_block;
unsigned good_block = 0;
- BUG_ON(logic_block + 1 > apanic_good_blocks);
-
for (phy_block = 0; phy_block < apanic_erase_blocks; phy_block++) {
if (!get_bb(phy_block, apanic_bbt))
good_block++;
@@ -126,6 +126,9 @@ static unsigned int phy_offset(struct mtd_info *mtd, unsigned int offset)
break;
}
+ if (good_block != (logic_block + 1))
+ return APANIC_INVALID_OFFSET;
+
return offset + ((phy_block-logic_block)<<mtd->erasesize_shift);
}
@@ -178,6 +181,13 @@ static int apanic_proc_read(char *buffer, char **start, off_t offset,
page_no = (file_offset + offset) / ctx->mtd->writesize;
page_offset = (file_offset + offset) % ctx->mtd->writesize;
+
+ if (phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize))
+ == APANIC_INVALID_OFFSET) {
+ pr_err("apanic: reading an invalid address\n");
+ mutex_unlock(&drv_mutex);
+ return -EINVAL;
+ }
rc = ctx->mtd->read(ctx->mtd,
phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize)),
ctx->mtd->writesize,
@@ -296,6 +306,11 @@ static void mtd_panic_notify_add(struct mtd_info *mtd)
alloc_bbt(mtd, apanic_bbt);
scan_bbt(mtd, apanic_bbt);
+ if (apanic_good_blocks == 0) {
+ printk(KERN_ERR "apanic: no any good blocks?!\n");
+ goto out_err;
+ }
+
rc = mtd->read(mtd, phy_offset(mtd, 0), mtd->writesize,
&len, ctx->bounce);
if (rc && rc == -EBADMSG) {
@@ -397,6 +412,10 @@ static int apanic_writeflashpage(struct mtd_info *mtd, loff_t to,
}
to = phy_offset(mtd, to);
+ if (to == APANIC_INVALID_OFFSET) {
+ printk(KERN_EMERG "apanic: write to invalid address\n");
+ return 0;
+ }
if (panic)
rc = mtd->panic_write(mtd, to, mtd->writesize, &wlen, buf);
@@ -448,7 +467,7 @@ static int apanic_write_console(struct mtd_info *mtd, unsigned int off)
if (rc2 <= 0) {
printk(KERN_EMERG
"apanic: Flash write failed (%d)\n", rc2);
- return rc2;
+ return idx;
}
if (!last_chunk)
idx += rc2;
@@ -477,6 +496,7 @@ static int apanic(struct notifier_block *this, unsigned long event,
/* Ensure that cond_resched() won't try to preempt anybody */
add_preempt_count(PREEMPT_ACTIVE);
#endif
+ touch_softlockup_watchdog();
if (!ctx->mtd)
goto out;