Poważny bug w PHP

Rick Regan opublikował na blogu exploringbinary.com informacje na temat poważnego błędu w PHP. Przetwarzanie określonej liczby może doprowadzić do wpadnięcia w nieskończoną pętlę wykorzystującą 100% zasobów procesora, co w wyniku zawiesi interpreter. Problem dotyczy dużej liczby serwerów opartych o procesor 32 bitowy.

Aby doprowadzić do zawieszenia PHP, wystarczy naprawdę niewiele:

<?php $d = 2.2250738585072011e-308; ?>

Feralny ciąg to największa liczba zmiennoprzecinkowa podwójnej precyzji. Taki sam wynik będzie miało podanie liczby w normalnej notacji, wtedy jednak zawiera ona 324 cyfry. Problem pojawia się, gdy przetwarzamy powyższy ciąg jako liczbę. W przypadku, gdy traktowany jest jako string, nie wywołuje nieporządnego efektu.

Poniższy kod zatem nie jest niebezpieczny:

<?php $d = '2.2250738585072011e-308'; echo $d; ?>

Ale następujący powoduje opisany wyżej problem:

<?php $d = '2.2250738585072011e-308'; echo $d + 0; ?>

Autor testował zachowanie powyższego kody na maszynie z procesorem Intel Core Duo: pod Windows z PHP 5.3.1 i XAMPP 1.7.3, oraz pod Linux z PHP 5.3.2-1ubuntu4.5. W obu przypadkach doszło do nawieszenia interpretera. Czytelnicy exploringbinary.com w komentarzach do posta publikowali wiele innych konfiguracji, które były lub nie były odporne na opisany błąd. Dyskusję dotyczącą błędu można także zobaczyć na trackerze bugów PHP.

Zespół PHP potwierdził istnienie problemu, który jest związany z wadą występującą w koprocesorze FPU z zestawem instrukcji x87 (występujący w procesorach z rodziny x86). Błąd nie dotyczy więc tylko PHP, może występować w innych językach oraz aplikacjach. Nie pojawi się jednak, jeśli PHP zostało skompilowane z flagami -mfpmath=sse lub -ffloat-store.

Odnaleziony błąd można uznać za całkiem poważny. Teoretycznie można doprowadzić do zawieszenia PHP na podatnych serwerach poprzez wpisanie feralnego ciągu jako parametru GET lub podaniu do w zwykłym formularzu, przetwarzającym go jako liczbę. Należy pamiętać, że przez przetwarzanie należy rozumieć samo przypisanie do zmiennej lub użycie jakiejkolwiek funkcji matematycznej na niebezpiecznej liczbie. Na taki rodzaj ataku może być podatna ogromna liczba serwisów internetowych. W większości przypadków będzie polegał na zużyciu zasobów procesora w 100%, chwilowym zawieszeniu i zrestartowaniu PHP.

Sposobów na rozwiązanie problemu jest kilka. Można skorzystać z udostepnionej poprawki, przekompilować PHP z flagami -mfpmath=sse lub -ffloat-store, albo na poczatku swoich skryptów PHP umieścić  proponowany przez niebezpiecznik.pl kod:

if (strpos(str_replace('.', '', serialize($GLOBALS)),
'22250738585072011')!==false) die();

Dzisiaj zostały także wydane nowe PHP 5.3.5 oraz 5.2.17, w których usunięto problem. W przypadku gałęzi 5.2 jest to już trzecie z rzedu „ostatnie” wydanie, kończące support tej wersji.

Dodaj komentarz