bvmlinuz/386 boot protocol 2.08 has gzipped ELF [needs more work]

This commit is contained in:
John Reiser 2008-07-18 15:02:28 -07:00
parent aedf8dad15
commit b05ba7683e
2 changed files with 56 additions and 7 deletions

View File

@ -28,6 +28,7 @@
#include "conf.h"
#include "p_elf.h"
#include "file.h"
#include "filter.h"
#include "packer.h"
@ -54,7 +55,7 @@ PackVmlinuzI386::PackVmlinuzI386(InputFile *f) :
super(f), physical_start(0x100000), page_offset(0), config_physical_align(0)
{
bele = &N_BELE_RTP::le_policy;
COMPILE_TIME_ASSERT(sizeof(boot_sect_t) == 0x218);
COMPILE_TIME_ASSERT(sizeof(boot_sect_t) == 0x250);
}
@ -102,8 +103,6 @@ bool PackVmlinuzI386::canPack()
int PackVmlinuzI386::readFileHeader()
{
boot_sect_t h;
setup_size = 0;
fi->readx(&h, sizeof(h));
@ -232,14 +231,18 @@ int PackVmlinuzI386::decompressKernel()
checkAlreadyPacked(obuf + setup_size, UPX_MIN(file_size - setup_size, (off_t)1024));
for (int gzoff = setup_size; gzoff < file_size; gzoff++)
int gzoff = setup_size;
if (0x208<=h.version) {
gzoff += h.payload_offset;
}
for (; gzoff < file_size; gzoff++)
{
// 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;
const int gzlen = file_size - gzoff;
const int gzlen = (h.version < 0x208) ? (file_size - gzoff) : h.payload_length;
if (gzlen < 256)
break;
// check gzip flag byte
@ -288,6 +291,45 @@ int PackVmlinuzI386::decompressKernel()
if (klen <= gzlen)
continue;
if (0x208<=h.version && 0==memcmp("\177ELF", ibuf, 4)) {
// Full ELF in theory; but for now, try to handle as .bin.
// Check for PT_LOAD.p_paddr being ascending and adjacent.
Elf_LE32_Ehdr const *const ehdr = (Elf_LE32_Ehdr const *)(void const *)ibuf;
Elf_LE32_Phdr const *phdr = (Elf_LE32_Phdr const *)(ehdr->e_phoff + (char const *)ehdr);
Elf_LE32_Shdr const *shdr = (Elf_LE32_Shdr const *)(ehdr->e_shoff + (char const *)ehdr);
unsigned hi_paddr = 0, lo_paddr = 0;
unsigned delta_off = 0;
for (unsigned j=0; j < ehdr->e_phnum; ++j, ++phdr) {
if (phdr->PT_LOAD==phdr->p_type) {
unsigned step = (-1+ phdr->p_align + hi_paddr) & ~(-1+ phdr->p_align);
if (0==hi_paddr) {
delta_off = phdr->p_paddr - phdr->p_offset;
lo_paddr = phdr->p_paddr;
hi_paddr = phdr->p_filesz + phdr->p_paddr;
}
else if (step==phdr->p_paddr
&& delta_off==(phdr->p_paddr - phdr->p_offset)) {
hi_paddr = phdr->p_filesz + phdr->p_paddr;
}
else {
return 0; // Not equivalent to a .bin. Too complex for now.
}
}
}
unsigned xlen = 0;
for (unsigned j=1; j < ehdr->e_shnum; ++j) {
if (shdr->SHF_EXECINSTR & shdr[j].sh_flags) {
xlen += shdr[j].sh_size; // FIXME: include sh_addralign
}
else {
break;
}
}
//printf("xlen = 0x%x\n", xlen); // FIXME: use as length to filter
memmove(ibuf, (lo_paddr - delta_off) + ibuf, hi_paddr - lo_paddr); // FIXME: set_size
// FIXME: .bss ? Apparently handled by head.S
}
if (opt->force > 0)
return klen;
@ -426,6 +468,7 @@ void PackVmlinuzI386::pack(OutputFile *fo)
boot_sect_t * const bs = (boot_sect_t *) ((unsigned char *) setup_buf);
bs->sys_size = ALIGN_UP(lsize + ph.c_len, 16u) / 16;
bs->payload_length = ph.c_len;
fo->write(setup_buf, setup_buf.getSize());
fo->write(loader, lsize);

View File

@ -80,11 +80,17 @@ protected:
unsigned char load_flags;
char ______[2];
LE32 code32_start;
char _7[0x230 - (0x214 + 4)];
LE32 kernel_alignment;
char relocatable_kernel;
char _8[0x248 - (0x234 + 1)];
LE32 payload_offset;
LE32 payload_length;
// some more uninteresting fields here ...
// see /usr/src/linux/Documentation/i386/zero-page.txt
// see /usr/src/linux/Documentation/i386/boot.txt
}
__attribute_packed;
__attribute_packed h;
MemBuffer setup_buf;
int setup_size;