mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2025-11-11 11:08:02 -06:00
Windows vulnerability fix : make boot-loader decompressor more robust and secure by adding multiple checks and validation code. Note that we had to switch to the slow implementation of the function decode in order to keep the size of the decompressor code under 2K.
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
#include "BootDefs.h"
|
#include "BootDefs.h"
|
||||||
|
|
||||||
// The user will be advised to upgrade the rescue disk if upgrading from the following or any previous version
|
// The user will be advised to upgrade the rescue disk if upgrading from the following or any previous version
|
||||||
#define TC_RESCUE_DISK_UPGRADE_NOTICE_MAX_VERSION 0x010a
|
#define TC_RESCUE_DISK_UPGRADE_NOTICE_MAX_VERSION 0x010d
|
||||||
|
|
||||||
#define TC_BOOT_LOADER_AREA_SIZE (TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
|
#define TC_BOOT_LOADER_AREA_SIZE (TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,8 @@ checksum_ok:
|
|||||||
push dx
|
push dx
|
||||||
|
|
||||||
; Decompress boot loader
|
; Decompress boot loader
|
||||||
|
mov cx, word ptr [start + TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET]
|
||||||
|
push cx ; Compressed data size
|
||||||
push TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET + TC_GZIP_HEADER_SIZE ; Compressed data
|
push TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET + TC_GZIP_HEADER_SIZE ; Compressed data
|
||||||
push TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE ; Output buffer size
|
push TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE ; Output buffer size
|
||||||
push TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE + TC_COM_EXECUTABLE_OFFSET ; Output buffer
|
push TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE + TC_COM_EXECUTABLE_OFFSET ; Output buffer
|
||||||
@@ -145,7 +147,7 @@ checksum_ok:
|
|||||||
retf
|
retf
|
||||||
decompressor_ret:
|
decompressor_ret:
|
||||||
|
|
||||||
add sp, 6
|
add sp, 8
|
||||||
pop dx
|
pop dx
|
||||||
|
|
||||||
; Restore boot sector segment
|
; Restore boot sector segment
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ struct state {
|
|||||||
|
|
||||||
/* input state */
|
/* input state */
|
||||||
unsigned char *in; /* input buffer */
|
unsigned char *in; /* input buffer */
|
||||||
|
unsigned int inlen; /* available input at in */
|
||||||
unsigned int incnt; /* bytes read so far */
|
unsigned int incnt; /* bytes read so far */
|
||||||
int bitbuf; /* bit buffer */
|
int bitbuf; /* bit buffer */
|
||||||
int bitcnt; /* number of bits in bit buffer */
|
int bitcnt; /* number of bits in bit buffer */
|
||||||
@@ -81,6 +82,9 @@ local int stored(struct state *s)
|
|||||||
s->bitbuf = 0;
|
s->bitbuf = 0;
|
||||||
s->bitcnt = 0;
|
s->bitcnt = 0;
|
||||||
|
|
||||||
|
if (s->incnt + 4 > s->inlen)
|
||||||
|
return 2; /* not enough input */
|
||||||
|
|
||||||
/* get length and check against its one's complement */
|
/* get length and check against its one's complement */
|
||||||
len = s->in[s->incnt++];
|
len = s->in[s->incnt++];
|
||||||
len |= s->in[s->incnt++] << 8;
|
len |= s->in[s->incnt++] << 8;
|
||||||
@@ -88,6 +92,9 @@ local int stored(struct state *s)
|
|||||||
s->in[s->incnt++] != ((~len >> 8) & 0xff))
|
s->in[s->incnt++] != ((~len >> 8) & 0xff))
|
||||||
return -2; /* didn't match complement! */
|
return -2; /* didn't match complement! */
|
||||||
|
|
||||||
|
if (s->incnt + len > s->inlen)
|
||||||
|
return 2; /* not enough input */
|
||||||
|
|
||||||
/* copy len bytes from in to out */
|
/* copy len bytes from in to out */
|
||||||
if (s->out != NIL) {
|
if (s->out != NIL) {
|
||||||
if (s->outcnt + len > s->outlen)
|
if (s->outcnt + len > s->outlen)
|
||||||
@@ -110,6 +117,8 @@ struct huffman {
|
|||||||
short *symbol; /* canonically ordered symbols */
|
short *symbol; /* canonically ordered symbols */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* use slow version of decode to save code space */
|
||||||
|
#define SLOW
|
||||||
|
|
||||||
#ifdef SLOW
|
#ifdef SLOW
|
||||||
local int decode(struct state *s, struct huffman *h)
|
local int decode(struct state *s, struct huffman *h)
|
||||||
@@ -363,26 +372,37 @@ local int dynamic(struct state *s)
|
|||||||
int len; /* last length to repeat */
|
int len; /* last length to repeat */
|
||||||
|
|
||||||
symbol = decode(s, &lencode);
|
symbol = decode(s, &lencode);
|
||||||
|
if (symbol < 0) return symbol;
|
||||||
if (symbol < 16) /* length in 0..15 */
|
if (symbol < 16) /* length in 0..15 */
|
||||||
lengths[index++] = symbol;
|
lengths[index++] = symbol;
|
||||||
else { /* repeat instruction */
|
else { /* repeat instruction */
|
||||||
len = 0; /* assume repeating zeros */
|
len = 0; /* assume repeating zeros */
|
||||||
if (symbol == 16) { /* repeat last length 3..6 times */
|
switch(symbol)
|
||||||
|
{
|
||||||
|
case 16: { /* repeat last length 3..6 times */
|
||||||
if (index == 0) return -5; /* no last length! */
|
if (index == 0) return -5; /* no last length! */
|
||||||
len = lengths[index - 1]; /* last length */
|
len = lengths[index - 1]; /* last length */
|
||||||
symbol = 3 + bits(s, 2);
|
symbol = 3 + bits(s, 2);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (symbol == 17) /* repeat zero 3..10 times */
|
case 17: /* repeat zero 3..10 times */
|
||||||
symbol = 3 + bits(s, 3);
|
symbol = 3 + bits(s, 3);
|
||||||
else /* == 18, repeat zero 11..138 times */
|
break;
|
||||||
|
default: /* == 18, repeat zero 11..138 times */
|
||||||
symbol = 11 + bits(s, 7);
|
symbol = 11 + bits(s, 7);
|
||||||
if (index + symbol > nlen + ndist)
|
break;
|
||||||
|
}
|
||||||
|
if ((index + symbol > nlen + ndist))
|
||||||
return -6; /* too many lengths! */
|
return -6; /* too many lengths! */
|
||||||
while (symbol--) /* repeat last or zero symbol times */
|
while (symbol--) /* repeat last or zero symbol times */
|
||||||
lengths[index++] = len;
|
lengths[index++] = len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for end-of-block code -- there better be one! */
|
||||||
|
if (lengths[256] == 0)
|
||||||
|
return -9;
|
||||||
|
|
||||||
/* build huffman table for literal/length codes */
|
/* build huffman table for literal/length codes */
|
||||||
err = construct(&lencode, lengths, nlen);
|
err = construct(&lencode, lengths, nlen);
|
||||||
if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
|
if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
|
||||||
@@ -404,7 +424,8 @@ void _acrtused () { }
|
|||||||
int far main (
|
int far main (
|
||||||
unsigned char *dest, /* pointer to destination pointer */
|
unsigned char *dest, /* pointer to destination pointer */
|
||||||
unsigned int destlen, /* amount of output space */
|
unsigned int destlen, /* amount of output space */
|
||||||
unsigned char *source) /* pointer to source data pointer */
|
unsigned char *source, /* pointer to source data pointer */
|
||||||
|
unsigned int sourcelen)
|
||||||
{
|
{
|
||||||
struct state s; /* input/output state */
|
struct state s; /* input/output state */
|
||||||
int last, type; /* block information */
|
int last, type; /* block information */
|
||||||
@@ -417,6 +438,7 @@ int far main (
|
|||||||
|
|
||||||
/* initialize input state */
|
/* initialize input state */
|
||||||
s.in = source;
|
s.in = source;
|
||||||
|
s.inlen = sourcelen;
|
||||||
s.incnt = 0;
|
s.incnt = 0;
|
||||||
s.bitbuf = 0;
|
s.bitbuf = 0;
|
||||||
s.bitcnt = 0;
|
s.bitcnt = 0;
|
||||||
@@ -425,10 +447,22 @@ int far main (
|
|||||||
do {
|
do {
|
||||||
last = bits(&s, 1); /* one if last block */
|
last = bits(&s, 1); /* one if last block */
|
||||||
type = bits(&s, 2); /* block type 0..3 */
|
type = bits(&s, 2); /* block type 0..3 */
|
||||||
err = type == 0 ? stored(&s) :
|
switch(type)
|
||||||
(type == 1 ? fixed(&s) :
|
{
|
||||||
(type == 2 ? dynamic(&s) :
|
case 0:
|
||||||
-1)); /* type == 3, invalid */
|
err = stored(&s);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
err = fixed(&s);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
err = dynamic(&s);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -1; /* type == 3, invalid */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (err != 0) break; /* return with error */
|
if (err != 0) break; /* return with error */
|
||||||
} while (!last);
|
} while (!last);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user