В этой статье я расскажу, как можно настроить сохранение дампов в Linux при падении процессов, такие дампы называют core dumps.

Введение

При работе в Linux у вас запускается множество процессов, но иногда какой-нибудь процесс может начать падать. Или какая-нибудь программа может не запускаться. Иногда разработчики для анализа таких ситуаций просят выслать им дамп ядра (core dumps) относящийся к падению их программы.

Вообще core dumps никак не связан с ядром Linux. Термин «Ядро» в этом случае относится к старой памяти на магнитных сердечниках из старых систем (magnetic core memory). Хотя такая память уже не используется, но термин core dumps всё еще употребляется.

В core dumps сохраняется память сбойного процесса при его падении, а также некоторая служебная информация.

Ограничение на размер дампа

Самое главное ограничение, которое говорит системе, делать дамп упавшего процесса или не делать — это ограничение максимального размера дампа. Если это ограничение равняется 0 — то дамп не будет делаться совсем. Также вы можете ограничить максимальный размер дампа произвольным числом в байтах, или отключить лимит вовсе.

Посмотреть текущее ограничение для своего пользователя и своей оболочки можно выполнив команду:

$ ulimit -S -c
0

В выводе у меня 0 — это означает что создание дампов под моим пользователем и в моём окружении невозможно.

Командой выше мы смотрели мягкое (soft) ограничение. Это фактическое ограничение, которое влияет на процессы.

Есть ещё жесткое ограничение (hard), его может поменять только root пользователь. Давайте посмотрим как сейчас нас ограничивает жёсткое ограничение:

$ ulimit -H -c
unlimited

Из этого следует, что сейчас жёсткое ограничение нас вообще не ограничивает. Поэтому мы можем изменить для себя мягкое ограничение и разрешить создание дампов. Это делается командой:

$ ulimit -c unlimited

Проверим:

$ ulimit -S -c
unlimited

Куда сохранять дампы ядра

Чтобы узнать, куда сейчас сохраняются дампы ядра, нужно прочитать файл /proc/sys/kernel/core_pattern:

*** Debian 11 ***
$ cat /proc/sys/kernel/core_pattern
core

*** Ubuntu 22.04 ***
$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E

Debian называет файлы дампов именем core и куда-то их сохраняет (если честно, я не выяснял куда).

Ubuntu через пайп передаёт дамп на обработку программе apport.

Вы можете временно (до перезагрузки) изменить путь и имя дампов задав свой шаблон, например таким способом:

$ sudo sysctl -w kernel.core_pattern=/var/crash/core.%u.%e.%p

Выше мы меняем параметр sysctl — kernel.core_pattern. И задаём ему значение состоящее из пути и имени файла, а также используем переменные:

  • %u — имя пользователя (под каким пользователем работала упавшая программа);
  • %e — имя программы;
  • %p — номер процесса (pid).

Проверим что путь изменился. Затем нужно создать этот каталог, если его ещё не существует и убедиться что наш пользователь сможет в него писать.

*** Ubuntu 22.04 ***
$ cat /proc/sys/kernel/core_pattern
/var/crash/core.%u.%e.%p
$ ls -ld /var/crash/
drwxrwxrwx 2 root root 4096 апр 21 01:01 /var/crash/

*** Debian ***
$ cat /proc/sys/kernel/core_pattern
/var/crash/core.%u.%e.%p
$ ls -ld /var/crash/
ls: невозможно получить доступ к '/var/crash/': Нет такого файла или каталога
$ sudo mkdir /var/crash/; sudo chmod 777 /var/crash/
$ ls -ld /var/crash/
drwxrwxrwx 2 root root 4096 мая 31 15:50 /var/crash/

Хорошо, путь мы поменяли и каталог по этому пути сделали доступным. Ограничение на размер дампов для своей оболочки тоже сняли.

Создаём сбойную программу

Для того чтобы проверить что дампы для нас уже выполняются нужно запустить программу, которая точно упадёт. Напишем эту программу сами:

$ nano crash.c
int main()
{
    return 1/0;
}

Наша программа выполняет деление на 0 и это приводит к сбою.

Теперь нужно откомпилировать эту программу (возможно вам придется установить gcc):

$ gcc -o crash crash.c
crash.c: In function ‘main’:
crash.c:3:13: warning: division by zero [-Wdiv-by-zero]
    3 |     return 1/0;
      |             ^

Даже компилятор показывает, что наша программа содержит ошибку деления на ноль.

Теперь запустим программу:

$ ./crash
Floating point exception (core dumped)

Программа падает с ошибкой и видно что был сформирован core dumped. Если бы дампы ядра были отключены, этой надписи в скобках не появилось бы.

Посмотрим на наш файл дампа:

$ ls -l /var/crash/
total 120
-rw------- 1 alex alex 299008 мая 31 12:58 core.1000.crash.1397

Настройка создания дампов на постоянной основе

Проделанное выше вернётся к значениям по умолчанию после перезагрузки. Также остальные процессы, которые были запущены от имени других пользователей и в других оболочках не будут создавать дампы при падениях. Исправим это внеся изменения в конфигурационные файлы.

Ограничение на размер дампа

Настройка лимитов производится в конфиге /etc/security/limits.conf или лучше создать отдельный конфиг в каталоге /etc/security/limits.d/.

$ sudo nano /etc/security/limits.d/core.conf
root    hard        core        unlimited
root    soft        core        unlimited
*       hard        core        unlimited
*       soft        core        unlimited

Звездочка означает что это правило применимо ко всем пользователям в системе, кроме root. Для root пользователя нужно создавать отдельные правила.

Дальше идет тип ограничения. Soft — это мягкое ограничение, которое фактически ограничивает процессы. А hard — это верхняя граница для soft. Соответственно soft должно быть всегда меньше hard.

Core — это специальное ограничение для дампов ядра. Ограничивать лимитами можно многие параметры, но это выходит за рамки этой статьи.

Unlimited — означает, что мы не ограничиваем размер дампов. Здесь вы можете указать число в байтах, или 0 чтобы совсем выключить создание дампов.

Чтобы внесённые изменения применились к какому-нибудь процессу, этот процесс нужно перезагрузить.

Путь сохранения дампов

Отредактируйте конфиг /etc/sysctl.conf:

$ sudo nano /etc/sysctl.conf
kernel.core_pattern=/var/crash/core.%u.%e.%p
fs.suid_dumpable=2

Вторым параметром мы разрешаем программам имеющим бит Setuid тоже сохранять дампы при падениях.

Setuid – это бит разрешения, который позволяет пользователю запускать исполняемый файл с правами владельца этого файла. Другими словами, использование этого бита позволяет нам поднять привилегии пользователя в случае, если это необходимо.

Параметр fs.suid_dumpable для sysctl может принимать следующие значения:

  • 0 – отключено;
  • 1 – включено;
  • 2 – включено с ограничениями. Делает дампы ядра доступными для чтения только пользователю root.

Чтобы применить изменения, выполните sysctl с ключом -p.

$ sudo sysctl -p
kernel.core_pattern = /var/crash/core.%u.%e.%p
fs.suid_dumpable = 2

Разрешаем сохранять дампы службам systemd

Хорошо, путь к созданию дампов мы указали и лимиты для всех пользователей убрали.

Но для сохранения дампов служб работающих в systemd, нам нужно настроить ещё один конфиг.

$ sudo nano /etc/systemd/system.conf
DefaultLimitCORE=infinity

Чтобы применить изменения выполните следующие команды:

$ sudo systemctl daemon-reexec
$ sudo systemctl restart nginx.service

И чтобы проверить применились ли наши изменения посмотрите информацию о лимитах для процесса nginx:

$ systemctl status nginx.service | grep 'Main PID'
   Main PID: 2099 (nginx)
$ cat /proc/2099/limits | grep 'core'
Max core file size        unlimited            unlimited            bytes

В командах выше я вначале получаю PID основного процесса nginx, а затем использую его, чтобы посмотреть лимиты этого процесса.

Вот теперь nginx сможет сохранить дамп при падении.

Сохранения дампа при падении nginx

Чтобы имитировать падение nginx, убьём его главный процесс отправив сигнал SIGSEGV:

$ sudo kill -s SIGSEGV 2099

Проверим что дамп появился:

$ ls -l /var/crash/
total 1940
-rw------- 1 root root 2347008 мая 31 13:41 core.0.nginx.2099
-rw------- 1 alex alex  299008 мая 31 12:58 core.1000.crash.1397

Чтение дампов ядра

Чтобы понять что произошло нужно прочитать дамп ядра. Для этого используется утилита gdb (её нужно установить). Вначале указывается путь к программе, затем путь к дампу:

*** Дамп нашей сбойной программы ***
$ gdb ./crash /var/crash/core.1000.crash.1397
Program terminated with signal SIGFPE, Arithmetic exception.
Программа завершилась с сигналом SIGFPE, арифметическое исключение.

*** Дамп процесса nginx ***
$ sudo gdb /usr/sbin/nginx /var/crash/core.0.nginx.2099
Program terminated with signal SIGSEGV, Segmentation fault.
Программа завершена с сигналом SIGSEGV, ошибка сегментации.

Вывод

Дампы ядра могут быть полезны для устранения неполадок, но могут стать причиной утечки конфиденциальных данных. По возможности отключайте дампы ядра и включайте их только тогда, когда это действительно необходимо. И проверяйте, надежно ли хранятся файлы, чтобы обычные пользователи не могли видеть их. И независимо от того, какой выбор вы сделали, всегда проверяйте, работает ли ваша конфигурация именно так, как вы ожидаете.

Сводка
Настройка дампов ядра (core dumps) в Linux
Имя статьи
Настройка дампов ядра (core dumps) в Linux
Описание
В этой статье я расскажу, как можно настроить сохранение дампов в Linux при падении процессов, такие дампы называют core dumps

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *