blob: 10d2bce1c96b48bc9197def2390338e3a3e40f59 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "linux-static-pie.h"
#include <lib/elfldltl/diagnostics.h>
#include <lib/elfldltl/relro.h>
#include <lib/elfldltl/static-pie.h>
#include <link.h>
#include <sys/mman.h>
#include <initializer_list>
#include <string_view>
#include <tuple>
#include "lss.h"
namespace {
using namespace std::literals;
void WriteStderr(std::initializer_list<std::string_view> strings) {
for (auto str : strings) {
sys_write(2, str.data(), str.size());
}
}
constexpr auto Panic = [](std::string_view error, auto&&... args) -> bool {
WriteStderr({"Failure in static PIE initialization: "sv, error, "\n"sv});
while (true) {
sys_exit_group(127);
}
};
size_t GetPageSize(const uintptr_t* start_sp) {
// We need to locate and decode the auxv just to get the page size!
using Auxv = ElfW(auxv_t);
const Auxv* auxv;
{
const auto argc = start_sp[0];
const auto* const argv = &start_sp[1];
const auto* const envp = &argv[argc + 1];
auto envp_end = envp;
while (*envp_end != 0) {
++envp_end;
}
auxv = reinterpret_cast<const Auxv*>(envp_end + 1);
}
size_t pagesize = 0;
for (const auto* av = auxv; av->a_type != AT_NULL; ++av) {
if (av->a_type == AT_PAGESZ) {
pagesize = av->a_un.a_val;
break;
}
}
if (pagesize == 0) {
Panic("no AT_PAGESZ found in auxv!"sv);
}
return pagesize;
}
void ProtectRelro(uintptr_t start, size_t size) {
if (size > 0) {
start += elfldltl::Self<>::LoadBias();
auto ptr = reinterpret_cast<const void*>(start);
if (sys_mprotect(ptr, size, PROT_READ) != 0) {
Panic("cannot mprotect RELRO"sv);
}
}
}
} // namespace
// This is passed the starting value of the stack pointer as set by the kernel
// on execve.
extern "C" void StaticPieSetup(uintptr_t* start_sp) {
elfldltl::Diagnostics diag(Panic, elfldltl::DiagnosticsPanicFlags());
// Apply relocations.
elfldltl::LinkStaticPie(elfldltl::Self<>(), diag);
// Now protect the RELRO segment.
std::apply(ProtectRelro, elfldltl::RelroBounds(elfldltl::Self<>::Phdrs(), GetPageSize(start_sp)));
}