ADR-068 — Surface fine credentials (uid/gid) en couche 1 (air-process), bindée par la libc
Statut : Accepté (2026-07-05, ratification BDFL — y compris la sémantique POSIX setuid/setgid du § dédié).
(ADR-015). Sous la délégation
d’ADR-065 (additifs révélés par les toits).
Catégorie : Descellement additif de la couche 1 scellée (couche-1-v1.3 →
couche-1-v1.4). Aucune rupture de signature existante.
Contexte
La séparation de privilèges d’OpenSSH exige la famille unistd/grp des
identifiants : getuid/geteuid/getgid/getegid (contrôles), setuid/setgid/
setresuid/setresgid (largage de privilèges), getgroups/setgroups,
initgroups. sshd démarre root, résout l’utilisateur (getpwnam, fait) puis
largue dans un ordre strict.
Ce que la couche 0 a DÉJÀ (aucun additif couche 0)
air-sys-syscall::process expose, en variantes modernes typées (ADR-021) :
get_resuid/set_resuid (triplet ResUid), get_resgid/set_resgid (ResGid),
get_groups/set_groups. Rien à ajouter en couche 0.
Le manque : une surface FINE en couche 1
air-process (couche 1) n’expose que drop_privileges (la séquence orchestrée
setgroups→setresgid→setresuid + vérification + seccomp/Landlock). Les briques
à-la-carte (lire l’identité courante, poser un seul triplet uid/gid, poser les
groupes) — les 1:1 dont la libc a besoin — ne sont pas exposées. C’est un manque
couche 1, pas couche 0.
Décision
Module air-process::credentials (couche 1)
Surface mince et typée sur la couche 0 (zéro réimplémentation) :
pub struct AirProcessCredentials { pub uid: ResUid, pub gid: ResGid }
impl AirProcessCredentials { pub fn current() -> AirResult<Self>; } // get_resuid + get_resgid
pub fn set_uids(new: ResUid) -> AirResult<()>; // = set_resuid
pub fn set_gids(new: ResGid) -> AirResult<()>; // = set_resgid
pub fn supplementary_groups(buf: &mut [Gid]) -> AirResult<&[Gid]>; // = get_groups
pub fn set_supplementary_groups(groups: &[Gid]) -> AirResult<()>; // = set_groups
drop_privileges reste la voie recommandée pour le largage réel (elle vérifie +
pose seccomp/Landlock) ; ces briques à-la-carte sont plus bas niveau, pour la
conformité libc.
Binders libc (couche 2)
- Getters (infaillibles) :
getuid→current().uid.real,geteuid→.effective,getgid/getegid(idemgid). setres*/groupes (explicites, non ambigus) :setresuid(r,e,s)→set_uids,setresgid→set_gids,getgroups/setgroups→les fns de groupes.initgroups(user, gid)=air_account::groups_of_user(user)+gid→set_supplementary_groups.
Sémantique POSIX setuid/setgid — REMONTÉE AU BDFL
setuid(uid) a une sémantique conditionnelle au privilège (source de bugs
sécurité historiques) :
- Privilégié (
euid == 0) : pose real + effective + saved =uid(largage irréversible — ce que veutsshd). - Non privilégié : pose uniquement l’effectif, et seulement si
uid ∈ {real, saved}; sinonEPERM.
Proposition : implémenter exactement cette sémantique au-dessus de set_uids
(idem setgid/setresgid). Comme c’est le point sécurité-sensible de cet ADR,
il est remonté : à ratifier avant implémentation de setuid/setgid (les
getters + setres* + groupes, eux, sont non ambigus et peuvent précéder).
Gouvernance
- Module
air-process::credentials= additif → re-sceaucouche-1-v1.4(signé) au merge.drop_privilegesinchangé. - Sous la délégation ADR-065 ; volet sécurité (
setuid/setgidprivilégié) remonté explicitement au BDFL.
Conséquences
air-processgagnecredentials(getters + set à-la-carte).- Binders libc :
getuid/geteuid/getgid/getegid/setresuid/setresgid/getgroups/setgroups(+setuid/setgidaprès ratification) +initgroups. - Tag
couche-1-v1.4; registredocs/libc-conformance.mdmis à jour.
Alternatives rejetées
- Faire la libc appeler
drop_privileges. Rejeté :drop_privilegesest une opération composée (tout ou rien, + seccomp/Landlock) ; la libc a besoin des primitives 1:1 POSIX, pas de l’orchestration. - Réimplémenter les syscalls uid/gid en couche 1/2. Sans objet : la couche 0 les
a déjà (
set_resuid/…), la couche 1 ne fait que les surfacer finement. - Additif couche 0. Sans objet (déjà présent).
Suite
- Après ratification :
air-process::credentials, binders libc,initgroups,air-process::drop_to_user(résout viaair-account+drop_privileges). Tagcouche-1-v1.4. Note de re-sceau dansINDEX.md+etat-avancement.md.