DoS-уязвимость при обработке некоторых чисел с плавающей запятой

05.01.2011 20:17

В интерпретаторе PHP версий 5.2 и 5.3 была обнаружена довольно странная ошибка: при обработке некоторых числовых значений (в частности, 2.2250738585072011e-308) интерпретатор зависал (достаточно выполнить "$a = 2.2250738585072011e-308;" или "$a = '2.2250738585072011e-308'; echo $a + 0;").

Как показали дальнейшие исследования, такое поведение интерпретатора вызвано наличием ошибки округления, порождающей бесконечный цикл при попытке преобразования строки в число. Что характерно, сходные аномалии при операциях с вещественными значениями были замечены при работе с gcc еще в 2000 году. Однако, стоит подчеркнуть, что корень ошибки кроется не в конкретной реализации компилятора, а в некорректной работе процессоров архитектуры x86 с вещественными 64-битными типами данных, при задействовании набора инструкций x87. На других архитектурах, включая x86_64, данная ошибка не возникает (в x86_64 вместо x87 используются инструкции SSE2).

Возникшая в результате этой ошибки DoS-уязвимость PHP может быть задействована удаленно — достаточно передать «магическое число» в качестве значения параметра, с которым в коде производятся какие-либо арифметические операции (в виде обычной стоки такое число, естественно, угрозы не представляет — проблема возникает при преобразовании этой строки в число). Кроме числа 2.2250738585072011e-308, подобный эффект вызывают числа 0.22250738585072011e-307, 22.250738585072011e-309 и 22250738585072011e-324.

Как уже упоминалось, данной проблеме подвержены ветки PHP 5.2 и 5.3. В готовящейся к выходу версии 5.3.5 она уже исправлена, для остальных версий можно задействовать простой патч (добавляет спецификатор volatile перед некоторыми объявлениями типа double). Другим вариантом решения проблемы является пересборка PHP с опцией "-ffloat-store" или "-mfpmath=sse".

Дополнение: доступен для загрузки релиз PHP 5.3.5 с устранением уязвимости.