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 )
{
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,8 +220,7 @@ 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", "?" )) {
switch( interactive ? get_key( "123", "?" ) : '2') {
case '1':
if (!lfn_offsets)
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;
fs_write( dir_offset+offsetof(LFN_ENT,id),
sizeof(lfn->id), &lfn->id );
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) );
@ -241,8 +243,7 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
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,9 +268,12 @@ 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", "?" )) {
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();
@ -284,7 +288,6 @@ void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
break;
}
}
}
if (lfn->alias_checksum != lfn_checksum) {
/* checksum mismatch */
@ -390,8 +393,7 @@ 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", "?" )) {
switch( interactive ? get_key( "123", "?" ) : '2') {
case '1':
clear_lfn_slots( 0, lfn_parts-1 );
lfn_reset();
@ -410,7 +412,6 @@ char *lfn_get( DIR_ENT *de )
break;
}
}
}
for (sum = 0, i = 0; i < 11; i++)
sum = (((sum&1) << 7) | ((sum&0xfe) >> 1)) + de->name[i];