Better kernel decompression.
committer: mfx <mfx> 978531885 +0000
This commit is contained in:
+1
-1
@@ -69,7 +69,7 @@ const int *PackElks8086::getFilters() const
|
|||||||
// common util routines
|
// common util routines
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
int PackElks8086::uncompressKernel()
|
int PackElks8086::decompressKernel()
|
||||||
{
|
{
|
||||||
// not used
|
// not used
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+66
-20
@@ -129,9 +129,9 @@ int PackVmlinuzI386::readFileHeader()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// read full kernel into obuf, gzip-uncompress into ibuf,
|
// read full kernel into obuf[], gzip-decompress into ibuf[],
|
||||||
// return uncompressed size
|
// return decompressed size
|
||||||
int PackVmlinuzI386::uncompressKernel()
|
int PackVmlinuzI386::decompressKernel()
|
||||||
{
|
{
|
||||||
// read whole kernel image
|
// read whole kernel image
|
||||||
obuf.alloc(file_size);
|
obuf.alloc(file_size);
|
||||||
@@ -140,28 +140,77 @@ int PackVmlinuzI386::uncompressKernel()
|
|||||||
|
|
||||||
checkAlreadyPacked(obuf + setup_size, UPX_MIN(file_size - setup_size, 1024));
|
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++)
|
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);
|
int off = find(obuf + gzoff, file_size - gzoff, "\x1F\x8B\x08", 3);
|
||||||
if (off < 0)
|
if (off < 0)
|
||||||
break;
|
break;
|
||||||
gzoff += off;
|
gzoff += off;
|
||||||
// try to decompress
|
if (gzoff + 256 >= file_size)
|
||||||
fi->seek(gzoff, SEEK_SET);
|
|
||||||
gzFile zf = gzdopen(fi->getFd(), "r");
|
|
||||||
if (zf == 0)
|
|
||||||
break;
|
break;
|
||||||
int klen = gzread(zf, ibuf, ibuf.getSize());
|
// check gzip flag byte
|
||||||
if (klen <= file_size)
|
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;
|
continue;
|
||||||
|
|
||||||
// FIXME: check for special magic bytes in ibuf ???
|
if (klen <= file_size - gzoff)
|
||||||
// FIXME: check for kernel architecture ???
|
continue;
|
||||||
// FIXME: check for special klen size, e.g. (klen & 0xfff) == 0 ???
|
|
||||||
|
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;
|
return klen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,12 +220,9 @@ int PackVmlinuzI386::uncompressKernel()
|
|||||||
|
|
||||||
void PackVmlinuzI386::readKernel()
|
void PackVmlinuzI386::readKernel()
|
||||||
{
|
{
|
||||||
int klen = uncompressKernel();
|
int klen = decompressKernel();
|
||||||
if (klen <= 0)
|
if (klen <= 0)
|
||||||
throwCantPack("kernel decompression failed");
|
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);
|
//OutputFile::dump("kernel.img", ibuf, klen);
|
||||||
|
|
||||||
// copy the setup boot code
|
// copy the setup boot code
|
||||||
|
|||||||
+2
-2
@@ -53,7 +53,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int readFileHeader();
|
virtual int readFileHeader();
|
||||||
virtual int uncompressKernel();
|
virtual int decompressKernel();
|
||||||
virtual void readKernel();
|
virtual void readKernel();
|
||||||
|
|
||||||
virtual int buildLoader(const Filter *ft);
|
virtual int buildLoader(const Filter *ft);
|
||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
virtual int canUnpack();
|
virtual int canUnpack();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int uncompressKernel();
|
virtual int decompressKernel();
|
||||||
virtual void readKernel();
|
virtual void readKernel();
|
||||||
|
|
||||||
virtual int buildLoader(const Filter *ft);
|
virtual int buildLoader(const Filter *ft);
|
||||||
|
|||||||
Reference in New Issue
Block a user