Correct ELF alignment settings
This commit is contained in:
parent
545efaa155
commit
e92fbe3e69
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
},
|
||||
vm::{
|
||||
perms::VmPerms,
|
||||
vmar::{VMAR_LOWEST_ADDR, Vmar},
|
||||
vmar::{VMAR_CAP_ADDR, VMAR_LOWEST_ADDR, Vmar},
|
||||
vmo::Vmo,
|
||||
},
|
||||
};
|
||||
|
|
@ -205,24 +205,28 @@ fn map_segment_vmos(
|
|||
let map_range = if elf.is_shared_object() {
|
||||
// Relocatable object.
|
||||
|
||||
let align = elf.max_load_align();
|
||||
|
||||
// Given that `elf_va_range` is guaranteed to be below `VMAR_CAP_ADDR`, as long as
|
||||
// `VMAR_CAP_ADDR * 2` does not overflow, the following `align_up(align)` cannot overflow
|
||||
// either.
|
||||
const { assert!(VMAR_CAP_ADDR.checked_mul(2).is_some()) };
|
||||
|
||||
// Allocate a continuous range of virtual memory for all segments in advance.
|
||||
//
|
||||
// All segments in the ELF program must be mapped to a continuous VM range to
|
||||
// ensure the relative offset of each segment not changed.
|
||||
let elf_va_range_aligned =
|
||||
elf_va_range.start.align_down(PAGE_SIZE)..elf_va_range.end.align_up(PAGE_SIZE);
|
||||
elf_va_range.start.align_down(align)..elf_va_range.end.align_up(align);
|
||||
let map_size = elf_va_range_aligned.len();
|
||||
|
||||
let vmar_map_options = vmar
|
||||
.new_map(map_size, VmPerms::empty())?
|
||||
.align(elf.max_load_align())
|
||||
.handle_page_faults_around();
|
||||
let vmar_map_options = vmar.new_map(map_size, VmPerms::empty())?.align(align);
|
||||
let aligned_range = vmar_map_options.build().map(|addr| addr..addr + map_size)?;
|
||||
|
||||
let start_in_page_offset = elf_va_range.start - elf_va_range_aligned.start;
|
||||
let end_in_page_offset = elf_va_range_aligned.end - elf_va_range.end;
|
||||
let start_offset = elf_va_range.start - elf_va_range_aligned.start;
|
||||
let end_offset = elf_va_range_aligned.end - elf_va_range.end;
|
||||
|
||||
aligned_range.start + start_in_page_offset..aligned_range.end - end_in_page_offset
|
||||
aligned_range.start + start_offset..aligned_range.end - end_offset
|
||||
} else {
|
||||
// Not relocatable object. Map as-is.
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ static struct custom_elf elf;
|
|||
#define UD2_INSTR \
|
||||
"\x0f\x0b" // "ud2" in x86-64. TODO: Support other architectures.
|
||||
|
||||
FN_SETUP(init)
|
||||
FN_SETUP(init_exec)
|
||||
{
|
||||
elf.ehdr.e_ident[EI_MAG0] = ELFMAG0;
|
||||
elf.ehdr.e_ident[EI_MAG1] = ELFMAG1;
|
||||
|
|
@ -71,23 +71,30 @@ static int do_execve(void)
|
|||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
FN_TEST(good)
|
||||
static int do_execve_good(void)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
// First of all, verify that `elf` is a good ELF.
|
||||
|
||||
memcpy(elf.buf, UD2_INSTR, sizeof(UD2_INSTR));
|
||||
|
||||
pid = TEST_SUCC(fork());
|
||||
pid = CHECK(fork());
|
||||
if (pid == 0) {
|
||||
CHECK(do_execve());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
TEST_RES(wait(&status), _ret == pid && WIFSIGNALED(status) &&
|
||||
WTERMSIG(status) == SIGILL);
|
||||
CHECK_WITH(wait(&status), _ret == pid);
|
||||
if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGILL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FN_TEST(good_exec)
|
||||
{
|
||||
// First of all, verify that `elf` is a good ELF.
|
||||
TEST_RES(do_execve_good(), _ret == 0);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
|
|
@ -418,6 +425,71 @@ FN_TEST(filesz_larger_than_memsz)
|
|||
}
|
||||
END_TEST()
|
||||
|
||||
// ==========================
|
||||
// Below are tests for ET_DYN
|
||||
// ==========================
|
||||
|
||||
FN_SETUP(init_dyn)
|
||||
{
|
||||
elf.ehdr.e_type = ET_DYN;
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_TEST(good_dyn)
|
||||
{
|
||||
// First of all, verify that `elf` is a good ELF.
|
||||
TEST_RES(do_execve_good(), _ret == 0);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_TEST(bad_align)
|
||||
{
|
||||
long old;
|
||||
|
||||
old = elf.phdr[0].p_align;
|
||||
|
||||
// 2048 is smaller than PAGE_SIZE.
|
||||
elf.phdr[0].p_align = 2048;
|
||||
TEST_RES(do_execve_good(), _ret == 0);
|
||||
|
||||
// 2047 is not a power of two.
|
||||
elf.phdr[0].p_align = 2047;
|
||||
TEST_RES(do_execve_good(), _ret == 0);
|
||||
|
||||
elf.phdr[0].p_align = old;
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_TEST(large_align)
|
||||
{
|
||||
long old;
|
||||
|
||||
old = elf.phdr[0].p_align;
|
||||
|
||||
elf.phdr[0].p_align = 1ul << 21;
|
||||
TEST_RES(do_execve_good(), _ret == 0);
|
||||
|
||||
elf.phdr[0].p_align = 1ul << 42;
|
||||
TEST_RES(do_execve_good(), _ret == 0);
|
||||
|
||||
elf.phdr[0].p_align = 1ul << 63;
|
||||
// FIXME: p_align exceeds the size of the user address space.
|
||||
// What does this mean? As far as Linux is concerned, it tries
|
||||
// to map to a zero address due to [1], [2], and [3]. This
|
||||
// does not seem to make much sense.
|
||||
// [1]: https://elixir.bootlin.com/linux/v6.19-rc2/source/fs/binfmt_elf.c#L1172
|
||||
// [2]: https://elixir.bootlin.com/linux/v6.19-rc2/source/fs/binfmt_elf.c#L1185
|
||||
// [3]: https://elixir.bootlin.com/linux/v6.19-rc2/source/fs/binfmt_elf.c#L1188
|
||||
#ifdef __asterinas__
|
||||
TEST_ERRNO(do_execve_fatal(), ENOMEM);
|
||||
#else
|
||||
TEST_ERRNO(do_execve_fatal(), EPERM);
|
||||
#endif
|
||||
|
||||
elf.phdr[0].p_align = old;
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_SETUP(cleanup)
|
||||
{
|
||||
CHECK(unlink(EXE_PATH));
|
||||
|
|
|
|||
Loading…
Reference in New Issue