Tailscale remonte 19 corruptions de base à un bug SQLite vieux de 16 ans
Tailscale explique avoir identifié la cause de plusieurs pannes de son plan de contrôle dans un bug rare de SQLite, la base embarquée souvent choisie pour sa simplicité et sa robustesse. Le point intéressant pour les développeurs n’est pas seulement le correctif : c’est la manière dont une configuration valide mais peu courante — des checkpoints WAL (journal d’écriture anticipée) pilotés manuellement et très fréquents — a suffi à faire émerger un défaut resté caché pendant au moins 16 ans. ([tailscale.com](https://tailscale.com/blog/sqlite-wal-reset-bug))
Fil « Bug SQLite WAL-reset »
Tailscale dit avoir subi 19 incidents distincts de corruption sur six mois, avec des interruptions qui ont d’abord dépassé une heure sur les fragments internes touchés de son service de contrôle. L’entreprise stocke l’état de chaque fragment dans une base SQLite par shard (serveur de coordination isolé), accédée par un seul processus Go en écriture — un modèle explicitement aligné avec l’usage normal de SQLite. Les données touchées relevaient de la configuration du réseau privé virtuel, pas des clés privées ni du trafic. (tailscale.com)
Ce qui a réellement cassé
Le bug se niche dans le mode WAL (Write-Ahead Logging, journal où les écritures vont d’abord avant d’être recopiées dans le fichier principal). Chez Tailscale, les sauvegardes imposaient de piloter manuellement les checkpoints (phase où SQLite recopie les pages du journal dans le fichier principal) et de les lancer de façon agressive. Avec l’aide des mainteneurs de SQLite et d’un nouvel outil de traçage au niveau VFS (Virtual File System, couche d’accès au système de fichiers), ils ont fini par isoler une course critique (data race, deux opérations qui se chevauchent dans un mauvais ordre) entre un checkpoint et une transaction d’écriture. Résultat : certaines pages étaient considérées comme recopiées alors qu’elles ne l’étaient pas, puis des pages dépendantes — par exemple un index — étaient bien écrites, ce qui laissait la base dans un état incohérent. (tailscale.com)
Un indice décisif est venu de leur propre pipeline de reprise : Tailscale a journalisé chaque requête SQL modifiant la base afin de pouvoir rejouer les transactions à partir d’un snapshot sain. Dans deux incidents, ce rejeu a montré qu’une écriture validée devenait invisible pour les transactions suivantes, sans erreur remontée par SQLite. C’est ce symptôme, ajouté à des métriques de checkpoint montrant davantage de pages copiées que présentes dans le WAL, qui a orienté l’enquête vers ce que les mainteneurs ont baptisé le "WAL-Reset bug". Ils estiment que ce défaut était présent depuis au moins 16 ans. (tailscale.com)
Les versions à retenir
Les mainteneurs de SQLite ont d’abord publié le correctif dans SQLite 3.52.0. Mais Tailscale a alors vu apparaître 13 bases signalées corrompues par PRAGMA integrity_check. Ce n’était pas la même panne : SQLite a attribué ces alertes à un autre problème, lié à des indexes d’expression obsolètes (indexes construits sur une valeur calculée, devenue incohérente après un changement de calcul). Dans leur cas, une conversion texte → nombre à virgule flottante sur des horodatages de haute précision avait changé subtilement de comportement d’arrondi. Le résultat : 3.52.0 a été retirée, et SQLite a publié 3.51.3 avec uniquement le correctif du bug WAL-Reset. Ensuite, SQLite 3.53.0 a ajouté un mécanisme d’auto-réparation pour ce problème d’index calculé. (tailscale.com)
Ce que ça change concrètement pour toi
Si tu utilises SQLite en mode standard, le billet de Tailscale dit explicitement que la plupart des utilisateurs ne verront jamais ce problème. En revanche, si ton application ou ton service prend le contrôle fin de la base — sauvegardes maison, checkpoints pilotés, instrumentation du moteur, exécution très agressive sur un stockage local — ce retour d’expérience rappelle qu’une configuration documentée et supportée peut quand même sortir du chemin le mieux testé. Leur mitigation opérationnelle vaut presque autant que le correctif lui-même : arrêt immédiat à la détection de corruption, vérification continue des sauvegardes avec PRAGMA integrity_check, journalisation des transactions, et déploiement progressif des nouvelles versions. (tailscale.com)
PRAGMA integrity_check;
“running boring technology in a non-standard way is a risk.” (tailscale.com)
Dernier signal rassurant : après déploiement du correctif, Tailscale a modifié son pilote SQLite pour journaliser le chevauchement entre écriture et réinitialisation du WAL. L’alerte attendue a fini par se produire deux mois plus tard, sans corruption, ce que l’entreprise considère comme une confirmation positive que le correctif bloque bien le scénario fautif. Au moment de la publication, elle indique aussi avoir passé quatre mois supplémentaires sans incident. Pour un développeur backend, la leçon est simple : SQLite reste une option sérieuse, y compris en production, mais dès qu’on sort du mode d’exploitation banal, il faut traiter la base comme n’importe quel composant critique : observabilité, validation d’intégrité, stratégie de restauration et montée de version prudente. (tailscale.com)