diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-06-17 19:05:26 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-06-17 19:05:26 -0400 |
commit | 3877f0b6c9f54d43e55e532404a935b90393b635 (patch) | |
tree | b22e658ee19ea83c630c6464ed9c7a46d8073606 /fs | |
parent | 21c8db9eff95260e543535dfc6f27164c4c0c0ff (diff) |
[JFFS2] Don't trust node headers before the CRC is checked.
Especially when summary code is used, we can have in-memory data
structures referencing certain nodes without them actually being readable
on the flash. Discard the nodes gracefully in that case, rather than
triggering a BUG().
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/jffs2/readinode.c | 62 |
1 files changed, 34 insertions, 28 deletions
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index e1acce8fb2bf..5351b34d5419 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -343,7 +343,7 @@ free_out: | |||
343 | * Helper function for jffs2_get_inode_nodes(). | 343 | * Helper function for jffs2_get_inode_nodes(). |
344 | * It is called every time an unknown node is found. | 344 | * It is called every time an unknown node is found. |
345 | * | 345 | * |
346 | * Returns: 0 on succes; | 346 | * Returns: 0 on success; |
347 | * 1 if the node should be marked obsolete; | 347 | * 1 if the node should be marked obsolete; |
348 | * negative error code on failure. | 348 | * negative error code on failure. |
349 | */ | 349 | */ |
@@ -354,37 +354,30 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re | |||
354 | 354 | ||
355 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); | 355 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); |
356 | 356 | ||
357 | if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) { | 357 | switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { |
358 | /* Hmmm. This should have been caught at scan time. */ | ||
359 | JFFS2_NOTICE("node header CRC failed at %#08x. But it must have been OK earlier.\n", ref_offset(ref)); | ||
360 | jffs2_dbg_dump_node(c, ref_offset(ref)); | ||
361 | return 1; | ||
362 | } else { | ||
363 | switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { | ||
364 | 358 | ||
365 | case JFFS2_FEATURE_INCOMPAT: | 359 | case JFFS2_FEATURE_INCOMPAT: |
366 | JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n", | 360 | JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n", |
367 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 361 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
368 | /* EEP */ | 362 | /* EEP */ |
369 | BUG(); | 363 | BUG(); |
370 | break; | 364 | break; |
371 | 365 | ||
372 | case JFFS2_FEATURE_ROCOMPAT: | 366 | case JFFS2_FEATURE_ROCOMPAT: |
373 | JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n", | 367 | JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n", |
374 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 368 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
375 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); | 369 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); |
376 | break; | 370 | break; |
377 | 371 | ||
378 | case JFFS2_FEATURE_RWCOMPAT_COPY: | 372 | case JFFS2_FEATURE_RWCOMPAT_COPY: |
379 | JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", | 373 | JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", |
380 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 374 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
381 | break; | 375 | break; |
382 | 376 | ||
383 | case JFFS2_FEATURE_RWCOMPAT_DELETE: | 377 | case JFFS2_FEATURE_RWCOMPAT_DELETE: |
384 | JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", | 378 | JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", |
385 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 379 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
386 | return 1; | 380 | return 1; |
387 | } | ||
388 | } | 381 | } |
389 | 382 | ||
390 | return 0; | 383 | return 0; |
@@ -549,6 +542,18 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
549 | 542 | ||
550 | node = (union jffs2_node_union *)bufstart; | 543 | node = (union jffs2_node_union *)bufstart; |
551 | 544 | ||
545 | /* No need to mask in the valid bit; it shouldn't be invalid */ | ||
546 | if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) { | ||
547 | JFFS2_NOTICE("Node header CRC failed at %#08x. {%04x,%04x,%08x,%08x}\n", | ||
548 | ref_offset(ref), je16_to_cpu(node->u.magic), | ||
549 | je16_to_cpu(node->u.nodetype), | ||
550 | je32_to_cpu(node->u.totlen), | ||
551 | je32_to_cpu(node->u.hdr_crc)); | ||
552 | jffs2_dbg_dump_node(c, ref_offset(ref)); | ||
553 | jffs2_mark_node_obsolete(c, ref); | ||
554 | goto cont; | ||
555 | } | ||
556 | |||
552 | switch (je16_to_cpu(node->u.nodetype)) { | 557 | switch (je16_to_cpu(node->u.nodetype)) { |
553 | 558 | ||
554 | case JFFS2_NODETYPE_DIRENT: | 559 | case JFFS2_NODETYPE_DIRENT: |
@@ -606,6 +611,7 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
606 | goto free_out; | 611 | goto free_out; |
607 | 612 | ||
608 | } | 613 | } |
614 | cont: | ||
609 | spin_lock(&c->erase_completion_lock); | 615 | spin_lock(&c->erase_completion_lock); |
610 | } | 616 | } |
611 | 617 | ||