Applying Debians 12-zero-slot.dpatch by Karl Tomlinson

<karlt@karlt.net> 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 <mail@daniel-baumann.ch>
This commit is contained in:
Daniel Baumann 2008-09-26 14:34:17 +02:00
parent eec8585c73
commit 1b2c8ca3b4

View File

@ -148,12 +148,15 @@ void lfn_reset( void )
void lfn_add_slot( DIR_ENT *de, loff_t dir_offset ) void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
{ {
LFN_ENT *lfn = (LFN_ENT *)de; LFN_ENT *lfn = (LFN_ENT *)de;
int slot = lfn->id & LFN_ID_SLOTMASK;
unsigned offset; unsigned offset;
if (lfn_slot == 0) lfn_check_orphaned();
if (de->attr != VFAT_LN_ATTR) if (de->attr != VFAT_LN_ATTR)
die("lfn_add_slot called with non-LFN directory entry"); 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) { if (lfn_slot != -1) {
int can_clear = 0; int can_clear = 0;
/* There is already a LFN "in progess", so it is an error that a /* 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 /* XXX: Should delay that until next LFN known (then can better
* display the name) */ * display the name) */
printf( "A new long file name starts within an old one.\n" ); 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) { lfn->alias_checksum == lfn_checksum) {
char *part1 = CNV_THIS_PART(lfn); char *part1 = CNV_THIS_PART(lfn);
char *part2 = CNV_PARTS_SO_FAR(); 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_checksum = lfn->alias_checksum;
lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 ); lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 );
lfn_offsets = alloc( lfn_slot*sizeof(loff_t) ); lfn_offsets = alloc( lfn_slot*sizeof(loff_t) );
lfn_parts = 0; 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 */ /* No LFN in progress, but slot found; start bit missing */
/* Causes: 1) start bit got lost, 2) Previous slot with start bit got /* Causes: 1) start bit got lost, 2) Previous slot with start bit got
* lost */ * lost */
@ -217,8 +220,7 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
"3: Set start bit\n" ); "3: Set start bit\n" );
} }
else printf( " Not auto-correcting this.\n" ); else printf( " Not auto-correcting this.\n" );
if (interactive) { switch( interactive ? get_key( "123", "?" ) : '2') {
switch( get_key( "123", "?" )) {
case '1': case '1':
if (!lfn_offsets) if (!lfn_offsets)
lfn_offsets = alloc( sizeof(loff_t) ); lfn_offsets = alloc( sizeof(loff_t) );
@ -233,7 +235,7 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
lfn->id |= LFN_ID_START; lfn->id |= LFN_ID_START;
fs_write( dir_offset+offsetof(LFN_ENT,id), fs_write( dir_offset+offsetof(LFN_ENT,id),
sizeof(lfn->id), &lfn->id ); sizeof(lfn->id), &lfn->id );
lfn_slot = lfn->id & LFN_ID_SLOTMASK; lfn_slot = slot;
lfn_checksum = lfn->alias_checksum; lfn_checksum = lfn->alias_checksum;
lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 ); lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 );
lfn_offsets = alloc( lfn_slot*sizeof(loff_t) ); lfn_offsets = alloc( lfn_slot*sizeof(loff_t) );
@ -241,8 +243,7 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
break; break;
} }
} }
} else if (slot != lfn_slot) {
else if ((lfn->id & LFN_ID_SLOTMASK) != lfn_slot) {
/* wrong sequence number */ /* wrong sequence number */
/* Causes: 1) seq-no destroyed */ /* Causes: 1) seq-no destroyed */
/* Fixes: 1) delete LFN, 2) fix number (maybe only if following parts /* 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; int can_fix = 0;
printf( "Unexpected long filename sequence number " printf( "Unexpected long filename sequence number "
"(%d vs. expected %d).\n", "(%d vs. expected %d).\n",
(lfn->id & LFN_ID_SLOTMASK), lfn_slot ); slot, lfn_slot );
if (lfn->alias_checksum == lfn_checksum) { if (lfn->alias_checksum == lfn_checksum && lfn_slot > 0) {
char *part1 = CNV_THIS_PART(lfn); char *part1 = CNV_THIS_PART(lfn);
char *part2 = CNV_PARTS_SO_FAR(); char *part2 = CNV_PARTS_SO_FAR();
printf( " It could be that just the number is wrong\n" printf( " It could be that just the number is wrong\n"
@ -267,9 +268,12 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
printf( "3: Correct sequence number\n" ); printf( "3: Correct sequence number\n" );
} }
else printf( " Not auto-correcting this.\n" ); else printf( " Not auto-correcting this.\n" );
if (interactive) { switch( interactive ? get_key( can_fix ? "123" : "12", "?" ) : '2') {
switch( get_key( can_fix ? "123" : "12", "?" )) {
case '1': case '1':
if (!lfn_offsets) {
lfn_offsets = alloc( sizeof(loff_t) );
lfn_parts = 0;
}
lfn_offsets[lfn_parts++] = dir_offset; lfn_offsets[lfn_parts++] = dir_offset;
clear_lfn_slots( 0, lfn_parts-1 ); clear_lfn_slots( 0, lfn_parts-1 );
lfn_reset(); lfn_reset();
@ -284,7 +288,6 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
break; break;
} }
} }
}
if (lfn->alias_checksum != lfn_checksum) { if (lfn->alias_checksum != lfn_checksum) {
/* checksum mismatch */ /* checksum mismatch */
@ -390,8 +393,7 @@ char *lfn_get( DIR_ENT *de )
"it to short name %s)\n", short_name ); "it to short name %s)\n", short_name );
} }
else printf( " Not auto-correcting this.\n" ); else printf( " Not auto-correcting this.\n" );
if (interactive) { switch( interactive ? get_key( "123", "?" ) : '2') {
switch( get_key( "123", "?" )) {
case '1': case '1':
clear_lfn_slots( 0, lfn_parts-1 ); clear_lfn_slots( 0, lfn_parts-1 );
lfn_reset(); lfn_reset();
@ -410,7 +412,6 @@ char *lfn_get( DIR_ENT *de )
break; break;
} }
} }
}
for (sum = 0, i = 0; i < 11; i++) for (sum = 0, i = 0; i < 11; i++)
sum = (((sum&1) << 7) | ((sum&0xfe) >> 1)) + de->name[i]; sum = (((sum&1) << 7) | ((sum&0xfe) >> 1)) + de->name[i];