
Clickbait. The CVE is AI slop.
désolé pour le nom de dépôt putaclick mais cette CVE est un ramassis d'hallucinations LLM, franchement triste de voir une CNA accepter ça vu à quel point les affirmations sont incohérentes 💔
La CVE-2026-51302 n'est pas réelle 😱
Le SQL publié ne reproduit pas d'use-after-free dans aucune version de SQLite 3.41 sous AddressSanitizer. Plus important encore, la cause racine annoncée est totalement incompatible avec le code source concerné :
exprComputeOperands() n'existe pas dans SQLite 3.41.0, 3.41.1 ni 3.41.2 ;regFree1 est un identifiant entier de registre de la machine virtuelle, pas un pointeur vers un stockage heap ;sqlite3ReleaseTempReg() rend un registre disponible pour réutilisation et ne laisse pas de pointeur C pendant dans regFree1 ;exprComputeOperands(), les opérandes sont calculées avant la libération des registres temporaires, contrairement à la séquence annoncée dans l'avis ; etexprComputeOperands() a été introduite.Cet enregistrement CVE devrait être rejeté et je vais soulever un litige CNA auprès de MITRE 😉
L'avis identifie la version affectée comme « SQLite 3.41 » et fournit cette requête :
SELECT CASE WHEN (1+3) THEN (5*8) ELSE (2/0) END FROM test;
Il prétend que :
sqlite3ReleaseTempReg() libère la mémoire heap associée à regFree1 ;regFree1 reste comme une référence pendante ;exprComputeOperands() accède ensuite à la mémoire libérée ; etL'amalgamation SQLite 3.41.0 définit la fonction comme suit :
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
if( iReg ){
sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0);
if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
pParse->aTempReg[pParse->nTempReg++] = iReg;
}
}
}
La fonction reçoit iReg comme un int. Elle enregistre cet entier dans pParse->aTempReg afin que le numéro de registre puisse être réattribué :
SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){
if( pParse->nTempReg==0 ){
return ++pParse->nMem;
}
return pParse->aTempReg[--pParse->nTempReg];
}
Il s'agit de la gestion de la durée de vie des registres pendant la génération du programme VDBE. L'avis décrit regFree1 comme s'il s'agissait d'un pointeur survivant vers du stockage heap libéré. Ce n'est pas le cas :
int regFree1 = 0, regFree2 = 0;
int r1, r2;
r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1);
r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2);
codeCompare(pParse, pL, pR, opx, r1, r2, addrDone, p5, isCommuted);
sqlite3ReleaseTempReg(pParse, regFree1);
sqlite3ReleaseTempReg(pParse, regFree2);
La comparaison générée consomme les identifiants de registre avant qu'ils ne soient libérés pour réutilisation.
Une recherche de blame dans le miroir Git a révélé que exprComputeOperands() a été introduite par :
e24f20a4f5a6d26cdaece58eff77619a4ee757b9
2025-06-30T10:30:47Z
Factor out the code that tries to avoid evaluating subquery operands if the other operand is NULL into a subroutine, so that it can be more easily reused by other parts of the code generator.
La fonction est absente des trois amalgamations officielles de SQLite 3.41. Une vulnérabilité dans SQLite 3.41 ne peut pas suivre un chemin d'exécution à travers une fonction introduite en 2025, franchement MITRE, vraiment ? 🥲
Dans le code source moderne de SQLite, l'ordre abrégé des appels dans sqlite3ExprIfTrue() est :
addrIsNull = exprComputeOperands(
pParse, pExpr, &r1, &r2, ®Free1, ®Free2);
codeCompare(
pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr, EP_Commuted));
/* Other switch cases and generated-bytecode handling occur here. */
sqlite3ReleaseTempReg(pParse, regFree1);
sqlite3ReleaseTempReg(pParse, regFree2);
exprComputeOperands() produit les identifiants de registre. L'appelant les consomme puis les libère. L'avis prétend au contraire que sqlite3ReleaseTempReg() s'exécute en premier et que exprComputeOperands() accède ensuite à l'objet libéré.
exprComputeOperands() a été introduite pour éviter d'évaluer une opérande de sous-requête coûteuse lorsque l'autre opérande est NULL. L'expression publiée :
CASE WHEN (1+3) THEN (5*8) ELSE (2/0) END
contient des opérations arithmétiques et une expression CASE mais aucune opérande de sous-requête. La justification donnée pour cette requête ne correspond pas aux conditions d'appel de la fonction.
vm au fait
Debian GNU/Linux 13 (trixie)
Clang 19.1.7
AddressSanitizer activé
Niveau d'optimisation : -O1
Pointeurs de trame conservés
Récupération du désinfectant désactivée
SHA des amalgamations :
3.41.0 146ce189b67fdbefbf2d72cdc81e198d07ff643614cc9102e9bf063255e8e7e1
3.41.1 df0d54bf246521360c8148f64e7e5ad07a4665b4f902339e844f4c493d535ff5
3.41.2 01df06a84803c1ab4d62c64e995b151b2dbcf5dbc93bbc5eee213cb18225d987
3.53.3 646421e12aac110282ef8cc68f1a62d4bb15fc7b8f09da0b53e29ee690500431