Intermédiaire·3 min·29 avril 2026

Rust ne protège pas contre ces bugs de sécurité

44 failles de sécurité dans du code Rust professionnel : le borrow checker ne les a pas vues.
Rust ne protège pas contre ces bugs de sécurité

Pourquoi ça compte pour toi

Si tu écris du code système en Rust (CLI, outils privilégiés, services), tu crois être protégé par le compilateur. L'audit de Canonical sur uutils montre que c'est faux sur des vecteurs d'attaque classiques. Ces bugs ne sont pas des erreurs de débutant : ils viennent d'une réimplémentation de GNU coreutils par des gens qui savaient ce qu'ils faisaient. C'est la leçon de sécurité la plus dense sur Rust en ce moment.

Ce qu'il faut retenir

  • 1.Les interfaces ergonomiques de Rust (fs::metadata, File::create) rerésoluent le chemin à chaque appel : ouvertes aux attaques TOCTOU entre deux syscalls.
  • 2.Créer un fichier/dossier avec permissions restreintes APRÈS sa création = fenêtre de tir : un autre utilisateur peut l'ouvrir avant le chmod.
  • 3.Comparer des chemins en chaîne de caractères ("" vs "/../") rate les symlinks : il faut canonicaliser avant de comparer.
  • 4.Convertir les bytes Unix en UTF-8 avec from_utf8_lossy corrompt silencieusement les données binaires.

Rust ferme certaines portes, en laisse d'autres grandes ouvertes

Le compilateur Rust t'empêche les buffer overflows, les use-after-free, les data races. Mais il ne sait rien des bugs de logique système qui vivent entre deux appels noyau.

TOCTOU : le classique que tu dois éviter

Le scénario standard :

// 1. Vérifier que le fichier existe
fs::metadata(path)?;

// 2. L'utiliser — mais entre les deux, quelqu'un peut le swapper
fs::remove_file(path)?;

Entre l'étape 1 et 2, un attaquant avec accès en écriture au dossier parent peut remplacer path par un symlink vers /etc/shadow. Le noyau rerésout le chemin de zéro à chaque syscall. Si le processus est privilégié, boom : tu as écrit sur le fichier système.

L'exemple de CVE-2026-35355 :

// ❌ Mauvais : TOCTOU
fs::remove_file(to)?;
let mut dest = File::create(to)?;  // path rerésolu ici

// ✅ Bon : create_new atomique
let mut dest = OpenOptions::new()
    .write(true)
    .create_new(true)  // Échoue si existe déjà (symlink inclus)
    .open(to)?;

Permissions : fixe-les à la création, jamais après

Code dangereux :

fs::create_dir(&path)?;           // Permission par défaut
fs::set_permissions(&path, 0o700)?;  // Trop tard : quelques millisecondes dangereuses

Un autre utilisateur peut ouvrir le dossier pendant ce laps de temps. Après, le chmod ne le ferme pas — il a déjà un descripteur de fichier valide.

Utilise OpenOptions::mode() ou DirBuilderExt::mode() pour que le fichier naisse avec les permissions correctes.

Comparer des chemins : tu dois canonicaliser

La vérification originale du --preserve-root de chmod :

// ❌ Échoue contre /../, /./, /usr/.., ou symlinks vers /
if file == Path::new("/") {
    return Err(PreserveRoot);
}

Correction :

fn is_root(file: &Path) -> bool {
    matches!(fs::canonicalize(file), Ok(p) if p == Path::new("/"))
}

canonicalize dissout les .., ., et symlinks en chemin absolu réel. La comparaison de chaînes ne suffit pas.

UTF-8 aux limites Unix : source de corruption silencieuse

La commande comm en Rust :

// ❌ from_utf8_lossy remplace les bytes invalides par U+FFFD
print!("{}", String::from_utf8_lossy(raw_bytes));

// ✅ Rester en bytes
let mut out = BufWriter::new(io::stdout().lock());
out.write_all(raw_bytes)?;  // Écrit directement, pas de UTF-8 round-trip

GNU comm traite des fichiers binaires en manipulant des bytes bruts. La version Rust corrompait silencieusement tout ce qui n'était pas de l'UTF-8 valide.

À retenir

Rust te protège contre des classes entières de bugs. Mais les systèmes Unix sont rusés : ils cachent de la logique dans les syscalls, les chemins, les permissions. Le compilateur n'y voit rien. Si tu écris du code système :

  • Ancre-toi sur des descripteurs de fichiers, pas des chemins.
  • Fixe les permissions à la création, jamais après.
  • Canonicalise avant de comparer des chemins.
  • Reste en bytes aux limites Unix (chemins, variables d'environnement, flux).

L'honnêteté de Canonical à partager cet audit en détail ? C'est du rare, et c'est utile pour tous.

Approfondir avec un guide

📊 Cours en bourse

Newsletter quotidienne

3 minutes d'IA dans ta boîte mail, chaque matin.

Rejoins les francophones qui comprennent, essaient et progressent avec l'IA. Un email court, utile, sans spam. Désabonnement en 1 clic.

Explorer les thèmes de cet article :