Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ADR-126 — Descellement additif couche-0-v1.14 : complétion de l’énumération Capability (41 capabilities noyau)

Statut : Accepté (2026-07-28, autorisation BDFL explicite). RFC de structure (ADR-015). Applique le modèle de re-sceau additif de la couche 0 (ADR-051, ADR-085).

Catégorie : Descellement additif de la couche 0 scellée (couche-0-v1.13couche-0-v1.14). Aucun retrait, aucune signature modifiée ; seule la surface grandit (nouvelles variantes d’un enum #[non_exhaustive]).

Contexte

L’implémentation du privsep pré-auth d’air-sshd (ADR-124 V2.2, ADR-125) a révélé une limite : air_sys_types::Capability ne nommait que 20 des 41 capabilities du noyau. air_process::reduce_capabilities_to (qui largue du bounding set toute capability nommée absente de la cible) ne pouvait donc réduire le bounding set du monitor qu’à 20/41CAP_SETPCAP, CAP_SETFCAP, CAP_MKNOD, CAP_BPF, CAP_AUDIT_*, CAP_MAC_*, … y subsistaient, faute de pouvoir les désigner.

Ce n’était pas un trou de privilège immédiat (les ensembles permitted/effective sont réduits exactement à la cible par masque de bits, et permitted ne peut jamais regrandir ; les résidus du bounding set ne comptent que pour un execve d’un binaire à file-capabilities, or ni le monitor ni l’enfant n’exec). Mais l’objectif littéral d’ADR-122 §6 (« bounding set = la cible ») n’était pas atteint, et le combler exige un additif couche 0 — hors du mandat d’un descellement couche 1 (ADR-125 l’a donc remonté au BDFL, qui a tranché : compléter).

Décision

Descellement additif couche-0-v1.14. Sur air-sys-types :

  • AJOUT des 21 variantes manquantes de Capability, aux valeurs ABI noyau (include/uapi/linux/capability.h, identiques x86_64/aarch64) : Setpcap=8, LinuxImmutable=9, NetBroadcast=11, IpcLock=14, IpcOwner=15, SysPacct=20, SysTtyConfig=26, Mknod=27, Lease=28, AuditWrite=29, AuditControl=30, Setfcap=31, MacOverride=32, MacAdmin=33, Syslog=34, WakeAlarm=35, BlockSuspend=36, AuditRead=37, Perfmon=38, Bpf=39, CheckpointRestore=40. L’énumération couvre désormais CAP_CHOWN (0) … CAP_CHECKPOINT_RESTORE (40 = CAP_LAST_CAP)41/41.

Mot haut du masque. Les valeurs 32-40 occupent désormais le mot haut (bits 32-63) du CapabilityMask (u64), donc le second mot u32 de l’ABI capget/capset. La conversion lo/hi était déjà faite par les helpers d’air-sys-syscall (mask_to_words/words_to_mask, bidirectionnels) ; un test dédié exerce maintenant le mot haut avec de vraies Capability (32 et 40), pas seulement un bit brut.

Consommateur (interne, pas d’API couche 1). air_process::NAMEABLE_CAPABILITIES (const privé) passe de 20 à 41 entrées ⇒ reduce_capabilities_to réduit le bounding set exactement à la cible. Le monitor d’air-sshd est donc borné à 4/41 ({SETUID, SETGID, CHOWN, KILL}) — la limitation 20/41 d’ADR-125 est levée. La signature publique de reduce_capabilities_to est inchangée ⇒ aucun re-sceau couche 1.

Conséquences

  • Tag git couche-0-v1.14 posé par le superviseur sur le commit de merge, après CI verte (barrière x86 + couverture 100 % + aarch64). Signé.
  • Objectif d’ADR-122 §6 pleinement atteint ; note de limitation d’ADR-125 caduque (référencée « levée » dans le code d’air-process).
  • Couverture couche 0 100 % : Capability n’a aucun match exhaustif (as_raw = self as u32, pas de from_raw), donc les nouvelles variantes n’ajoutent aucune ligne non couverte ; les valeurs sont assertées une à une, et le mot haut est testé.
  • Cibles noyau : Air vise Linux ≥ 6.12 (CAP_LAST_CAP = 40) ; capbset_drop d’une cap ≤ 40 réussit. Sur un noyau plus ancien (CAP_LAST_CAP < 40), larguer une cap au-delà échouerait EINVAL — hors cible supportée (ADR-004).

Alternatives rejetées

  • Garder 20/41. Rejeté par le BDFL : l’objectif d’ADR-122 §6 reste inatteignable et la dette resurgirait à chaque nouvel étage privsep.
  • Ne nommer que les caps du mot haut strictement nécessaires. Rejeté : incomplet et arbitraire ; l’énumération d’une ABI kernel stable et bornée (41 valeurs fixes) se complète une fois, proprement.
  • Réintroduire la complétion via un from_raw exhaustif. Non nécessaire : aucun appelant n’en a besoin, et cela créerait un match à 41 bras (surface + risque) sans bénéfice.

Suite

  • Tag couche-0-v1.14 après merge. Note de re-sceau dans etat-avancement.md et INDEX.md. Débloque la suite du privsep (V2.3 SIGN).