From 1b2c8ca3b4b1b308b684a032c794799c0d967536 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 26 Sep 2008 14:34:17 +0200 Subject: [PATCH] Applying Debians 12-zero-slot.dpatch by Karl Tomlinson to fix dosfsck zero slot crashes: * Fixes crashes due to zero slot numbers causing a negative offset in the call to copy_lfn_part in lfn_add_slot. On amd64 this results in a SIGSEGV in copy_lfn_part. On x86 the result is heap corruption and thus sometimes a SIGSEGV or double free abort later. (Closes: #152550, #353198, #356377, #401798). Signed-off-by: Daniel Baumann --- dosfsck/lfn.c | 127 +++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 63 deletions(-) diff --git a/dosfsck/lfn.c b/dosfsck/lfn.c index 9b2cfc3..c6f0fa4 100644 --- a/dosfsck/lfn.c +++ b/dosfsck/lfn.c @@ -148,12 +148,15 @@ void lfn_reset( void ) void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) { LFN_ENT *lfn = (LFN_ENT *)de; + int slot = lfn->id & LFN_ID_SLOTMASK; unsigned offset; + if (lfn_slot == 0) lfn_check_orphaned(); + if (de->attr != VFAT_LN_ATTR) die("lfn_add_slot called with non-LFN directory entry"); - if (lfn->id & LFN_ID_START) { + if (lfn->id & LFN_ID_START && slot != 0) { if (lfn_slot != -1) { int can_clear = 0; /* There is already a LFN "in progess", so it is an error that a @@ -165,7 +168,7 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) /* XXX: Should delay that until next LFN known (then can better * display the name) */ printf( "A new long file name starts within an old one.\n" ); - if ((lfn->id & LFN_ID_SLOTMASK) == lfn_slot && + if (slot == lfn_slot && lfn->alias_checksum == lfn_checksum) { char *part1 = CNV_THIS_PART(lfn); char *part2 = CNV_PARTS_SO_FAR(); @@ -197,13 +200,13 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) } } } - lfn_slot = lfn->id & LFN_ID_SLOTMASK; + lfn_slot = slot; lfn_checksum = lfn->alias_checksum; lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 ); lfn_offsets = alloc( lfn_slot*sizeof(loff_t) ); lfn_parts = 0; } - else if (lfn_slot == -1) { + else if (lfn_slot == -1 && slot != 0) { /* No LFN in progress, but slot found; start bit missing */ /* Causes: 1) start bit got lost, 2) Previous slot with start bit got * lost */ @@ -217,32 +220,30 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) "3: Set start bit\n" ); } else printf( " Not auto-correcting this.\n" ); - if (interactive) { - switch( get_key( "123", "?" )) { - case '1': - if (!lfn_offsets) - lfn_offsets = alloc( sizeof(loff_t) ); - lfn_offsets[0] = dir_offset; - clear_lfn_slots( 0, 0 ); - lfn_reset(); - return; - case '2': - lfn_reset(); - return; - case '3': - lfn->id |= LFN_ID_START; - fs_write( dir_offset+offsetof(LFN_ENT,id), - sizeof(lfn->id), &lfn->id ); - lfn_slot = lfn->id & LFN_ID_SLOTMASK; - lfn_checksum = lfn->alias_checksum; - lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 ); - lfn_offsets = alloc( lfn_slot*sizeof(loff_t) ); - lfn_parts = 0; - break; - } + switch( interactive ? get_key( "123", "?" ) : '2') { + case '1': + if (!lfn_offsets) + lfn_offsets = alloc( sizeof(loff_t) ); + lfn_offsets[0] = dir_offset; + clear_lfn_slots( 0, 0 ); + lfn_reset(); + return; + case '2': + lfn_reset(); + return; + case '3': + lfn->id |= LFN_ID_START; + fs_write( dir_offset+offsetof(LFN_ENT,id), + sizeof(lfn->id), &lfn->id ); + lfn_slot = slot; + lfn_checksum = lfn->alias_checksum; + lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 ); + lfn_offsets = alloc( lfn_slot*sizeof(loff_t) ); + lfn_parts = 0; + break; } } - else if ((lfn->id & LFN_ID_SLOTMASK) != lfn_slot) { + else if (slot != lfn_slot) { /* wrong sequence number */ /* Causes: 1) seq-no destroyed */ /* Fixes: 1) delete LFN, 2) fix number (maybe only if following parts @@ -251,8 +252,8 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) int can_fix = 0; printf( "Unexpected long filename sequence number " "(%d vs. expected %d).\n", - (lfn->id & LFN_ID_SLOTMASK), lfn_slot ); - if (lfn->alias_checksum == lfn_checksum) { + slot, lfn_slot ); + if (lfn->alias_checksum == lfn_checksum && lfn_slot > 0) { char *part1 = CNV_THIS_PART(lfn); char *part2 = CNV_PARTS_SO_FAR(); printf( " It could be that just the number is wrong\n" @@ -267,22 +268,24 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) printf( "3: Correct sequence number\n" ); } else printf( " Not auto-correcting this.\n" ); - if (interactive) { - switch( get_key( can_fix ? "123" : "12", "?" )) { - case '1': - lfn_offsets[lfn_parts++] = dir_offset; - clear_lfn_slots( 0, lfn_parts-1 ); - lfn_reset(); - return; - case '2': - lfn_reset(); - return; - case '3': - lfn->id = (lfn->id & ~LFN_ID_SLOTMASK) | lfn_slot; - fs_write( dir_offset+offsetof(LFN_ENT,id), - sizeof(lfn->id), &lfn->id ); - break; + switch( interactive ? get_key( can_fix ? "123" : "12", "?" ) : '2') { + case '1': + if (!lfn_offsets) { + lfn_offsets = alloc( sizeof(loff_t) ); + lfn_parts = 0; } + lfn_offsets[lfn_parts++] = dir_offset; + clear_lfn_slots( 0, lfn_parts-1 ); + lfn_reset(); + return; + case '2': + lfn_reset(); + return; + case '3': + lfn->id = (lfn->id & ~LFN_ID_SLOTMASK) | lfn_slot; + fs_write( dir_offset+offsetof(LFN_ENT,id), + sizeof(lfn->id), &lfn->id ); + break; } } @@ -390,25 +393,23 @@ char *lfn_get( DIR_ENT *de ) "it to short name %s)\n", short_name ); } else printf( " Not auto-correcting this.\n" ); - if (interactive) { - switch( get_key( "123", "?" )) { - case '1': - clear_lfn_slots( 0, lfn_parts-1 ); - lfn_reset(); - return NULL; - case '2': - lfn_reset(); - return NULL; - case '3': - for( i = 0; i < lfn_parts; ++i ) { - __u8 id = (lfn_parts-i) | (i==0 ? LFN_ID_START : 0); - fs_write( lfn_offsets[i]+offsetof(LFN_ENT,id), - sizeof(id), &id ); - } - memmove( lfn_unicode, lfn_unicode+lfn_slot*CHARS_PER_LFN*2, - lfn_parts*CHARS_PER_LFN*2 ); - break; + switch( interactive ? get_key( "123", "?" ) : '2') { + case '1': + clear_lfn_slots( 0, lfn_parts-1 ); + lfn_reset(); + return NULL; + case '2': + lfn_reset(); + return NULL; + case '3': + for( i = 0; i < lfn_parts; ++i ) { + __u8 id = (lfn_parts-i) | (i==0 ? LFN_ID_START : 0); + fs_write( lfn_offsets[i]+offsetof(LFN_ENT,id), + sizeof(id), &id ); } + memmove( lfn_unicode, lfn_unicode+lfn_slot*CHARS_PER_LFN*2, + lfn_parts*CHARS_PER_LFN*2 ); + break; } }