Jest wpół do drugiej w nocy. Siedzę w biurze. Serwer Apache wygląda na stabilny. Dokładnie, wygląda.

Prawie wszystkie działające u nas aplikacje są zaimplementowane jako usługi FastCGI serwowane przez Lighttpd. Bazy danych działają w osobnych serwerach wirtualnych, podobnie odseparowany jest Apache, który dzierży brzemię mielenia PHP i przedzierania się przez gąszcze plików .htaccess.

Wszystko byłoby pięknie, gdyby Apache nie zaczął sobie chodzić na spacerek do krainy wiecznych łowów (jak to Indianie mają w zwyczaju czynić po SIGSEGV). Szybki (błyskawiczny rzekłbym, ale to nie prawda) strace i końcówka gdb pokazały, że ślad urywa się gdzieś w PHP.

Następny test — przestawienie PHP z mod_php (użytkownicy nie mają dostępu do kodu serwisów, więc nie bawiliśmy się w żadne separacje użytkowników) na CGI. Tym razem dzielny serwer przetrwał, w przeciwieństwie do skryptu. Kolejny strace i gdb na symulowanym środowisku CGI (w bardzo wysublimowany sposób — export QUERY_STRING=… i tak dalej) i okazuje się, że zdycha jednak biblioteka implementująca PCRE.

Dużo Google. Bardzo dużo. W końcu pomaga Qwiat. Miał to samo, pomógł downgrade pakietu pcre do wersji 6.7. Przebudowa wspomnianego pakietu we wspomnianej wersji, upgrade w vserwerze, restart usług. Działa. Nieźle się maskuje.

Kod serwisów zdaje się działać bez zarzutu. Chciałem zarzucić temat, ale obiecałem znaleźć syntetyczny testcase. Więcej Google. Na liście błędów pcre jest znana podatność na przepełnienie stosu. Autorzy zdają się mieć ją w dużym poważaniu. Wersja 7.x zdycha, wersja 6.x działa. A takiego.

<?php
print 'A teraz coś z zupełnie innej beczki: ';
preg_match('/(.(?!b))*/', str_repeat("a", 10000));
?>

Powyższy kod położył mi każdą kombinację PHP i PCRE. Bardzo ładny sposób, żeby komuś zrobić DOS na PHP działające w trybie FastCGI (po n-tym padzie usługi w krótkim czasie serwer słusznie uzna, że jest uszkodzona i przestanie ją wskrzeszać, przynajmniej na jakiś czas).

I tym optymistycznym akcentem zakończę swoje gadanie od rzeczy i udam się do domu spać.