gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

⎇ main recipes/busybox.toml TOML · 122 líneas · 10.0 KB Historia crudo

fix(instalador): la cuenta de quien va a usar la maquina se pregunta antes de instalar 0f66c9973 · sergio ·

1# busybox 1.36.1 — coreutils + shell + init del userland mínimo del Stage 1 (SDD 11 §3).
2#
3# Es la "balsa desechable" (ADR 0008): se sustituye por el userland multi-call nativo en
4# Rust/Zig más adelante; mientras tanto da `sh`, las utilidades de manipulación de texto que el
5# pipeline asume, y su propio `init` (PID 1 provisional, vía /etc/inittab que ensambla Stage 1).
6#
7# Estático con `zig cc` cross al target: el binario es autocontenido, sin loader del host. El
8# `install` de busybox crea los symlinks de applets (sh, mount, init, …) bajo CONFIG_PREFIX, que
9# el ensamblado del rootfs hidrata tal cual.
10
11name    = "busybox"
12version = "1.36.1"
13license = "GPL-2.0-only"
14
15[source]
16tarball = "https://busybox.net/downloads/busybox-1.36.1.tar.bz2"
17sha256  = "b8cc24c9574d809e7279c3be349795c5d5ceb6fdf19ca709f80cde50e47de314"
18
19[build]
20compiler = "zig-cc"
21target   = "x86_64-linux-musl"
22link     = "static"
23
24[deps]
25build = ["make"]
26
27[build.phases]
28# busybox usa Kconfig, no autotools: arrancamos de `defconfig` y forzamos CONFIG_STATIC=y. `tc`
29# no compila contra musl (gcc-ismos de red), así que lo desactivamos — es el ajuste mínimo
30# conocido para un build estático limpio con musl.
31#
32# CC='zig cc -mcpu=baseline' HOSTCC='zig cc -mcpu=baseline' EN LÍNEA DE COMANDO: el Kbuild de busybox fija `CC = gcc` y
33# `HOSTCC = gcc` con `=` (hard), que ignora el env `CC` del sandbox; sólo un override de línea de
34# comando gana. Apunta target (CC) y herramientas host (HOSTCC, p.ej. fixdep/gcc-version.sh) a
35# `zig cc`, manteniendo la hermeticidad zig-only (ADR 0003) sin meter gcc al rootfs.
36# El link final asume GNU ld y pasa flags que `zig cc` valida y rechaza (`--warn-common`, `-Map`,
37# `--verbose`); los quitamos de scripts/trylink. Es la incompatibilidad GNU-ld↔zig/lld esperada.
38#
39# ── EL RECORTE (docs/plan-botar-busybox.md, paso 1) ──────────────────────────────────────────────
40# `RETIRADOS` apaga 139 de los 401 applets que `defconfig` instala. No es adelgazar por adelgazar:
41# cada uno o NO SE REEMPLAZA (dpkg, rpm, httpd, telnetd, ubi*, nand*, i2c*: 105) o su función ya la
42# hace otro componente del producto (init/runit -> arje-zero, syslogd/klogd/logread -> hammerd: 19).
43#
44# ── SEGUNDA TANDA, 15 más (2026-09-22): 277 -> 262 ───────────────────────────────────────────────
45# Los tres grupos salieron de MEDIR, no de adelgazar:
46#
47#   · **kmod (6)** — `insmod rmmod lsmod modprobe depmod modinfo`, más `MODPROBE_SMALL`, que es la
48#     implementación compartida y sin applets que la usen queda como código muerto. El plan los
49#     tenía como «escribir en Rust», la pieza más grande que quedaba. **No hay nada que escribir:
50#     los cuatro kernels de takana traen `# CONFIG_MODULES is not set`, CERO drivers `=m` y ninguna
51#     receta hace `modules_install`.** Sin CONFIG_MODULES el kernel ni implementa `init_module`: un
52#     insmod recibiría ENOSYS. Si algún día un kernel de takana habilita módulos, esto se revisa
53#     ENTERO y antes de arrancarlo.
54#   · **gestor de /dev (3)** — `mdev makedevs uevent`. `CONFIG_DEVTMPFS_MOUNT=y` hace que el kernel
55#     cree y monte `/dev` con sus nodos, no hay `CONFIG_UEVENT_HELPER` (o sea que el kernel no llama
56#     a ningún helper de hotplug) y `libudev-zero` ya viaja en los 8 perfiles.
57#   · **alias internos de iproute2 (6)** — `ipaddr iplink ipneigh iproute iprule iptunnel`. No son
58#     comandos de nadie: son `ip addr`, `ip link`… escritos como applet. `ip` (el de verdad, de
59#     iproute2) sigue en los 7 perfiles y no se toca.
60#
61# ⚠ Los 5 de kmod tenían `?` en la columna `simbolo_kconfig` del TSV y hubo que ir al fuente: sus
62# líneas `//applet:` llevan `IF_NOT_MODPROBE_SMALL(...)` anidado y el extractor no lo entendía. El
63# TSV avisó con `?` en vez de inventar, que es lo correcto — pero mientras estuvo así **el vigía no
64# podía vigilarlos**: sin símbolo no hay cruce. Rellenados antes de retirarlos, no después.
65#
66# ⚠ Y 5 se INDULTARON a propósito, porque arje-zero y hammerd reemplazan la FUNCIÓN pero no instalan
67# un COMANDO con ese nombre — son un binario cada uno:
68#   setuidgid    la card de gitea hace `setuidgid gitea` (recipes/gitea.toml:89)
69#   switch_root  el /init del instalador lo ejecuta (scripts/takana-live-install.sh:375)
70#   poweroff/halt/reboot   nada más en el corpus apaga la máquina: arje-zero es PID 1, no una CLI
71#
72# El mapa applet->símbolo sale de las líneas `//applet:` del fuente, NO de poner el nombre en
73# mayúsculas: eso falla en 6 casos medidos (`[`->TEST1, `[[`->TEST2, arch->BB_ARCH, sh->SH_IS_ASH…).
74# Está en la columna `simbolo_kconfig` de docs/state/busybox-applets.tsv.
75#
76# ⚠ Tocar esta lista RE-HASHEA busybox, y con él las 24 recetas que lo declaran build-dep.
77# `scripts/busybox-vigia.py` falla si alguien invoca un applet retirado — sin él esto se deshace
78# solo, porque quitar un applet no rompe nada hasta que arranca una máquina, semanas después.
79#
80# `yes '' | make oldconfig` tras editar .config: sin esto, el compile corre `silentoldconfig`, que
81# al ver opciones NEW (p.ej. WERROR) **prompea interactivamente** leyendo stdin — build
82# no-determinista y flaky (lo destapó la verificación de reproducibilidad de Stage 2). `yes ''`
83# acepta el default de cada NEW ⇒ config resuelta y determinista (busybox 1.36.1 no tiene el target
84# `olddefconfig`, así que usamos `oldconfig` alimentado por `yes`).
85configure = "make CC='zig cc -mcpu=baseline' HOSTCC='zig cc -mcpu=baseline' defconfig && sed -i -e 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/' -e 's/^CONFIG_TC=y/# CONFIG_TC is not set/' -e 's/^CONFIG_FEATURE_TC_INGRESS=y/# CONFIG_FEATURE_TC_INGRESS is not set/' .config && RETIRADOS='ACPID ADJTIMEX ASCII BEEP BOOTCHARTD CHAT CHPST CONSPY CRC32 DEPMOD DEVMEM DHCPRELAY DNSD DNSDOMAINNAME DOS2UNIX DPKG DPKG_DEB ED ENVDIR ENVUIDGID ETHER_WAKE FAKEIDENTD FATATTR FBSET FBSPLASH FDFLUSH FDFORMAT FREERAMDISK FSYNC FTPD FTPGET FTPPUT HDPARM HEXEDIT HTTPD I2CDETECT I2CDUMP I2CGET I2CSET I2CTRANSFER IFPLUGD INETD INIT INSMOD IOSTAT IPADDR IPCALC IPLINK IPNEIGH IPROUTE IPRULE IPTUNNEL KLOGD LINUXRC LOGGER LOGREAD LPD LPQ LPR LSMOD LSSCSI LZOP MAKEDEVS MAKEMIME MDEV MICROCOM MIM MODINFO MODPROBE MODPROBE_SMALL MPSTAT MT NANDDUMP NANDWRITE NBDCLIENT NMETER PIPE_PROGRESS POPMAILDIR POWERTOP PSCAN RAIDAUTORUN RDEV READAHEAD REFORMIME RESIZE RESUME RMMOD RPM RPM2CPIO RUNLEVEL RUNSV RUNSVDIR RUN_INIT RX SEEDRNG SENDMAIL SETCONSOLE SETFATTR SETLOGCONS SETSERIAL SHA3SUM SMEMCAP SOFTLIMIT SSL_CLIENT START_STOP_DAEMON SV SVC SVLOGD SVOK SYSLOGD TCPSVD TELNET TELNETD TEST2 TFTP TFTPD TIME TREE TS TTYSIZE UBIATTACH UBIDETACH UBIMKVOL UBIRENAME UBIRMVOL UBIRSVOL UBIUPDATEVOL UDHCPD UDPSVD UEVENT UNIX2DOS UNZIP USLEEP UUDECODE UUENCODE VOLNAME WATCHDOG WHICH WHOIS ZCIP' && for s in $RETIRADOS; do sed -i \"s/^CONFIG_$s=y$/# CONFIG_$s is not set/\" .config; done && yes '' | make CC='zig cc -mcpu=baseline' HOSTCC='zig cc -mcpu=baseline' oldconfig && sed -i -e 's/-Wl,--warn-common//g' -e 's/-Wl,-Map,[^ ]*//g' -e 's/-Wl,--verbose//g' scripts/trylink"
86compile   = "make -j\"$(nproc)\" CC='zig cc -mcpu=baseline' HOSTCC='zig cc -mcpu=baseline'"
87# busybox instala en CONFIG_PREFIX (no DESTDIR): bin/busybox + symlinks de cada applet.
88install   = "make CC='zig cc -mcpu=baseline' HOSTCC='zig cc -mcpu=baseline' CONFIG_PREFIX=/out install"
89
90# ── EL BIT DE PRIVILEGIO (SDD 28 §5.11, `[[setuid]]`) ─────────────────────────────────────────────
91# Medido en metal el 2026-10-15, en la máquina del operador: `su` contesta
92#
93#     su: must be suid to work properly
94#
95# y era **la única escalada que le quedaba** (root tenía la cuenta cerrada y `sudo`/`doas` no
96# estaban proyectados). El encabezado de `crates/takana-core/src/setuid.rs` lo había previsto
97# textualmente —«hoy es LATENTE: el instalador sólo pone contraseña de root, así que no hay un
98# humano no-root que lo choque»— y ése fue el día que lo hubo.
99#
100# **ONCE applets instalados dependen de este bit** (contados en el rootfs instalado, todos symlink a
101# `bin/busybox`): `su` `login` `passwd` `mount` `umount` `ping` `ping6` `traceroute` `traceroute6`
102# `crontab` `vlock`. Sin él fallan los once, y ninguno nombra el privilegio al fallar: `ping 8.8.8.8`
103# sale 1 al instante y se lee como «no hay red».
104#
105# **Por qué el bit es seguro en ESTE build, y no es una opinión:** el binario trae
106# `CONFIG_FEATURE_SUID` (medido con `strings -a`: la cadena «must be suid to work properly» sólo
107# existe si está compilada, y es la que el operador vio). Con esa opción busybox **suelta el
108# privilegio en `check_suid()`** para todo applet que no lo declara `BB_SUID_REQUIRE` ⇒ `ls`, `sh` y
109# `cat` corren con el uid real aunque el multi-call sea setuid. También trae
110# `CONFIG_FEATURE_SUID_CONFIG` (la cadena `busybox.conf` está en el binario), así que un
111# `/etc/busybox.conf` 0600 root:root puede acotar la lista applet por applet el día que se quiera —
112# si el fichero no existe, manda la tabla compilada, que es este comportamiento.
113#
114# ⚠ Lo que NO se hace acá, y el motivo: Alpine pone el bit en un binario APARTE (`busybox.suid`) y
115# reapunta sólo los symlinks privilegiados, para que el multi-call que corre todo el sistema no sea
116# setuid. Es mejor, y acá cuesta tocar el `install` de esta receta ⇒ **re-hashea busybox y con él las
117# 24 recetas que lo declaran build-dep**. Esta declaración es metadato (fuera de `hash_inputs`) y no
118# mueve un solo `ArtifactHash`, así que entra hoy; el split queda anotado como lo que sigue.
119[[setuid]]
120path = "bin/busybox"
121mode = "4755"
122why  = "once applets instalados lo necesitan (su, login, passwd, mount, umount, ping, ping6, traceroute, traceroute6, crontab, vlock) y sin el bit fallan los once sin nombrar el privilegio — `su` dice «must be suid to work properly» y `ping` sale 1 al instante, que se lee como «no hay red». El build trae CONFIG_FEATURE_SUID, así que busybox suelta el privilegio para todo applet que no lo pide."