Skip to content

Commit

Permalink
[ld] ld::RemoteZygote
Browse files Browse the repository at this point in the history
This implements the "ELF-only zygote model".  After using the
ld::RemoteDynamicLinker API to launch a prototype process, it can
be distilled into a simpler ld::RemoteZygote object that can be
used to launch more identical new processes.

Bug: 326524302
Change-Id: Ie46c239235ad2e2040227cf49ded133761cf57bd
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1013912
Fuchsia-Auto-Submit: Roland McGrath <[email protected]>
Reviewed-by: Caslyn Tonelli <[email protected]>
Commit-Queue: Auto-Submit <[email protected]>
  • Loading branch information
frobtech authored and CQ Bot committed May 23, 2024
1 parent b3cf214 commit 2381222
Show file tree
Hide file tree
Showing 17 changed files with 775 additions and 59 deletions.
1 change: 1 addition & 0 deletions sdk/lib/ld/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ library_headers("headers") {
"lib/ld/remote-decoded-module.h",
"lib/ld/remote-dynamic-linker.h",
"lib/ld/remote-load-module.h",
"lib/ld/remote-zygote.h",
]

public_deps += [
Expand Down
14 changes: 7 additions & 7 deletions sdk/lib/ld/include/lib/ld/remote-abi-heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,10 @@ class RemoteAbiHeapLayout {
// RemoteAbiHeapLayout constructor from RemoteAbiStub::data_size() and a
// mutable RemoteLoadModule describing the same stub dynamic linker ELF file
// presented to RemoteAbiStub::Init.
template <class Elf, class AbiTraits>
template <class RemoteModule, class AbiTraits>
class RemoteAbiHeap {
public:
using Elf = typename RemoteModule::Elf;
using size_type = typename Elf::size_type;
using Addr = typename Elf::Addr;
using Phdr = typename Elf::Phdr;
Expand All @@ -219,8 +220,7 @@ class RemoteAbiHeap {
// of the RemoteAbiHeap object.
template <class Diagnostics>
static zx::result<RemoteAbiHeap> Create(Diagnostics& diagnostics, size_type stub_data_size,
RemoteLoadModule<Elf>& stub_module,
RemoteAbiHeapLayout layout) {
RemoteModule& stub_module, RemoteAbiHeapLayout layout) {
if (!stub_module.PrepareLoadInfo(diagnostics)) [[unlikely]] {
return zx::error{ZX_ERR_NO_MEMORY};
}
Expand All @@ -246,7 +246,7 @@ class RemoteAbiHeap {
auto& new_segment = std::get<StubConstantSegment>(stub_module.load_info().segments().back());

// Build the RemoteAbiHeap.
RemoteAbiHeap<Elf, AbiTraits> heap;
RemoteAbiHeap heap;
heap.strtab_ = strtab.offset_;
heap.size_bytes_ = memsz;

Expand Down Expand Up @@ -278,7 +278,7 @@ class RemoteAbiHeap {
//
// This should only be called on a stub_module that was previously modified
// by a successful Create() call, and has since had its load_bias() set.
static size_type HeapVaddr(const RemoteLoadModule<Elf>& stub_module) {
static size_type HeapVaddr(const RemoteModule& stub_module) {
const auto& segment = stub_module.load_info().segments().back();
const size_type segment_vaddr =
std::visit([](const auto& segment) { return segment.vaddr(); }, segment);
Expand Down Expand Up @@ -366,7 +366,7 @@ class RemoteAbiHeap {
}

private:
using LoadInfo = typename RemoteLoadModule<Elf>::LoadInfo;
using LoadInfo = typename RemoteModule::LoadInfo;
using StubSegment = typename LoadInfo::Segment;
using StubConstantSegment = typename LoadInfo::ConstantSegment;

Expand Down Expand Up @@ -398,7 +398,7 @@ class RemoteAbiHeap {
size_t segment_size) {
assert(file_vmo);

const size_type page_size = RemoteLoadModule<Elf>::Loader::page_size();
const size_type page_size = RemoteModule::Loader::page_size();
const size_type filesz = old_segment.filesz();
const size_type memsz = (segment_size + page_size - 1) & -page_size;

Expand Down
6 changes: 3 additions & 3 deletions sdk/lib/ld/include/lib/ld/remote-abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ namespace ld {
// before laying out the remote address space; Finish is called after address
// space layout is known, to finalize the data.

template <class Elf = elfldltl::Elf<>>
template <class RemoteModule>
class RemoteAbi {
public:
using Elf = typename RemoteModule::Elf;
using AbiStubPtr = typename RemoteAbiStub<Elf>::Ptr;

using size_type = typename Elf::size_type;
using Addr = typename Elf::Addr;
using TlsLayout = elfldltl::TlsLayout<Elf>;

using AbiStub = RemoteAbiStub<Elf>;
using RemoteModule = RemoteLoadModule<Elf>;
using ModuleList = typename RemoteModule::List;

using LocalAbi = abi::Abi<Elf>;
Expand Down Expand Up @@ -171,7 +171,7 @@ class RemoteAbi {
}

private:
using AbiHeap = RemoteAbiHeap<Elf, elfldltl::RemoteAbiTraits>;
using AbiHeap = RemoteAbiHeap<RemoteModule, elfldltl::RemoteAbiTraits>;
using AbiStringPtr = typename AbiHeap::template AbiPtr<const char>;

using Abi = abi::Abi<Elf, elfldltl::RemoteAbiTraits>;
Expand Down
46 changes: 38 additions & 8 deletions sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ namespace ld {
// It may or may not be the first or only dynamic linking session performed on
// the same process. Each dynamic linking session defines its own symbolic
// dynamic linking domain and has its own passive ABI (stub dynamic linker).
// TODO(https://fxbug.dev/326524302): Describe Zygote options.
//
// The second optional template parameter can select the "zygote mode"
// implementation. This is used by the <lib/ld/remote-zygote.h> API, which
// provides the ld::RemoteZygote::Linker alias. The zygote-mode linker is used
// in the same ways as the plain ld::RemoteDynamicLinker described here.
//
// Before creating an ld::RemoteDynamicLinker, the ld::RemoteAbiStub must be
// provided (see <lib/ld/remote-abi-stub.h>). Only a single ld::RemoteAbiStub
Expand Down Expand Up @@ -131,8 +135,9 @@ namespace ld {
// The VMAR handles are no longer available and the VmarLoader objects would
// need to be reinitialized to be used again. The segment VMO handles are
// still available, but when not in zygote mode they are in use by process
// mappings and must not be touched. TODO(https://fxbug.dev/326524302): In
// Zygote mode, it can also be distilled into a zygote.
// mappings and must not be touched. In zygote mode, the relocated segment
// VMOs will be made read-only and then reused (directly for RELRO mappings or
// via copy-on-write copies) to load additional as-relocated process images.
//
// Various other methods are provided for interrogating the list of modules and
// accessing the dynamic linker stub module and the ld::RemoteAbi object.
Expand Down Expand Up @@ -326,8 +331,8 @@ class RemoteDynamicLinker {

// Other accessors should be used only after a successful Init call (below).

RemoteAbi<Elf>& remote_abi() { return remote_abi_; }
const RemoteAbi<Elf>& remote_abi() const { return remote_abi_; }
RemoteAbi<Module>& remote_abi() { return remote_abi_; }
const RemoteAbi<Module>& remote_abi() const { return remote_abi_; }

List& modules() { return modules_; }
const List& modules() const { return modules_; }
Expand Down Expand Up @@ -702,7 +707,28 @@ class RemoteDynamicLinker {
// Resolve against the successfully decoded modules, ignoring the others.
return module.Relocate(diag, valid_modules, tls_desc_resolver);
};
return OnModules(valid_modules, relocate) && FinishAbi(diag);

// After the segments are complete, make sure all the VMO handles are
// read-only so they don't accidentally get mutated. This isn't necessary
// in non-zygote mode since the object won't usually be saved long anyway.
auto protect_segments = [&diag](auto& module) -> bool {
return module.load_info().VisitSegments([&diag](auto& segment) -> bool {
using SegmentType = std::decay_t<decltype(segment)>;
if constexpr (elfldltl::kSegmentHasFilesz<SegmentType>) {
zx::result<> result = segment.MakeImmutable();
if (result.is_error()) [[unlikely]] {
return diag.SystemError( //
"cannot drop ZX_RIGHT_WRITE from finished zygote VMO",
elfldltl::ZirconError{result.error_value()});
}
}
return true;
});
};

return OnModules(valid_modules, relocate) && FinishAbi(diag) &&
(Zygote == RemoteLoadZygote::kNo || // No need for non-zygote.
OnModules(valid_modules, protect_segments));
}

// Load each module into the VMARs created by Allocate. This should only be
Expand Down Expand Up @@ -734,7 +760,11 @@ class RemoteDynamicLinker {
// mappings and must not be disturbed. The VmarLoader object for each module
// will be in moved-from state, and cannot be used without reinitialization.
//
// TODO(https://fxbug.dev/326524302): Describe Zygote options.
// In zygote mode, this object can be moved into the ld::RemoteZygote
// constructor after Commit(). If it's moved in without Commit(), then all
// the mappings made in the original process VMAR will be destroyed and the
// existing process should not be started, but the zygote will still work
// just the same to start more processes.
void Commit() {
for (Module& module : ValidModules()) {
// After this, destroying the module won't destroy its VMAR any more. No
Expand Down Expand Up @@ -849,7 +879,7 @@ class RemoteDynamicLinker {
}

AbiStubPtr abi_stub_;
RemoteAbi<Elf> remote_abi_;
RemoteAbi<Module> remote_abi_;
List modules_;
size_type max_tls_modid_ = 0;
uint32_t stub_modid_ = 0;
Expand Down
Loading

0 comments on commit 2381222

Please sign in to comment.