Проверьте nginx на AlmaLinux, если после обновления часть запросов отвечает ошибкой 500

4 ноября 2026 года Andrew Lukoshko, ведущий архитектор AlmaLinux, написал в блоге проекта: после недавней заплатки nginx от CVE-2026-42533 сервер на части конфигов время от времени отвечает кодом 500. В /var/log/nginx/error.log при этом появляется alert no buffer space in script copy. Тот же адрес может открыться со следующего запроса. Причину нашли. Новые пакеты убирают эти 500 и оставляют проверку из CVE на месте. Сборки уже лежат в репозитории testing. В обычные репозитории их ещё не выложили, и AlmaLinux просит помочь с проверкой, пока пакеты туда не попали.

Строка no buffer space in script copy

Жалобы пришли после установки пакетов, которые закрывают CVE-2026-42533. AlmaLinux повторила сбой на каждом своём релизе, куда эта заплатка доехала. В журнале nginx строка выглядит так, как в примере из заметки:

[alert] 12345#0: *678 no buffer space in script copy, client: 192.0.2.10, server: example.com, request: "GET /some/path HTTP/1.1"

Каждая такая строка значит, что запрос закончился ответом 500. На одном из затронутых сайтов на отдельном location падало от трети до половины запросов. Со стороны это легко спутать с капризом кэша или php-fpm: страницу обновил, она открылась, обновил ещё раз, уже 500. PHP здесь ни при чём. Смотреть надо error.log nginx, не журнал пула.

Map с пометкой volatile

Ломается не любой конфиг. Нужны две вещи сразу. Директива set или rewrite читает переменную из map, у этого map стоит volatile, и значение map само собрано из других переменных. Без volatile nginx считает map один раз и запоминает результат ещё до внешнего скрипта. Вложенного запуска нет, и этой ошибки нет. С пометкой volatile nginx не берёт запомненное значение: map считается заново, когда set или rewrite к нему обращается.

AlmaLinux показывает такой кусок. Так часто собирают ключ кэша и location, которым этот кэш сбрасывают. На WordPress за nginx ключ кэша нередко собирают похожим map. Смотреть надо, стоит ли у него volatile и собрано ли значение из других переменных.

map $uri $cache_key {
    volatile;
    default "$scheme://$host$uri$is_args$args";
}

server {
    location /purge/ {
        set $key $cache_key;
        ...
    }
}

До обновления под CVE-2026-42533 эта схема работала.

Если nginx приехал из Ubuntu или Debian, сборки из этой заметки не ваши. Имена пакетов ниже принадлежат AlmaLinux, в apt их нет. Речь про AlmaLinux 8, 9 и 10. Какой модульный поток включён, показывает dnf module list nginx. Репозиторий testing отдаст обновление только для уже включённого потока.

Одна глобальная переменная на конец буфера

CVE-2026-42533 относится к коду, который собирает строки из переменных для set, rewrite, return и proxy_pass. Специально собранный запрос мог выйти за конец буфера (buffer overrun). Upstream перед копированием проверяет, что запись не уйдёт дальше конца, и хранит этот конец отдельно для каждого запуска скрипта. Заметка ссылается на коммит nginx 7ac6789.

Новое поле в структуре меняет двоичный интерфейс модулей (ABI). Сторонние динамические модули, собранные под текущие пакеты, после такого изменения не загрузились бы. В пакетах CentOS Stream и RHEL, а за ними и в AlmaLinux, конец буфера положили в одну глобальную переменную. Пока скрипт один, этого хватает.

Скрипты бывают вложенными. Когда set $key $cache_key копирует значение volatile-map, nginx считает map прямо сейчас. Внутренний скрипт собирает строку $scheme://$host$uri... и записывает в ту же глобальную переменную конец уже своего буфера. Внешний set возвращается к работе, а проверка границы смотрит не на его буфер. Сработает она или нет, зависит от того, куда эти два буфера легли в памяти. Поэтому ответ 500 приходит не на каждый запрос.

Починка короткая. Каждая функция, которая запускает скрипт, запоминает текущий конец глобального буфера и возвращает его, когда скрипт закончился. В заметке названы ngx_http_complex_value(), ngx_http_script_run() и такие же функции модуля stream. Внутренний скрипт по-прежнему пользуется глобальной переменной, а внешний получает своё значение обратно. Снаружи это работает как у upstream, где конец хранится отдельно на каждый запуск. Поле в структуру не добавляли, поэтому уже собранные динамические модули трогать не нужно.

Проверки из заплатки CVE остаются и смотрят уже в свой буфер. AlmaLinux прогнала запрос, который вызывает исходный выход за буфер: он по-прежнему отвергается с HTTP 500 и тем же alert. Конфиги вроде примера выше перестают сыпать ошибками.

На 2000 запросах к этому примеру AlmaLinux насчитала так:

  • AlmaLinux 9, nginx 1.20. До починки 26 ответов 500, с новой сборкой 0.
  • AlmaLinux 9, поток nginx:1.24. Было 20, стало 0.
  • AlmaLinux 10, nginx 1.26. Было 19, стало 0.

В прогоне на 2000 запросов участвовали AlmaLinux 9 и 10. Для AlmaLinux 8 в testing лежит свой пакет потока nginx:1.24. Ту же ошибку и ту же починку отправили в Red Hat, заявка RHEL-300689, чтобы их приняли в CentOS Stream и RHEL.

Сборки, которые лежат в testing

В обычный репозиторий пакеты ещё не положили. На машины они попадут у тех, кто сам включит testing. На проде AlmaLinux не советует оставлять этот репозиторий включённым после установки. Оставить его имеет смысл на машине, где сайт специально можно уронить. На боевом после обновления testing отключают.

  • AlmaLinux 8, поток nginx:1.24: nginx-1.24.0-3.module_el8.10.0+4351+6f6e4e3e.5.alma.2
  • AlmaLinux 9, пакет по умолчанию: nginx-1.20.1-28.el9_8.6.alma.2
  • AlmaLinux 9, поток nginx:1.24: nginx-1.24.0-7.module_el9.8.0+335+c30a9238.5.alma.2
  • AlmaLinux 10, пакет по умолчанию: nginx-1.26.3-6.el10_2.7.alma.1

AlmaLinux в первую очередь ждёт тех, кто уже видел alert no buffer space in script copy. Письмо, что всё тихо, тоже нужно: ошибка случайная, и короткий заход на главную может её не поймать. Если у map нет volatile, этот сбой, как пишет AlmaLinux, не возникает. Снимать уже поставленную заплатку CVE незачем. Новая сборка оставляет защиту и убирает лишние ответы 500.

Команды из заметки:

sudo dnf install -y almalinux-release-testing
sudo dnf upgrade 'nginx*' --enablerepo=almalinux-testing
rpm -q nginx
sudo nginx -t && sudo systemctl restart nginx
sudo grep 'no buffer space in script copy' /var/log/nginx/error.log
sudo dnf config-manager --disable almalinux-testing

rpm -q nginx должен совпасть со строкой вашего релиза из списка выше. Пакет сам nginx не перезапускает. Пока службу не перезапустили, в памяти остаётся прежний бинарник, и ответы 500 не пропадут. nginx -t перед restart нужен по делу: кривой конфиг после рестарта положит весь сервер, не один location.

AlmaLinux просит именно restart, чтобы поднять новый бинарник. На живом сайте будет короткий обрыв соединений, лучше выбрать тихое окно. grep по журналу найдёт и старые строки. Смотрите время записи, а не сам факт, что фраза в файле когда-то была.

Результат, и если сломалось, и если день прошёл без 500, AlmaLinux просит прислать в канал Development их Mattermost, на bugs.almalinux.org или письмом на packager@almalinux.org.

Источники и ссылки


Комментарии загружаются…