Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ jobs:
- name: every headline number has exactly one home
run: |
fail=0
for n in 3470 358 66/66 62/62 45/45 40/40 26/26; do
for n in 3470 358 69/69 65/65 45/45 40/40 26/26; do
homes=$(git grep -lF "$n" -- '*.md' ':(exclude)docs/history/*' |
sed 's|^docs/report/.*|docs/report/|' | sort -u | tr '\n' ' ')
count=$(printf '%s' "$homes" | wc -w)
Expand Down
4 changes: 3 additions & 1 deletion docs/integrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ place and no `--library-path` can fix it.

When `libva.so.2` is in the process, the preload assembles the answer: every
host `<libdir>/dri` directory it finds is appended to `LIBVA_DRIVERS_PATH`,
behind anything already set. A process that never loads libva is not touched.
behind anything already set. NixOS is one of those `<libdir>`s, and its VA
drivers live under `/run/opengl-driver/lib/dri`. A process that never loads
libva is not touched.
The bundle's own `lib/dri` is never added. A bundle that ships VA drivers
manages the variable itself, and its entries stay ahead of anything appended
here.
Expand Down
2 changes: 1 addition & 1 deletion docs/report/01-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
| Completion criterion | Status |
|---|---|
| Both goals demonstrated by a test that fails before and passes after | **Yes.** Goal 1: E5, E12. Goal 2: E22/E23 for the mechanism, E30/E32 and E37a/E37 for the end-to-end |
| The evidence harness still reports all predictions held | **Yes, 66/66** on x86-64 and **62/62** on aarch64, up from 22/22. The AppImage suite adds 45 on a glvnd glibc host, 40 on musl, 26 on each of two pre-glvnd glibc hosts and 7 on a real-application stage, with every unrunnable case SKIPPED by the capability it lacks |
| The evidence harness still reports all predictions held | **Yes, 69/69** on x86-64 and **65/65** on aarch64, up from 22/22. The AppImage suite adds 45 on a glvnd glibc host, 40 on musl, 26 on each of two pre-glvnd glibc hosts and 7 on a real-application stage, with every unrunnable case SKIPPED by the capability it lacks |
| No host file modified, verified by checksum | **Yes.** T4.3, identical sha256 before and after |
| Bundled libraries still win, verified via `dladdr` | **Yes.** T4.2, all resolved under `$APPDIR` |
| A forward-compatibility story that does not depend on foresight | **Yes.** Host-runtime selection for the unenumerable gap, a generated shim for the enumerable one, and a build-time audit (E26) for the version traps |
Expand Down
24 changes: 17 additions & 7 deletions docs/report/08-test-results.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,19 @@ wrong.

### Tier 1, the evidence table

`sh scripts/run-evidence.sh` reports **66/66 predictions held on x86-64** and
**62/62 on aarch64**. The x86-64 total was measured at the change that added
E103; the aarch64 runner runs the same table, so its total is the x86-64
total minus the four skips below, and CI re-runs both on every push.
`experiments/run.ps1` drives the same three stage scripts for a machine with
PowerShell and no POSIX shell.
`sh scripts/run-evidence.sh` reports **69/69 predictions held on x86-64** and
**65/65 on aarch64**. The x86-64 total was measured at the change that added
E104, E105 and E106, the cases for the NixOS host directories, which the
container suite runs as root; the aarch64 runner runs the same table, so its
total is the x86-64 total minus the four skips below, and CI re-runs both on
every push. `experiments/run.ps1` drives the same three stage scripts for a
machine with PowerShell and no POSIX shell.

⚠ **The three NixOS cases SKIP by name where `/run` is not writable.** E104,
E105 and E106 each create `/run/opengl-driver/lib`, which needs root, and each
reports the missing capability rather than being silently omitted. That is why
they were added to this table before they were measured: the machine that wrote
them had no root, and CI had it.

⚠ **The two totals differ by exactly the four cases aarch64 SKIPS**, each
naming the capability it lacks rather than the difference being unexplained:
Expand All @@ -43,7 +50,7 @@ naming the capability it lacks rather than the difference being unexplained:

⭐ **E23's skip is the one worth reading.** It was reporting MATCH on the ARM
runner while asserting nothing, and skipping it with E22 is what stopped that.
66 minus 4 is 62, and no case is missing for a reason nobody wrote down.
69 minus 4 is 65, and no case is missing for a reason nobody wrote down.

E1 through E13 measure the problem. E14 through E21 are one per fix from the first pass: the
ELF self-test, the generated-shim compile and behaviour, and five selector
Expand Down Expand Up @@ -76,6 +83,9 @@ objects small enough that the mechanism is the only thing being measured:
| E73 | the distinct-name call count an application can be measured by |
| E75 / E75b | the shim finds a target in a directory only `/etc/ld.so.conf` names, and does not when the conf file is removed |
| E103 | a directory the host names first holds a wrong-class library: the shim skips it and finds the one that loads, instead of reporting no target |
| E104 | the switched runtime's `--library-path` carries `/run/opengl-driver/lib` and `/run/current-system/sw/lib`, which NixOS publishes and no `ld.so.conf` names |
| E105 | the shim finds a target under `/run/opengl-driver/lib`, the directory a NixOS host keeps its GPU userspace in |
| E106 | `LIBVA_DRIVERS_PATH` gets `/run/opengl-driver/lib/dri`, the directory a NixOS host keeps its VA drivers in |
| E75c / E75d / E75e / E75f | a shim with no target serves each name from the provider behind it in the lookup order; the no-preload control; the log line pinning the fallthrough; the same in EAGER mode |
| E76 / E76b | the aarch64 trampolines and resolver RUN, under qemu-user, forwarding and absent paths both |

Expand Down
41 changes: 40 additions & 1 deletion docs/report/09-the-second-boundary.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ Totals with this section in: **40/40 on the musl host** with five named skips,
and ubuntu:16.04 with nineteen named skips, **7/7** on the gtk4 stage, and
**53/53** in the container suite on x86-64, and **50/50** on aarch64 with the
three skips named in section 8, at the measurement this section records; the
totals for the tree as it ships are **66/66** and **62/62** in section 8.
totals for the tree as it ships are **69/69** and **65/65** in section 8.

### 9.8 What the shim does not do, stated as a number

Expand Down Expand Up @@ -1531,6 +1531,45 @@ E103 is the case. It uses the five-name miniature of section O, with the
repair the shim reports `no target`; after it, it reports the `libtgt.so` in the
directory named second and the probe passes.

### 9.22 NixOS is a host class the FHS lists cannot reach

NixOS is neither FHS nor a host that writes its layout down where this project
reads it. It has no `/etc/ld.so.conf`, `/usr/lib` holds no host libraries, and
`hardware.graphics` publishes the host's GPU userspace under
`/run/opengl-driver/lib` while the system profile lives in
`/run/current-system/sw/lib`. Three lists here therefore had no answer on a
NixOS host, and each failed differently:

- `LIBVA_DRIVERS_PATH` never received `/run/opengl-driver/lib/dri`, so a
bundled libva found no host VA driver at all.
- `rs_library_path()` never put the two directories on the assembled
`--library-path`, so a host library reachable only there was invisible to the
switched runtime.
- `glfwd_host_dirs` never looked in `/run/opengl-driver/lib`, so the shim's
one-name lookup had no target on a host whose GL vendor library lives there.

sharun appends the same directories for the bundled runtime, so the repair is
the same three additions here. `/run/opengl-driver/lib` joins
`cld_va_libdirs` and is probed as `<dir>/dri`, the two directories are appended
to the library path after the `/etc/ld.so.conf` entries, and both join the
shim's fixed host list. Every entry is access-guarded, so a host without them
pays one failed probe each and nothing else.

E104, E105 and E106 are the cases, one per list, and the container suite runs
all three on both architectures and reports MATCH for each, with
`DRIVER=NIX env=[/run/opengl-driver/lib/dri]` as E106's line. Section 8 owns the
totals. They create `/run/opengl-driver/lib`, so where `/run` is not writable
each SKIPS by name instead of running.

The same three mechanisms were also measured before CI ran them, on a machine
with no root, with the prefix substituted for a writable one. There the
assembled library path gains both directories after the `/etc/ld.so.conf`
entries, the shim reports `target .../opengl-driver/lib/libtgt.so`, and the fake
libva answers `DRIVER=NIX` from a driver that exists only in the substituted
directory. The same runs against the unmodified source report the directories
absent, no target, and no driver, which is what makes each of the three an A/B
rather than a check that a string appeared.

---

---
Expand Down
2 changes: 1 addition & 1 deletion docs/report/10-measured-versus-assumed.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## 10. Measured versus assumed

**Measured:** every table and quoted output above, plus `sh scripts/run-evidence.sh`
(66/66 on x86-64, 62/62 on aarch64), `sh scripts/run-appimage.sh` (45/45 glvnd glibc, 40/40 musl with five
(69/69 on x86-64, 65/65 on aarch64), `sh scripts/run-appimage.sh` (45/45 glvnd glibc, 40/40 musl with five
named skips, 26/26 on each pre-glvnd glibc host, 7/7 on the gtk4 stage), `tools/gap.py --fetch`, the eight-distro inventory, the AppImage inventory,
the corpus test, the real mpv and `iHD` VA-API run in section 9.19, and the five-distro `ld.so.cache` survey in
`../ground-truth.md`.
Expand Down
54 changes: 54 additions & 0 deletions experiments/30-run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,35 @@ else
run E21 OK "runtime : host" \
env APPDIR="$PWD/app_old" ./runtime-select --probe --host-dir "$PWD/goodhost"

# E104: the NixOS directories are on the assembled library path. NixOS is
# not FHS and writes no /etc/ld.so.conf: hardware.graphics publishes
# the host's GPU userspace under /run/opengl-driver/lib and the system
# profile is /run/current-system/sw/lib. sharun appends both, and the
# switched runtime has to as well or a host library that lives only
# there is invisible.
if mkdir -p /run/opengl-driver/lib /run/current-system/sw/lib 2>/dev/null; then
run E104 OK "OK: both NixOS dirs on the library path" \
env APP="$PWD/app_old" HOSTD="$PWD/goodhost" sh -c '
lp=$(env APPDIR="$APP" ./runtime-select --probe \
--host-dir "$HOSTD" --no-self-test |
sed -n "s/^library-path : //p")
case ":$lp:" in
*:/run/opengl-driver/lib:*) a=yes ;;
*) a=no ;;
esac
case ":$lp:" in
*:/run/current-system/sw/lib:*) b=yes ;;
*) b=no ;;
esac
if [ "$a" = yes ] && [ "$b" = yes ]; then
echo "OK: both NixOS dirs on the library path"
else
echo "MISSING: $lp"
fi'
else
echo " E104 SKIPPED - cannot create /run/opengl-driver/lib: not root"
fi

# ---- the build-time strict-environment option -------------------------
#
# APPDIR is a convention this project does not own: an AppImage runtime
Expand Down Expand Up @@ -1057,6 +1086,18 @@ run E103 OK "target /opt/cross-libc-unguessable-42/libtgt.so" fwd_noenv ./tramp2
noconf
run E75b FAIL "no target; all 5 entry points return zero" fwd_noenv ./tramp2

# E105: NixOS publishes the host's GPU userspace under /run/opengl-driver/lib
# and writes no /etc/ld.so.conf naming it. The shim's fixed host list has
# to carry that directory, or a NixOS host has no target at all. The conf
# file is still gone, from E75b's control, so nothing else names it.
if mkdir -p /run/opengl-driver/lib 2>/dev/null &&
cp libtgt.so /run/opengl-driver/lib/libtgt.so 2>/dev/null; then
run E105 OK "target /run/opengl-driver/lib/libtgt.so" fwd_noenv ./tramp2
rm -f /run/opengl-driver/lib/libtgt.so
else
echo " E105 SKIPPED - cannot write /run/opengl-driver/lib: not root"
fi

# E75c: a shim with no target must not shadow the providers behind it. The
# preload wins the lookup, so with tgt-fwd.so preloaded the binary's
# t_ints binds to the shim whatever else the process carries, and
Expand Down Expand Up @@ -1418,6 +1459,19 @@ run E99 OK "bundle-dri-absent" sh -c \
run E100 OK "env=[(unset)]" \
env LD_PRELOAD=/work/cross-libc-dlopen.so ./va_nolib

# E106: NixOS publishes the host's VA drivers under /run/opengl-driver/lib/dri,
# which is neither FHS nor named by /etc/ld.so.conf, so only a list that
# carries it can answer. LD_LIBRARY_PATH is cleared, because a directory
# on the process's own search list is not what this case is about.
if mkdir -p /run/opengl-driver/lib/dri 2>/dev/null; then
gcc -shared -fPIC -O2 -DVA_VENDOR='"NIX"' va_drv.c \
-o /run/opengl-driver/lib/dri/vastub_drv_video.so 2>"$BERR" || bfail vastub-NIX
run E106 OK "DRIVER=NIX env=[/run/opengl-driver/lib/dri" \
env -u LD_LIBRARY_PATH LD_PRELOAD=/work/cross-libc-dlopen.so ./va_consumer
else
echo " E106 SKIPPED - cannot create /run/opengl-driver/lib/dri: not root"
fi

echo
echo "================================================================"
echo " predictions matched: $PASS mismatched: $FAIL"
Expand Down
4 changes: 2 additions & 2 deletions scripts/verify-gates.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ g_attrib() {
# section. Kept identical to the gates.yml step, including that.
g_onehome() {
f=0
for n in 3470 358 66/66 62/62 45/45 40/40 26/26; do
for n in 3470 358 69/69 65/65 45/45 40/40 26/26; do
c=$(git grep -lF "$n" -- '*.md' ':(exclude)docs/history/*' |
sed 's|^docs/report/.*|docs/report/|' | sort -u | wc -l)
[ "$c" -gt 1 ] && f=1
Expand Down Expand Up @@ -148,7 +148,7 @@ check "no tool is credited (tree)" g_attrib docs/_gate_probe.md \
check " the same, as a generated-with line" g_attrib docs/_gate_probe.md \
"Generated with [$TOOLNAME Code](https://example.invalid)"
check "every headline number has one home" g_onehome docs/_gate_probe.md \
'the suite reports 66/66 predictions held'
'the suite reports 69/69 predictions held'

# ⛔ THIS CHECK EXISTS BECAUSE THE RATCHET DID NOT REFUSE. It was written as a
# budget with a hardcoded number and a printed suggestion that the next reader
Expand Down
7 changes: 5 additions & 2 deletions src/cross-libc-dlopen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1490,9 +1490,12 @@ VISIBLE void cross_libc_dlopen_init_now(void) {

// The conventional libdirs of the hosts this runs on, each probed as
// <dir>/dri. Debian and Ubuntu keep their VA drivers under the triplet
// directory, Alpine in /usr/lib/dri, Fedora in /usr/lib64/dri. A missed
// access() costs nothing.
// directory, Alpine in /usr/lib/dri, Fedora in /usr/lib64/dri. NixOS is
// neither FHS nor ld.so.conf: hardware.graphics publishes the host's VA
// drivers under /run/opengl-driver/lib/dri, the directory sharun appends for
// the bundled runtime. A missed access() costs nothing.
static const char *const cld_va_libdirs[] = {
"/run/opengl-driver/lib",
"/usr/lib/" CLD_TRIPLET, "/lib/" CLD_TRIPLET,
"/usr/lib64", "/lib64",
"/usr/lib", "/lib",
Expand Down
7 changes: 7 additions & 0 deletions src/gl-fwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,15 @@ static const char *const glfwd_names[GLFWD_COUNT] = {
* PR #4's mesa-egl entries are kept in list 3 for the same reason: a host with
* the alternatives layout and no readable ld.so.conf is not hypothetical, and
* an access() that misses costs nothing.
*
* NixOS is a host class none of the three reaches by itself: it is not FHS and
* it writes no /etc/ld.so.conf naming its GPU userspace, which lives under
* /run/opengl-driver/lib (with the system profile at
* /run/current-system/sw/lib). sharun names the same two for the bundled
* runtime, and an access() that misses costs nothing.
*/
static const char *const glfwd_host_dirs[] = {
"/run/opengl-driver/lib", "/run/current-system/sw/lib",
"/usr/lib/" GLFWD_TRIPLET, "/lib/" GLFWD_TRIPLET,
"/usr/lib/" GLFWD_TRIPLET "/mesa", "/usr/lib/" GLFWD_TRIPLET "/mesa-egl",
"/usr/lib64", "/lib64", "/usr/lib64/mesa", "/usr/lib64/mesa-egl",
Expand Down
12 changes: 12 additions & 0 deletions src/runtime-select.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ static const char *rs_host_libdirs[] = {
NULL
};

/* NixOS is not FHS and writes no /etc/ld.so.conf: the host's GPU userspace is
* published under /run/opengl-driver/lib and its system profile under
* /run/current-system/sw/lib. sharun appends the same two after everything
* else, and this is that act for the switched runtime. */
static const char *rs_nixos_libdirs[] = {
"/run/opengl-driver/lib", "/run/current-system/sw/lib",
NULL
};

static int rs_debug;

static void rs_log(const char *fmt, ...) {
Expand Down Expand Up @@ -1029,6 +1038,9 @@ static char *rs_library_path(const struct rs_plan *p, const char *appdir,
/* The budget and its one-shot warning are per-walk state inside
* ldconf_each_dir now, so there is nothing to reset here. */
rs_conf_dirs("/etc/ld.so.conf", s, cap, &n);
for (size_t i = 0; rs_nixos_libdirs[i]; i++)
if (!rs_path_append(s, cap, &n, rs_nixos_libdirs[i]))
rs_log("library-path is full; %s omitted\n", rs_nixos_libdirs[i]);
return s;
}

Expand Down
Loading