An open API service indexing awesome lists of open source software.

https://github.com/rrbutani/rtld-shim


https://github.com/rrbutani/rtld-shim

bazel bazelcon25 hermetic-builds rtld

Last synced: 26 days ago
JSON representation

Awesome Lists containing this project

README

          

# Runtime Loader Shim

## what

## why

## how

#### normal execution

```mermaid
flowchart TB
exec["`exec path/to/binary`"]

bin_load@{ shape: procs, label: "mmap from binary"}

interp@{ shape: hex, label: "has
PT_INTERP?" }

interp_load@{ shape: procs, label: "mmap from ld.so"}

bin_entry@{ shape: stadium, label: "➡️ binary's entrypoint" }

interp_entry@{ shape: stadium, label: "➡️ ld.so's entrypoint" }

interp_run@{ shape: procs, label: "resolve dylibs
apply relocations" }

%% edges:

exec --> bin_load --> interp

interp -- "`no`" --> bin_entry

interp -- "`yes
/lib64/ld-linux-x86-64.so.2`" --> interp_load

interp_load --> interp_entry --> interp_run --> bin_entry

style interp fill:#444
```

#### explicit `ld.so` invocation

```mermaid
flowchart TB
exec["`exec ld.so path/to/binary`"]

bin_load@{ shape: procs, label: "mmap from binary"}

interp_load@{ shape: procs, label: "mmap from ld.so"}

bin_entry@{ shape: stadium, label: "➡️ binary's entrypoint" }

interp_entry@{ shape: stadium, label: "➡️ ld.so's entrypoint" }

interp_run@{ shape: procs, label: "resolve dylibs
apply relocations" }

%% edges:

exec --> interp_load --> interp_entry --> bin_load --> interp_run --> bin_entry
```

#### with loader shim

```mermaid
flowchart TB
exec["exec path/to/binary
(patched w/loader shim)"]

bin_load@{ shape: procs, label: "mmap from binary"}

interp@{ shape: hex, label: "has
PT_INTERP?" }

bin_entry@{ shape: stadium, label: "➡️ binary's entrypoint
(loader shim)" }

under_rtld@{ shape: hex, label: "under ld.so?" }

%% edges:

exec --> bin_load --> interp

interp -- "`no`" --> bin_entry --> under_rtld

under_rtld -- "no" --> runfiles_lookup --> rtld_exec
under_rtld -- "yes" --> rtld_bin_entry

style interp fill:#444
style under_rtld fill:#444

subgraph rtld_exec_sub ["."]
direction TB
rtld_exec["`exec ld.so path/to/binary`"]

rtld_bin_load@{ shape: procs, label: "mmap from binary"}

rtld_load@{ shape: procs, label: "mmap from ld.so"}

rtld_bin_entry@{ shape: stadium, label: "➡️ binary's entrypoint
(original)" }

rtld_entry@{ shape: stadium, label: "➡️ ld.so's entrypoint" }

rtld_run@{ shape: procs, label: "resolve dylibs
apply relocations" }

runfiles_lookup@{ shape: event, label: "runfiles lookup
for ld.so" }

under_rtld@{ shape: hex, label: "under ld.so?" }

%% edges:

rtld_exec --> rtld_load --> rtld_entry --> rtld_bin_load --> rtld_run --> bin_entry
end
```

## demo?

> [!CAUTION]
> Hacky, coupled to Bazel 8, x86-64 only for now.

> [!IMPORTANT]
> As of this writing, Bazel's experimental hermetic linux sandbox does not set up procfs appropriately; this causes `ld.so` to fail to canonicalize program paths which then causes shared object resolution (i.e. for `DT_NEEDED` entries with `$ORIGIN` and such) to fail.

1. Set up an RBE service of your choosing to use an [empty container image](bzl/Dockerfile) for action execution
- the [bundled example workspace's `--config=rbe`](bzl/.bazelrc) is set up for [buildbuddy](https://www.buildbuddy.io/) w/the [`rrbutani/empty`](https://hub.docker.com/repository/docker/rrbutani/empty/general) container image
+ be sure to create an account, get an API key, and place it in `bzl/.buildbuddy-api-key.bazelrc`
2. Run `bazel build //:out --config=rbe` in [`bzl`](./bzl/)
- if you're using [`nix`](flake.nix) + [`direnv`](bzl/.envrc), Bazel 8.4.2 will be fetched for you; if not you'll need to [grab it yourself](https://github.com/bazelbuild/bazelisk)