fsck.cramfs: fix fsck.cramfs crashes on blocksizes > 4K

fsck.cramfs crashes when extracting a cramfs image with a 16KB blocksize.
The read_buffer is hardcoded for a 4KB blocksize.  When using a blocksize
larger than 4KB, the program's code uses indexes that go past the end of the
allocated space for the read_buffer and this causes the crash.

The following changes fix the problem for me in the latest 2.36.1 release of
fsck.cramfs.c.  However there are hardcoded values of 4096 in the code that
might cause problems under other circumstances and I have not attempted to
fix those.

[kzak@redhat.com: - some coding style changes to code]

Fixes: https://github.com/karelzak/util-linux/issues/1232
Signed-off-by: ToddRK <ToddRK@example.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
ToddRK 2021-01-28 12:44:41 +01:00 committed by Karel Zak
parent 867df2617c
commit deba6720fb
1 changed files with 27 additions and 10 deletions

View File

@ -86,11 +86,17 @@ static unsigned long start_data = ~0UL; /* start of the data (256 MB = max) */
static unsigned long end_data = 0; /* end of the data */ static unsigned long end_data = 0; /* end of the data */
/* Guarantee access to at least 8kB at a time */ /* Guarantee access to at least 2 * blksize at a time */
#define ROMBUFFER_BITS 13 #define CRAMFS_ROMBUFFER_BITS 13
#define ROMBUFFERSIZE (1 << ROMBUFFER_BITS) #define CRAMFS_ROMBUFFERSIZE (1 << CRAMFS_ROMBUFFER_BITS)
#define ROMBUFFERMASK (ROMBUFFERSIZE - 1) #define CRAMFS_ROMBUFFERMASK (CRAMFS_ROMBUFFERSIZE - 1)
static char read_buffer[ROMBUFFERSIZE * 2];
/* Defaults, updated in main() according to block size */
static size_t rombufbits = CRAMFS_ROMBUFFER_BITS;
static size_t rombufsize = CRAMFS_ROMBUFFERSIZE;
static size_t rombufmask = CRAMFS_ROMBUFFERMASK;
static char *read_buffer;
static unsigned long read_buffer_block = ~0UL; static unsigned long read_buffer_block = ~0UL;
static z_stream stream; static z_stream stream;
@ -298,19 +304,19 @@ static void print_node(char type, struct cramfs_inode *i, char *name)
*/ */
static void *romfs_read(unsigned long offset) static void *romfs_read(unsigned long offset)
{ {
unsigned int block = offset >> ROMBUFFER_BITS; unsigned int block = offset >> rombufbits;
if (block != read_buffer_block) { if (block != read_buffer_block) {
ssize_t x; ssize_t x;
read_buffer_block = block; read_buffer_block = block;
if (lseek(fd, block << ROMBUFFER_BITS, SEEK_SET) == (off_t) -1) if (lseek(fd, block << rombufbits, SEEK_SET) == (off_t) -1)
warn(_("seek failed")); warn(_("seek failed"));
x = read(fd, read_buffer, ROMBUFFERSIZE * 2); x = read(fd, read_buffer, rombufsize * 2);
if (x < 0) if (x < 0)
warn(_("read romfs failed")); warn(_("read romfs failed"));
} }
return read_buffer + (offset & ROMBUFFERMASK); return read_buffer + (offset & rombufmask);
} }
static struct cramfs_inode *cramfs_iget(struct cramfs_inode *i) static struct cramfs_inode *cramfs_iget(struct cramfs_inode *i)
@ -701,10 +707,21 @@ int main(int argc, char **argv)
test_super(&start, &length); test_super(&start, &length);
test_crc(start); test_crc(start);
if(opt_extract) { if (opt_extract) {
size_t bufsize = 0;
if (blksize == 0) if (blksize == 0)
blksize = getpagesize(); blksize = getpagesize();
/* re-calculate according to blksize */
bufsize = rombufsize = blksize * 2;
rombufbits = 0;
while (bufsize >>= 1)
rombufbits++;
rombufmask = rombufsize - 1;
outbuffer = xmalloc(blksize * 2); outbuffer = xmalloc(blksize * 2);
read_buffer = xmalloc(rombufsize * 2);
test_fs(start); test_fs(start);
} }