ADR-070 — Descellement additif couche-0 : codec sockaddr public pour la face libc (socket_addr_from_bytes / socket_addr_to_bytes)
Statut : Accepté (2026-07-06, décision BDFL — exposition du codec sockaddr
existant plutôt que duplication côté libc ; sous la délégation des re-sceaux
additifs du superviseur, ADR-065, et
dans le cadre du descellement couche 0 pour la libc
ADR-051). RFC d’extension de couches
scellées (ADR-015). Sert l’implémentation du
jalon M4 réseau (ADR-069,
Lot 2). Conventions : ADR-021.
Catégorie : Descellement additif de la couche 0 scellée (couche-0-v1.9 →
couche-0-v1.10). Aucune rupture ; aucun symbole existant modifié ; jalons antérieurs
conservés. Tag couche-0-v1.10 DIFFÉRÉ (groupé avec le re-sceau couche-1-v1.6,
décision d’ordonnancement BDFL).
Contexte
La libc C-ABI d’Air doit convertir, aux frontières bind/connect/getsockname/
getpeername/accept, entre le struct sockaddr brut que présente un programme C
(octets + socklen_t) et le SocketAddr typé qu’utilisent le moteur socket
(ADR-069) et la couche 0.
Or la couche 0 possède déjà ce codec, dans les deux sens, mais en pub(crate) :
socket_addr_to_raw(&SocketAddr) -> (RawSockaddrStorage, u32)(sérialisation) ;raw_to_socket_addr(&[u8], u32) -> Option<SocketAddr>(désérialisation, validante : famille connue + longueur suffisante).
Deux options se présentaient (cf. décision BDFL) :
- Réimplémenter le layout
sockaddr_in/sockaddr_in6/sockaddr_undans la libc (air-libc-socket) — dupliquerait la connaissance du layout kernel, avec un risque de divergence à maintenir en phase. - Exposer le codec couche 0 existant — une seule autorité de layout (doctrine kernel = bible), zéro duplication.
Décision
Option 2. La couche 0 expose deux fines fonctions publiques, qui délèguent aux
codecs internes inchangés (aucune logique nouvelle, aucun unsafe) :
#![allow(unused)]
fn main() {
// crates/air-sys-syscall/src/net.rs
pub fn socket_addr_from_bytes(bytes: &[u8], length: u32) -> Option<SocketAddr>;
pub fn socket_addr_to_bytes(address: &SocketAddr, out: &mut [u8]) -> Option<u32>;
}
socket_addr_from_bytes= exposition deraw_to_socket_addr(le sens hostile : octets non fiables venus du C → adresse typée, validée ouNone).socket_addr_to_bytes= exposition desocket_addr_to_rawsans fuiter le type de stockage interne (RawSockaddrStoragerestepub(crate)) : copie bornée dans le buffer de l’appelant, rend lasocklen_teffective ouNonesi le buffer est trop court.
Les shims C bind/connect/getsockname/… (Lot 3) appellent ces fonctions
directement ; il n’y a pas de couche de re-hébergement du codec dans
air-libc-socket (qui ne porte que inet_pton/inet_ntop + byte-order, Lot 2.a).
Conséquences
- Positif : une seule implémentation du layout
sockaddr, testée et fuzzée (fuzz_air_sockaddr_decode— octets +socklen_tarbitraires, invariants no-panic + round-trip IP). Couverture 100 % des deux fonctions. - ABI : purement additif — les symboles
air-stableexistants sont intacts ; aucune garantie ABI n’est rompue. Re-sceaucouche-0-v1.10(tag différé). - Limitation connue (héritée, hors périmètre) :
raw_to_socket_addraccepte un nom Unix abstrait plus long quesun_path(107 octets) quesocket_addr_to_rawborne — asymétrie pré-existante du codec couche 0 (déjà employée pargetsockname/getpeername). Le fuzz restreint donc son invariant de round-trip aux familles IP (layout fixe). Durcissement éventuel = descellement additif ultérieur.
Alternatives rejetées
- Réimplémenter le codec dans
air-libc-socket: duplication du layout kernel, divergence possible (rejetée — cf. Contexte option 1). - Rendre
RawSockaddrStoragepublic : fuiterait un détail de représentation ([u8; 128]aligné) dans la surface stable, sans bénéfice — l’API par tranche (&mut [u8]) est plus sûre et suffit à la libc.