veilletech.fr
5 nov. Feed du jour
#05 LARAVEL Article

Laravel 13.40 : un RCE corrigé dans Concurrency

Un nombre nu n'a pas la même unité dans les deux méthodes.

Laravel 13.40 corrige une exécution de code dans Concurrency::run() avec le driver process : le résultat d'une tâche, lu sur la sortie du processus enfant puis désérialisé, est désormais signé par une clé aléatoire. La version ajoute aussi des alertes de jobs et de tâches trop longs, des identifiants de commit pour les répliques de lecture et des correctifs de transactions.

3 min de lectureintermédiairevidéo 1:24
Partager
Sommaire4 sections
  1. Ce qui se passe
  2. Les nouveautés utiles
  3. Comment s'y prendre
  4. À retenir

Ce qui se passe

Laravel 13.40.0 corrige une exécution de code à distance dans Concurrency::run() quand le driver est process, le driver par défaut. Le processus parent lisait le résultat de chaque tâche sur la sortie du processus enfant, puis le désérialisait. Une tâche qui affichait du texte contrôlé par un utilisateur pouvait donc écrire un faux résultat, que le parent désérialisait. Le défaut a été signalé par @Arr0way (PR #62297). La note de version ne donne pas d'identifiant CVE.

Désormais, l'enfant écrit son résultat dans une trame signée avec une clé aléatoire que le parent crée pour chaque tâche ; le parent ignore toute trame que la clé ne valide pas. Au passage, l'erreur « Trying to access array offset on null », que provoquait une tâche qui affichait quoi que ce soit, disparaît aussi.

Les nouveautés utiles

Alertes de lenteur. Queue::whenJobRunsLongerThan() et Schedule::whenTaskRunsLongerThan() appellent une fonction quand un job ou une tâche planifiée dépasse un seuil. Les unités diffèrent : un nombre nu se lit en millisecondes pour les jobs, en secondes pour les tâches planifiées. Passez plutôt un CarbonInterval.

PHP
Queue::whenJobRunsLongerThan(CarbonInterval::seconds(90), function ($job, $duration) {
    Log::warning($job->resolveName().' : '.$duration.' ms');
});

Schedule::whenTaskRunsLongerThan(CarbonInterval::minutes(45), function ($task, float $runtime) {
    Log::warning('Tâche planifiée : '.$runtime.' s');
});

Le premier écoute JobAttempted : il se déclenche aussi pour une tentative qui échoue ou qui est remise en file.

Retard des répliques de lecture. DB::getLastCommitId() renvoie un identifiant de commit après une écriture, et DB::hasCommitId($id, wait: 2) dit si la réplique l'a reçu, éventuellement en attendant deux secondes. mergeCommitIds() combine plusieurs identifiants. Cela fonctionne sur MySQL avec GTID, MariaDB avec journal binaire et PostgreSQL ; l'attente sur PostgreSQL demande PostgreSQL 19. Les autres drivers lèvent une RuntimeException. C'est une alternative précise au middleware PreventStaleDatabaseReads de la 13.38, qui envoie les lectures vers le serveur d'écriture pendant une durée fixe.

Entrées de requête. Un argument strict sur integer(), float(), boolean() et string() renvoie la valeur par défaut au lieu de convertir ?count=abc123 en 0. En mode strict, boolean() n'accepte que 1, true, on, yes, 0, false, off et no.

Middleware. insertBefore() et insertAfter() (et leurs variantes InGroup) dans bootstrap/app.php placent un middleware juste avant ou après un middleware natif, sans redéclarer toute la pile.

Transactions. Après une connexion perdue en pleine transaction, Laravel jette le PDO mort et se reconnecte à la requête suivante ; avant, chaque transaction échouait avec « There is already an active transaction » jusqu'au redémarrage du worker ou d'Octane. Un verrou expiré ou un deadlock dans une transaction imbriquée revient maintenant au point de sauvegarde de celle-ci, au lieu de valider les écritures imbriquées.

Comment s'y prendre

Terminal
composer update laravel/framework
grep -rn "Concurrency::run" app/ routes/

Si vous utilisez Concurrency::run() avec le driver process, mettez à jour sans attendre. Réglez ensuite vos seuils en fonction de l'unité de chaque méthode.

Source : Laravel News, qui reprend le journal des modifications de la 13.40.0. Source en anglais.