mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
4a57be824c
This converts the return value of File::read_link() from String to ErrorOr<String>. The rest of the change is to support the potential of an Error being returned and subsequent release of the value when no Error is returned. Unfortunately at this stage none of the places affected can utililize our TRY() macro.
306 lines
9.9 KiB
C++
306 lines
9.9 KiB
C++
/*
|
|
* Copyright (c) 2021, the SerenityOS developers.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibC/elf.h>
|
|
#include <LibCore/File.h>
|
|
#include <LibTest/TestCase.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
TEST_CASE(test_interp_header_tiny_p_filesz)
|
|
{
|
|
char buffer[0x2000];
|
|
|
|
auto& header = *(Elf32_Ehdr*)buffer;
|
|
header.e_ident[EI_MAG0] = ELFMAG0;
|
|
header.e_ident[EI_MAG1] = ELFMAG1;
|
|
header.e_ident[EI_MAG2] = ELFMAG2;
|
|
header.e_ident[EI_MAG3] = ELFMAG3;
|
|
header.e_ident[EI_CLASS] = ELFCLASS32;
|
|
header.e_ident[EI_DATA] = ELFDATA2LSB;
|
|
header.e_ident[EI_VERSION] = EV_CURRENT;
|
|
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
|
header.e_ident[EI_ABIVERSION] = 0;
|
|
header.e_type = ET_REL;
|
|
header.e_version = EV_CURRENT;
|
|
header.e_ehsize = sizeof(Elf32_Ehdr);
|
|
header.e_machine = EM_386;
|
|
header.e_shentsize = sizeof(Elf32_Shdr);
|
|
header.e_phnum = 1;
|
|
header.e_phoff = 52; // inaccurate
|
|
header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate
|
|
header.e_shnum = 3; // inaccurate
|
|
header.e_shoff = 1024; // inaccurate
|
|
header.e_shstrndx = 2; // inaccurate
|
|
header.e_entry = 1024; // inaccurate
|
|
|
|
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
|
|
ph[0].p_flags = PF_R | PF_X;
|
|
ph[0].p_vaddr = 0x00d4;
|
|
ph[0].p_align = PAGE_SIZE;
|
|
ph[0].p_type = PT_INTERP;
|
|
ph[0].p_memsz = 0xffff0000;
|
|
ph[0].p_offset = 0x100;
|
|
|
|
// p_filesz (1 or less) to trigger crash
|
|
ph[0].p_filesz = 1;
|
|
|
|
char path[] = "/tmp/test-elf.XXXXXX";
|
|
auto fd = mkstemp(path);
|
|
EXPECT_NE(fd, -1);
|
|
EXPECT_EQ(fchmod(fd, 0700), 0);
|
|
|
|
int nwritten = write(fd, buffer, sizeof(buffer));
|
|
EXPECT(nwritten);
|
|
|
|
auto elf_path_or_error = Core::File::read_link(String::formatted("/proc/{}/fd/{}", getpid(), fd));
|
|
EXPECT(!elf_path_or_error.is_error());
|
|
|
|
auto elf_path = elf_path_or_error.release_value();
|
|
EXPECT(elf_path.characters());
|
|
|
|
int rc = execl(elf_path.characters(), "test-elf", nullptr);
|
|
EXPECT_EQ(rc, -1);
|
|
EXPECT_EQ(errno, 8);
|
|
|
|
EXPECT_EQ(unlink(path), 0);
|
|
}
|
|
|
|
TEST_CASE(test_interp_header_p_filesz_larger_than_p_memsz)
|
|
{
|
|
char buffer[0x2000];
|
|
|
|
auto& header = *(Elf32_Ehdr*)buffer;
|
|
header.e_ident[EI_MAG0] = ELFMAG0;
|
|
header.e_ident[EI_MAG1] = ELFMAG1;
|
|
header.e_ident[EI_MAG2] = ELFMAG2;
|
|
header.e_ident[EI_MAG3] = ELFMAG3;
|
|
header.e_ident[EI_CLASS] = ELFCLASS32;
|
|
header.e_ident[EI_DATA] = ELFDATA2LSB;
|
|
header.e_ident[EI_VERSION] = EV_CURRENT;
|
|
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
|
header.e_ident[EI_ABIVERSION] = 0;
|
|
header.e_type = ET_REL;
|
|
header.e_version = EV_CURRENT;
|
|
header.e_ehsize = sizeof(Elf32_Ehdr);
|
|
header.e_machine = EM_386;
|
|
header.e_shentsize = sizeof(Elf32_Shdr);
|
|
header.e_phnum = 1;
|
|
header.e_phoff = 52; // inaccurate
|
|
header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate
|
|
header.e_shnum = 3; // inaccurate
|
|
header.e_shoff = 1024; // inaccurate
|
|
header.e_shstrndx = 2; // inaccurate
|
|
header.e_entry = 1024; // inaccurate
|
|
|
|
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
|
|
ph[0].p_flags = PF_R | PF_X;
|
|
ph[0].p_vaddr = 0x00d4;
|
|
ph[0].p_align = PAGE_SIZE;
|
|
ph[0].p_type = PT_INTERP;
|
|
ph[0].p_memsz = 0xffff0000;
|
|
ph[0].p_offset = 0x1000;
|
|
ph[0].p_filesz = 0x1000;
|
|
|
|
char path[] = "/tmp/test-elf.XXXXXX";
|
|
auto fd = mkstemp(path);
|
|
EXPECT_NE(fd, -1);
|
|
EXPECT_EQ(fchmod(fd, 0700), 0);
|
|
|
|
int nwritten = write(fd, buffer, sizeof(buffer));
|
|
EXPECT(nwritten);
|
|
|
|
auto elf_path_or_error = Core::File::read_link(String::formatted("/proc/{}/fd/{}", getpid(), fd));
|
|
EXPECT(!elf_path_or_error.is_error());
|
|
|
|
auto elf_path = elf_path_or_error.release_value();
|
|
EXPECT(elf_path.characters());
|
|
|
|
int rc = execl(elf_path.characters(), "test-elf", nullptr);
|
|
EXPECT_EQ(rc, -1);
|
|
EXPECT_EQ(errno, 8);
|
|
|
|
EXPECT_EQ(unlink(path), 0);
|
|
}
|
|
|
|
TEST_CASE(test_interp_header_p_filesz_plus_p_offset_overflow_p_memsz)
|
|
{
|
|
char buffer[0x2000];
|
|
|
|
auto& header = *(Elf32_Ehdr*)buffer;
|
|
header.e_ident[EI_MAG0] = ELFMAG0;
|
|
header.e_ident[EI_MAG1] = ELFMAG1;
|
|
header.e_ident[EI_MAG2] = ELFMAG2;
|
|
header.e_ident[EI_MAG3] = ELFMAG3;
|
|
header.e_ident[EI_CLASS] = ELFCLASS32;
|
|
header.e_ident[EI_DATA] = ELFDATA2LSB;
|
|
header.e_ident[EI_VERSION] = EV_CURRENT;
|
|
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
|
header.e_ident[EI_ABIVERSION] = 0;
|
|
header.e_type = ET_REL;
|
|
header.e_version = EV_CURRENT;
|
|
header.e_ehsize = sizeof(Elf32_Ehdr);
|
|
header.e_machine = EM_386;
|
|
header.e_shentsize = sizeof(Elf32_Shdr);
|
|
header.e_phoff = 52; // inaccurate
|
|
header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate
|
|
header.e_shnum = 3; // inaccurate
|
|
header.e_shoff = 1024; // inaccurate
|
|
header.e_shstrndx = 2; // inaccurate
|
|
header.e_entry = 1024; // inaccurate
|
|
|
|
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
|
|
ph[0].p_flags = PF_R | PF_X;
|
|
ph[0].p_vaddr = 0x00d4;
|
|
ph[0].p_align = PAGE_SIZE;
|
|
ph[0].p_type = PT_INTERP;
|
|
|
|
// p_memsz must be of sufficient size to hold maxint - 0x1000
|
|
ph[0].p_memsz = 0xfffff000;
|
|
|
|
// p_offset + p_filesz must not exceed buffer size in order to pass buffer size check in ELF::validate_program_headers().
|
|
// p_memsz + p_offset must be sufficiently large to overflow maxint.
|
|
ph[0].p_offset = 0x1234;
|
|
ph[0].p_filesz = -0x1000;
|
|
|
|
char path[] = "/tmp/test-elf.XXXXXX";
|
|
auto fd = mkstemp(path);
|
|
EXPECT_NE(fd, -1);
|
|
EXPECT_EQ(fchmod(fd, 0700), 0);
|
|
|
|
int nwritten = write(fd, buffer, sizeof(buffer));
|
|
EXPECT(nwritten);
|
|
|
|
auto elf_path_or_error = Core::File::read_link(String::formatted("/proc/{}/fd/{}", getpid(), fd));
|
|
EXPECT(!elf_path_or_error.is_error());
|
|
|
|
auto elf_path = elf_path_or_error.release_value();
|
|
EXPECT(elf_path.characters());
|
|
|
|
int rc = execl(elf_path.characters(), "test-elf", nullptr);
|
|
EXPECT_EQ(rc, -1);
|
|
EXPECT_EQ(errno, 8);
|
|
|
|
EXPECT_EQ(unlink(path), 0);
|
|
}
|
|
|
|
TEST_CASE(test_load_header_p_memsz_zero)
|
|
{
|
|
char buffer[0x2000];
|
|
|
|
auto& header = *(Elf32_Ehdr*)buffer;
|
|
header.e_ident[EI_MAG0] = ELFMAG0;
|
|
header.e_ident[EI_MAG1] = ELFMAG1;
|
|
header.e_ident[EI_MAG2] = ELFMAG2;
|
|
header.e_ident[EI_MAG3] = ELFMAG3;
|
|
header.e_ident[EI_CLASS] = ELFCLASS32;
|
|
header.e_ident[EI_DATA] = ELFDATA2LSB;
|
|
header.e_ident[EI_VERSION] = EV_CURRENT;
|
|
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
|
header.e_ident[EI_ABIVERSION] = 0;
|
|
header.e_type = ET_REL;
|
|
header.e_version = EV_CURRENT;
|
|
header.e_ehsize = sizeof(Elf32_Ehdr);
|
|
header.e_machine = EM_386;
|
|
header.e_shentsize = sizeof(Elf32_Shdr);
|
|
header.e_phoff = 52; // inaccurate
|
|
header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate
|
|
header.e_shnum = 3; // inaccurate
|
|
header.e_shoff = 1024; // inaccurate
|
|
header.e_shstrndx = 2; // inaccurate
|
|
header.e_entry = 1024; // inaccurate
|
|
|
|
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
|
|
ph[0].p_flags = PF_R | PF_X;
|
|
ph[0].p_vaddr = 0x00d4;
|
|
ph[0].p_align = PAGE_SIZE;
|
|
ph[0].p_type = PT_LOAD;
|
|
ph[0].p_offset = 0;
|
|
ph[0].p_filesz = 0;
|
|
|
|
// p_memsz zero to trigger crash
|
|
ph[0].p_memsz = 0;
|
|
|
|
char path[] = "/tmp/test-elf.XXXXXX";
|
|
auto fd = mkstemp(path);
|
|
EXPECT_NE(fd, -1);
|
|
EXPECT_EQ(fchmod(fd, 0700), 0);
|
|
|
|
int nwritten = write(fd, buffer, sizeof(buffer));
|
|
EXPECT(nwritten);
|
|
|
|
auto elf_path_or_error = Core::File::read_link(String::formatted("/proc/{}/fd/{}", getpid(), fd));
|
|
EXPECT(!elf_path_or_error.is_error());
|
|
|
|
auto elf_path = elf_path_or_error.release_value();
|
|
EXPECT(elf_path.characters());
|
|
|
|
int rc = execl(elf_path.characters(), "test-elf", nullptr);
|
|
EXPECT_EQ(rc, -1);
|
|
EXPECT_EQ(errno, 8);
|
|
|
|
EXPECT_EQ(unlink(path), 0);
|
|
}
|
|
|
|
TEST_CASE(test_load_header_p_memsz_not_equal_to_p_align)
|
|
{
|
|
char buffer[0x2000];
|
|
|
|
auto& header = *(Elf32_Ehdr*)buffer;
|
|
header.e_ident[EI_MAG0] = ELFMAG0;
|
|
header.e_ident[EI_MAG1] = ELFMAG1;
|
|
header.e_ident[EI_MAG2] = ELFMAG2;
|
|
header.e_ident[EI_MAG3] = ELFMAG3;
|
|
header.e_ident[EI_CLASS] = ELFCLASS32;
|
|
header.e_ident[EI_DATA] = ELFDATA2LSB;
|
|
header.e_ident[EI_VERSION] = EV_CURRENT;
|
|
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
|
header.e_ident[EI_ABIVERSION] = 0;
|
|
header.e_type = ET_REL;
|
|
header.e_version = EV_CURRENT;
|
|
header.e_ehsize = sizeof(Elf32_Ehdr);
|
|
header.e_machine = EM_386;
|
|
header.e_shentsize = sizeof(Elf32_Shdr);
|
|
header.e_phoff = 52; // inaccurate
|
|
header.e_phentsize = sizeof(Elf32_Phdr); // inaccurate
|
|
header.e_shnum = 3; // inaccurate
|
|
header.e_shoff = 1024; // inaccurate
|
|
header.e_shstrndx = 2; // inaccurate
|
|
header.e_entry = 1024; // inaccurate
|
|
|
|
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
|
|
ph[0].p_flags = PF_R | PF_X;
|
|
ph[0].p_vaddr = 0x00d4;
|
|
ph[0].p_type = PT_LOAD;
|
|
ph[0].p_memsz = 0xffff0000;
|
|
ph[0].p_offset = 0x1000;
|
|
ph[0].p_filesz = 0x1000;
|
|
|
|
// p_align not equal to PAGE_SIZE to trigger crash
|
|
ph[0].p_align = PAGE_SIZE / 2;
|
|
|
|
char path[] = "/tmp/test-elf.XXXXXX";
|
|
auto fd = mkstemp(path);
|
|
EXPECT_NE(fd, -1);
|
|
EXPECT_EQ(fchmod(fd, 0700), 0);
|
|
|
|
int nwritten = write(fd, buffer, sizeof(buffer));
|
|
EXPECT(nwritten);
|
|
|
|
auto elf_path_or_error = Core::File::read_link(String::formatted("/proc/{}/fd/{}", getpid(), fd));
|
|
EXPECT(!elf_path_or_error.is_error());
|
|
|
|
auto elf_path = elf_path_or_error.release_value();
|
|
EXPECT(elf_path.characters());
|
|
|
|
int rc = execl(elf_path.characters(), "test-elf", nullptr);
|
|
EXPECT_EQ(rc, -1);
|
|
EXPECT_EQ(errno, 8);
|
|
|
|
EXPECT_EQ(unlink(path), 0);
|
|
}
|