linux
Non-initialized buffer causes kernel panic in JFFS2
NOR flash setup function leaves struct field `wbuf_verify' uninitialized, but this buffer is used when JFFS2_FS_WBUF_VERIFY is enabled.
Bug fixed by commit bc8cec0dff0
Type | UninitializedVariable |
Config | "JFFS2_FS_WBUF_VERIFY" (1st degree) |
C-features | FunctionPointers, Structs |
Fix-in | code |
Location | fs/jffs2/ |
#define ENOMEM 12 /* Out of memory */ typedef long unsigned int size_t; extern void *malloc (size_t __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) ; extern void free (void *__ptr) __attribute__ ((__nothrow__ , __leaf__)); #define WBUF_PAGESIZE 32 unsigned char *wbuf; /* Write-behind buffer for NAND flash */ #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY unsigned char *wbuf_verify; /* read-back buffer for verification */ #endif int jffs2_nor_wbuf_flash_setup() { wbuf = malloc(WBUF_PAGESIZE); if (!wbuf) return -ENOMEM; return 0; } #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY static int jffs2_verify_write() { return(int) *wbuf_verify; // ERROR (6) } #else #define jffs2_verify_write() do { } while (0) #endif int __jffs2_flush_wbuf() { jffs2_verify_write(); // (5) return 0; } int jffs2_flash_writev() { __jffs2_flush_wbuf(); // (4) return 0; } int jffs2_flash_write() { return jffs2_flash_writev(); // (3) } int main() { jffs2_nor_wbuf_flash_setup(); // (1) jffs2_flash_write(); // (2) return 0; }
diff --git a/simple/bc8cec0.c b/simple/bc8cec0.c --- a/simple/bc8cec0.c +++ b/simple/bc8cec0.c @@ -19,6 +19,14 @@ if (!wbuf) return -ENOMEM; +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY + wbuf_verify = malloc(WBUF_PAGESIZE); + if (!wbuf_verify) { + free(wbuf); + return -ENOMEM; + } +#endif + return 0; }
#include <errno.h> #include <stdlib.h> #define WBUF_PAGESIZE 32 unsigned char *wbuf; /* Write-behind buffer for NAND flash */ #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY unsigned char *wbuf_verify; /* read-back buffer for verification */ #endif int main() { // jffs2_nor_wbuf_flash_setup(); wbuf = malloc(WBUF_PAGESIZE); if (!wbuf) return -ENOMEM; // jffs2_flash_write(); #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY return(int) *wbuf_verify; // ERROR #else do { } while (0); #endif return 0; }
. // SETUP . // at fs/jffs2/super.c:234 jffs2_get_sb() is set as a method to read a super-block . call fs/jffs2/super.c:183:jffs2_get_sb() .. call drivers/mtd/mtdsuper.c:125:get_sb_mtd() ... call drivers/mtd/mtdsuper.c:53:get_sb_mtd_aux() ... 75: ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); .... dyn-call fs/jffs2/super.c:148:jffs2_fill_super() ..... call fs/jffs2/fs.c:474:jffs2_do_fill_super() ..... 515: ret = jffs2_flash_setup(c); ...... call fs/jffs2/fs.c:668:jffs2_flash_setup() ...... 687: ret = jffs2_nor_wbuf_flash_setup(c); ....... call fs/jffs2/wbuf.c:1257:jffs2_nor_wbuf_flash_setup() ....... // c->wbuf_verify is left uninitialized for NOR flash . // later... . call fs/jffs2/wbuf.c:930:jffs2_flash_write() .. call fs/jffs2/wbuf.c:782:jffs2_flash_writev() ... call fs/jffs2/wbuf.c:570:__jffs2_flush_wbuf() .... call fs/jffs2/wbuf.c:224:jffs2_verify_write() .... // this call only happens when JFFS2_FS_WBUF_VERIFY is enabled .... ERROR 231: ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);