fix(arje): build-initrd compila musl-static por default
Sin musl, PID 1 panic con "error while loading shared libraries: libgcc_s.so.1" porque el initramfs no incluye libgcc/glibc/ld-linux. Solución estándar: target x86_64-unknown-linux-musl produce un ELF totalmente estático. Cambios en scripts/build-arje-initrd.sh: - ARJE_TARGET=x86_64-unknown-linux-musl por default (override con env). - Chequeo del target instalado antes de buildear; mensaje accionable con los comandos exactos (rustup target add..., apt install musl-tools, etc.) si falta. - Sanity check con `file`: aborta si ente-zero quedó dinámico. - Sanity check para busybox: aborta si el BUSYBOX_BIN apunta a un binario dinámico (la otra causa #1 de panic). - BIN_DIR ahora apunta a target/$TARGET/release/. Docs (docs/arje-boot.md): - §2a explica el porqué de musl. - §2b lista requisitos del host (rustup target, musl-tools, busybox-static). - §7 sección nueva de troubleshooting con el síntoma exacto del libgcc_s panic + 3 escenarios comunes más. - Checklist pre-deploy actualizado con el chequeo de "statically linked". Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+126
-16
@@ -22,12 +22,12 @@ El initrd es un **CPIO + gzip** (formato `newc`, estándar Linux). Su raíz:
|
||||
|
||||
```
|
||||
/init wrapper sh, ejecuta /sbin/ente-zero
|
||||
/sbin/ente-zero PID 1
|
||||
/sbin/ente-zero PID 1 (musl-static por default)
|
||||
/usr/sbin/ente-echo
|
||||
/usr/sbin/ente-policy-provider
|
||||
/usr/sbin/ente-*-compat 13 shims D-Bus (logind, hostnamed, …)
|
||||
/ente/seed.card.json Tarjeta Semilla canónica
|
||||
/bin/{sh,ls,mount,…} busybox-static (o glibc dinámica + libs)
|
||||
/bin/{sh,ls,mount,…} busybox-static
|
||||
/etc, /dev, /proc, /sys, /run mountpoints vacíos
|
||||
/sys/fs/cgroup mountpoint cgroup v2
|
||||
```
|
||||
@@ -38,31 +38,69 @@ Path canónico de la semilla en **prod**: `/ente/seed.card.json` (ver
|
||||
|
||||
## 2. Build del initrd
|
||||
|
||||
Requisitos host: `cargo`, `cpio`, `gzip`, y opcionalmente `busybox-static`
|
||||
(en Debian/Ubuntu: `apt install busybox-static`).
|
||||
### 2a. Por qué musl-static
|
||||
|
||||
`ente-zero` corre como **PID 1**: si tiene cualquier dependencia dinámica
|
||||
(`libgcc_s.so.1`, `libc.so.6`, `ld-linux-x86-64.so.2`) que no está
|
||||
presente en el initramfs, el kernel paniquea con
|
||||
`error while loading shared libraries: libgcc_s.so.1`.
|
||||
|
||||
Solución estándar: compilar contra el target `x86_64-unknown-linux-musl`,
|
||||
que produce un ELF **totalmente estático** (no necesita libc ni
|
||||
intérprete en runtime). Es el default del script.
|
||||
|
||||
### 2b. Requisitos del host
|
||||
|
||||
- `rust toolchain` con el target musl:
|
||||
```bash
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
```
|
||||
- `musl-gcc` para crates con `build.rs` C (sled, blake3, etc.):
|
||||
```bash
|
||||
apt install musl-tools # Debian/Ubuntu
|
||||
apk add musl-dev gcc # Alpine
|
||||
pacman -S musl # Arch
|
||||
```
|
||||
- `cpio`, `gzip` para empaquetar.
|
||||
- `busybox-static` para el userspace mínimo dentro del initramfs:
|
||||
```bash
|
||||
apt install busybox-static # Debian/Ubuntu
|
||||
# Alpine ya trae busybox built-in
|
||||
```
|
||||
|
||||
### 2c. Invocación
|
||||
|
||||
```bash
|
||||
# Default: semilla de prod, sale en out/arje.initrd.cpio.gz
|
||||
# Default: musl-static, semilla de prod, sale en out/arje.initrd.cpio.gz
|
||||
scripts/build-arje-initrd.sh
|
||||
|
||||
# Customizar:
|
||||
# Customizar seed/salida:
|
||||
scripts/build-arje-initrd.sh seeds/arje-minimal.card.json out/min.cpio.gz
|
||||
|
||||
# Sin busybox del sistema, apuntar a uno propio:
|
||||
# busybox-static no está en $PATH:
|
||||
BUSYBOX_BIN=/path/to/busybox scripts/build-arje-initrd.sh
|
||||
|
||||
# Vendorear binarios extra (separados por espacio):
|
||||
EXTRA_BINS="/usr/bin/strace /usr/bin/gdb" scripts/build-arje-initrd.sh
|
||||
# Vendorear binarios extra estáticos:
|
||||
EXTRA_BINS="/usr/local/bin/strace-static" scripts/build-arje-initrd.sh
|
||||
|
||||
# (NO RECOMENDADO) build glibc dinámico — kernel panic asegurado salvo que
|
||||
# vendorees libgcc_s + libc + ld-linux a mano:
|
||||
ARJE_TARGET=x86_64-unknown-linux-gnu scripts/build-arje-initrd.sh
|
||||
```
|
||||
|
||||
El script:
|
||||
### 2d. Qué hace el script
|
||||
|
||||
1. Corre `cargo build --release` para `ente-zero` + los 14 shims compat.
|
||||
2. Valida la seed con `seeds/validate.sh` (parse + `Card::validate`).
|
||||
3. Stage en un tmpdir → copia binarios + crea mountpoints + escribe `/init`.
|
||||
4. Empaqueta `find . | cpio -o -H newc | gzip -9`.
|
||||
1. Verifica que el target musl esté instalado; si no, da el comando
|
||||
exacto para instalarlo.
|
||||
2. `cargo build --release --target x86_64-unknown-linux-musl` para
|
||||
`ente-zero` + los 14 shims compat.
|
||||
3. Sanity-check con `file`: aborta si algún binario quedó dinámico.
|
||||
4. Valida la seed con `seeds/validate.sh` (parse + `Card::validate`).
|
||||
5. Verifica que `busybox` sea estático (también aborta si es dinámico).
|
||||
6. Stage en un tmpdir → copia binarios + crea mountpoints + escribe `/init`.
|
||||
7. Empaqueta `find . | cpio -o -H newc | gzip -9`.
|
||||
|
||||
Tamaño típico: ~15-25 MB descomprimido, 5-8 MB el `.cpio.gz`.
|
||||
Tamaño típico (musl): ~10-15 MB descomprimido, 4-6 MB el `.cpio.gz`.
|
||||
|
||||
## 3. Boot en QEMU
|
||||
|
||||
@@ -302,11 +340,83 @@ mkdir /tmp/arje-test && cp seeds/arje-minimal.card.json /tmp/arje-test/seed.card
|
||||
cd /tmp/arje-test && target/release/ente-zero
|
||||
```
|
||||
|
||||
## 7. Troubleshooting
|
||||
|
||||
### 7a. `error while loading shared libraries: libgcc_s.so.1` al boot
|
||||
|
||||
**Causa**: el `/sbin/ente-zero` del initrd se compiló contra glibc
|
||||
(`x86_64-unknown-linux-gnu`) y depende dinámicamente de `libgcc_s.so.1`,
|
||||
`libc.so.6`, `ld-linux-x86-64.so.2`. Esas libs no están en el initramfs,
|
||||
el kernel mata PID 1 → panic.
|
||||
|
||||
**Fix**: usar el target musl (default del script desde mayo 2026):
|
||||
|
||||
```bash
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
apt install musl-tools # Debian/Ubuntu — para crates con build.rs C
|
||||
scripts/build-arje-initrd.sh # ya usa musl por default
|
||||
```
|
||||
|
||||
Verificar manualmente que el binario quedó estático:
|
||||
|
||||
```bash
|
||||
file target/x86_64-unknown-linux-musl/release/ente-zero
|
||||
# → "ELF 64-bit LSB executable, ..., statically linked, ..."
|
||||
```
|
||||
|
||||
Si decidís quedarte en glibc dinámico, hay que vendorear `libgcc_s.so.1`,
|
||||
`libc.so.6` y `ld-linux-x86-64.so.2` (más cualquier dep de `tracing` y
|
||||
`tokio`) bajo `/lib64/` y `/lib/x86_64-linux-gnu/` del initrd. No
|
||||
recomendado.
|
||||
|
||||
### 7b. Kernel panic: `Kernel panic - not syncing: Attempted to kill init!`
|
||||
|
||||
**Causa**: `ente-zero` salió con error antes de bind del bus, o `/init`
|
||||
crashed antes de exec. PID 1 muriendo = panic kernel.
|
||||
|
||||
**Fix**: agregar `panic=10` al cmdline (ya está en el script) para
|
||||
auto-reboot tras 10 s y ver el error. Bajo QEMU, `-no-reboot` lo
|
||||
convierte en exit limpio. Capturar el log:
|
||||
|
||||
```bash
|
||||
HEADLESS=1 scripts/run-arje-qemu.sh 2>&1 | tee /tmp/arje-boot.log
|
||||
```
|
||||
|
||||
Buscar la línea anterior a `Attempted to kill init`.
|
||||
|
||||
### 7c. `seed inválida` al correr build-arje-initrd.sh
|
||||
|
||||
**Causa**: el JSON tiene un ULID con caracteres prohibidos (`I L O U`
|
||||
están **excluidos** de Crockford base32), un `Payload::Native.exec`
|
||||
vacío, o un campo del schema rechazado por `brahman_card::Card::validate`.
|
||||
|
||||
**Fix**: correr el validador directo para ver el error completo:
|
||||
|
||||
```bash
|
||||
seeds/validate.sh seeds/mi-seed.card.json
|
||||
# Si falla, las primeras 40 líneas del log van a stderr.
|
||||
```
|
||||
|
||||
### 7d. `cannot find -lcrypt` o `cannot find -lpam` al compilar musl
|
||||
|
||||
**Causa**: algún crate del workspace pulled in una dep C que no
|
||||
encontró su lib bajo musl.
|
||||
|
||||
**Fix**: para los crates de arje no debería pasar (revisamos las deps).
|
||||
Si ocurre con un crate nuevo, suele resolverse con `RUSTFLAGS="-C
|
||||
target-feature=+crt-static"` o aislando el feature problemático.
|
||||
|
||||
---
|
||||
|
||||
## Apéndice — checklist pre-deploy
|
||||
|
||||
- [ ] `cargo build --release -p ente-zero` sin warnings.
|
||||
- [ ] `rustup target add x86_64-unknown-linux-musl` instalado en el host build.
|
||||
- [ ] `musl-tools` (Debian/Ubuntu) o equivalente disponible.
|
||||
- [ ] `busybox-static` disponible para vendorear userspace.
|
||||
- [ ] `cargo build --release --target x86_64-unknown-linux-musl -p ente-zero`
|
||||
compila sin warnings.
|
||||
- [ ] `file target/x86_64-unknown-linux-musl/release/ente-zero` reporta
|
||||
"statically linked".
|
||||
- [ ] `seeds/validate.sh seeds/arje-prod.card.json` → OK.
|
||||
- [ ] `scripts/build-arje-initrd.sh` produce `out/arje.initrd.cpio.gz`.
|
||||
- [ ] `scripts/run-arje-qemu.sh` arranca y muestra `Tarjeta Semilla cargada
|
||||
|
||||
Reference in New Issue
Block a user