pub struct LandlockRuleset(/* private fields */);Expand description
Ruleset Landlock (cf. landlock_create_ruleset(2)).
Encapsule un FD ruleset Landlock qui accumule des règles d’accès
filesystem avant d’être appliqué au thread courant via
LandlockRuleset::restrict_self.
Les restrictions sont irréversibles pour le fil qui les pose : une fois
restrict_self appelé, ce fil ne peut plus voir ses permissions augmenter.
§Ce que la monotonie ne couvre PAS : TSYNC
Cette page affirmait « Landlock est monotone », sans réserve. C’est faux en présence
de LandlockRestrictFlags::TSYNC, et la correction est datée du 2026-08-13 après
mesure sur un noyau réel : un fil qui pose un domaine avec TSYNC écrase celui
de ses fils frères, y compris quand le leur était plus strict. Le noyau le dit —
« irrespective of previously established Landlock domains » — et l’expérience le
confirme : un fil frère qui ne pouvait rien ouvrir a retrouvé l’accès.
Ce n’est pas une élévation de privilège au sens usuel : les fils d’un processus
partagent leur espace d’adressage et n’ont jamais été une frontière de sécurité entre
eux. Mais l’intuition « une restriction Landlock ne se retire pas » est fausse à
l’échelle du processus, et la croire conduirait à poser TSYNC d’office.
Implementations§
Source§impl LandlockRuleset
impl LandlockRuleset
Sourcepub fn as_fd(&self) -> BorrowedFd<'_>
pub fn as_fd(&self) -> BorrowedFd<'_>
Vue empruntée du FD ruleset.
Sourcepub fn add_rule_path_beneath(
&mut self,
path: BorrowedFd<'_>,
allowed_access: LandlockAccessFs,
) -> Result<(), Errno>
pub fn add_rule_path_beneath( &mut self, path: BorrowedFd<'_>, allowed_access: LandlockAccessFs, ) -> Result<(), Errno>
Ajoute une règle d’accès pour un chemin filesystem et ses descendants.
Wrappeur de landlock_add_rule(2) avec LANDLOCK_RULE_PATH_BENEATH.
La règle s’applique au chemin référencé par path et à tous ses
descendants. path doit être ouvert avec O_PATH | O_DIRECTORY
(ou O_PATH seul pour un fichier).
Sémantique additive : les règles ne peuvent qu’étendre les accès
autorisés au sein de ce ruleset. restrict_self appliquera
l’intersection de tous les rulesets cumulés.
§Parameters
path: FD du chemin cible (typiquement ouvert avecO_PATH).allowed_access: permissions autorisées sur ce chemin et ses descendants.
§Errors
EINVAL:allowed_accesscontient un bit non géré par ce ruleset, oupathn’est pas un FD valide.ENOMEM: mémoire kernel insuffisante.EBADFD:pathn’est pas un FD de fichier ou répertoire.EINTR: interruption par signal (ADR-021 convention 2 — remonté tel quel, sans retry automatique).
§Examples
use air_sys_syscall::security::landlock_create_ruleset;
use air_sys_types::security::LandlockAccessFs;
use air_sys_types::fd::BorrowedFd;
let mut ruleset = landlock_create_ruleset(
LandlockAccessFs::READ_FILE | LandlockAccessFs::EXECUTE,
).expect("create_ruleset");
ruleset.add_rule_path_beneath(path_fd, LandlockAccessFs::READ_FILE)
.expect("add_rule");Sourcepub fn add_rule_net_port(
&mut self,
port: u16,
allowed_access: LandlockAccessNet,
) -> Result<(), Errno>
pub fn add_rule_net_port( &mut self, port: u16, allowed_access: LandlockAccessNet, ) -> Result<(), Errno>
Autorise un port TCP — landlock_add_rule(2) avec
LANDLOCK_RULE_NET_PORT (ABI v4+, Linux 6.7).
§Parameters
port: le port en ordre hôte (443, pas son écriture réseau) ;allowed_access:LandlockAccessNet::BIND_TCPet/ouLandlockAccessNet::CONNECT_TCP.
§Ce que cette règle borne, et ce qu’elle ne borne pas
Elle borne le port, jamais l’adresse. Un processus autorisé à se connecter au port 443 peut joindre n’importe quelle machine sur ce port. Landlock n’est pas un pare-feu, et le prendre pour tel donnerait un faux sentiment de confinement réseau.
§Errors
EINVAL: le ruleset ne gère pas les accès réseau (il faut l’avoir créé aveclandlock_create_ruleset_with_net), ouallowed_accessporte un bit inconnu du noyau ;EAFNOSUPPORT/ENOSYS: ABI Landlock antérieure à v4.
Sourcepub fn restrict_self(&self) -> Result<(), Errno>
pub fn restrict_self(&self) -> Result<(), Errno>
Applique le ruleset au thread courant.
Wrappeur de landlock_restrict_self(2). Irréversible. Après
cet appel, le thread ne peut plus accéder aux chemins filesystem
non couverts par les règles du ruleset (pour les accès dans
handled_access du ruleset).
Prérequis : avoir appelé crate::process::set_no_new_privs ou
posséder CAP_SYS_ADMIN.
§Errors
EPERM:no_new_privsnon positionné etCAP_SYS_ADMINabsent.EINVAL: flags invalides.EINTR: interruption par signal (ADR-021 convention 2 — remonté tel quel, sans retry automatique).
§Examples
use air_sys_syscall::security::landlock_create_ruleset;
use air_sys_syscall::process::set_no_new_privs;
use air_sys_types::security::LandlockAccessFs;
let ruleset = landlock_create_ruleset(LandlockAccessFs::READ_FILE)
.expect("create_ruleset");
set_no_new_privs().expect("no_new_privs");
ruleset.restrict_self().expect("restrict_self");Sourcepub fn restrict_self_with(
&self,
flags: LandlockRestrictFlags,
) -> Result<(), Errno>
pub fn restrict_self_with( &self, flags: LandlockRestrictFlags, ) -> Result<(), Errno>
Applique le ruleset avec des drapeaux (cf. LandlockRestrictFlags).
§Ce que TSYNC change, et pourquoi une fonction séparée n’aurait rien réglé
Sans TSYNC, le domaine ne borne que le fil
appelant : dans un processus multifil qui se met lui-même en cage, les fils frères
restent dehors, et la cage se contourne en changeant de fil. Avec lui, la
configuration s’applique atomiquement à tous les fils.
Les drapeaux ne sont pas des opérations multiplexées (ADR-021 convention 3) : ils se combinent, et un wrapper par combinaison serait une explosion combinatoire sans gain de typage.
§Le noyau refuse ce qu’il ne connaît pas
Un drapeau inconnu de l’ABI courante fait échouer l’appel (EINVAL) — il n’est
pas ignoré. La pose de cage étant fail-closed, demander un drapeau trop
récent tue le processus : interroger landlock_supported_abi d’abord.
§Errors
EPERM:no_new_privsnon positionné etCAP_SYS_ADMINabsent.EINVAL: un drapeau inconnu de l’ABI courante.EINTR: interruption par signal (ADR-021 convention 2 — remonté tel quel).