Better kernel decompression.

committer: mfx <mfx> 978531885 +0000
This commit is contained in:
Markus F.X.J. Oberhumer 2001-01-03 14:24:45 +00:00
parent 597143df7f
commit 5ddec963d0
3 changed files with 69 additions and 23 deletions

View File

@ -69,7 +69,7 @@ const int *PackElks8086::getFilters() const
// common util routines
**************************************************************************/
int PackElks8086::uncompressKernel()
int PackElks8086::decompressKernel()
{
// not used
return 0;

View File

@ -129,9 +129,9 @@ int PackVmlinuzI386::readFileHeader()
}
// read full kernel into obuf, gzip-uncompress into ibuf,
// return uncompressed size
int PackVmlinuzI386::uncompressKernel()
// read full kernel into obuf[], gzip-decompress into ibuf[],
// return decompressed size
int PackVmlinuzI386::decompressKernel()
{
// read whole kernel image
obuf.alloc(file_size);
@ -140,28 +140,77 @@ int PackVmlinuzI386::uncompressKernel()
checkAlreadyPacked(obuf + setup_size, UPX_MIN(file_size - setup_size, 1024));
// estimate gzip-uncompressed kernel size & alloc buffer
ibuf.alloc((file_size - setup_size) * 3);
for (int gzoff = setup_size; gzoff < file_size; gzoff++)
{
// find gzip header (2 bytes magic, 1 byte method "deflated")
// find gzip header (2 bytes magic + 1 byte method "deflated")
int off = find(obuf + gzoff, file_size - gzoff, "\x1F\x8B\x08", 3);
if (off < 0)
break;
gzoff += off;
// try to decompress
fi->seek(gzoff, SEEK_SET);
gzFile zf = gzdopen(fi->getFd(), "r");
if (zf == 0)
if (gzoff + 256 >= file_size)
break;
int klen = gzread(zf, ibuf, ibuf.getSize());
if (klen <= file_size)
// check gzip flag byte
unsigned char flags = obuf[gzoff + 3];
if ((flags & 0xe0) != 0) // reserved bits set
continue;
//printf("found gzip header at offset %d\n", gzoff);
// try to decompress
int klen;
int fd;
off_t fd_pos;
for (;;)
{
klen = -1;
fd = -1;
fd_pos = -1;
// open
fi->seek(gzoff, SEEK_SET);
fd = dup(fi->getFd());
if (fd < 0)
break;
gzFile zf = gzdopen(fd, "r");
if (zf == NULL)
break;
// estimate gzip-decompressed kernel size & alloc buffer
if (ibuf.getSize() == 0)
ibuf.alloc((file_size - gzoff) * 3);
// decompress
klen = gzread(zf, ibuf, ibuf.getSize());
fd_pos = lseek(fd, 0, SEEK_CUR);
gzclose(zf);
fd = -1;
if (klen != (int)ibuf.getSize())
break;
// realloc and try again
unsigned s = ibuf.getSize();
ibuf.free();
ibuf.alloc(3 * s / 2);
}
if (fd >= 0)
(void) close(fd);
if (klen <= 0)
continue;
// FIXME: check for special magic bytes in ibuf ???
// FIXME: check for kernel architecture ???
// FIXME: check for special klen size, e.g. (klen & 0xfff) == 0 ???
if (klen <= file_size - gzoff)
continue;
if (opt->force > 0)
return klen;
// some checks
if (fd_pos != file_size)
{
//printf("fd_pos: %ld, file_size: %ld\n", (long)fd_pos, (long)file_size);
throwCantPack("trailing bytes after kernel image; use option `-f' to force packing");
}
// see /usr/src/linux/arch/i386/kernel/head.S:
if (memcmp(ibuf, "\xFC\xB8", 2) != 0)
throwCantPack("unrecognized kernel architecture; use option `-f' to force packing");
// FIXME: more checks for special magic bytes in ibuf ???
// FIXME: more checks for kernel architecture ???
return klen;
}
@ -171,12 +220,9 @@ int PackVmlinuzI386::uncompressKernel()
void PackVmlinuzI386::readKernel()
{
int klen = uncompressKernel();
int klen = decompressKernel();
if (klen <= 0)
throwCantPack("kernel decompression failed");
if (klen >= (int) ibuf.getSize())
throwCantPack("kernel decompression failed -- too big; send a bug report");
//OutputFile::dump("kernel.img", ibuf, klen);
// copy the setup boot code

View File

@ -53,7 +53,7 @@ public:
protected:
virtual int readFileHeader();
virtual int uncompressKernel();
virtual int decompressKernel();
virtual void readKernel();
virtual int buildLoader(const Filter *ft);
@ -125,7 +125,7 @@ public:
virtual int canUnpack();
protected:
virtual int uncompressKernel();
virtual int decompressKernel();
virtual void readKernel();
virtual int buildLoader(const Filter *ft);