Не запускается ntp, дебажим и находим причину

На одном из серверов FreeBSD перестал запускаться ntpd. То есть, работал и в один момент перестал. Причиной стал простой reboot сервера, без изменений конфига. Странно, но нужно разобраться. Начинаем стандартно: ldd, truss, дефолтный конфиг, дефолтные опции, включение debug’a в ntp и никакого намёка на проблему. Усложняет тот факт, что есть другой сервер с такими же настройками и такой же версией ОС и там всё работает. Остаётся один вариант — дебаггер gdb.

После установки запускаем через дебаггер gdb и внутри выполняем команду start:

# gdb /usr/sbin/ntpd
GNU gdb (GDB) 11.2 [GDB v11.2 for FreeBSD]
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-portbld-freebsd13.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
    .

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/sbin/ntpd...
Reading symbols from /usr/lib/debug//usr/sbin/ntpd.debug...
(gdb) start
Temporary breakpoint 1 at 0x272160: file /usr/src/contrib/ntp/ntpd/ntpd.c, line 447.
Starting program: /usr/sbin/ntpd

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffeb50) at /usr/src/contrib/ntp/ntpd/ntpd.c:447
447                     int aslr_var = PROC_STACKGAP_DISABLE;

Идём в /usr/src/contrib/ntp/ntpd/ntpd.c и смотрим, что там такого в строке 447 (на самом деле привёл полный кусок кода; сама строка 447 начинается с ‘int aslr’):

#   ifdef __FreeBSD__                                                                                                                                                                                       
        {                                                                                                                                                                                                   
                /*                                                                                                                                                                                          
                 * We Must disable ASLR stack gap on FreeBSD to avoid a                                                                                                                                     
                 * segfault. See PR/241421 and PR/241960.                                                                                                                                                   
                 */                                                                                                                                                                                         
                int aslr_var = PROC_STACKGAP_DISABLE;                                                                                                                                                       
                                                                                                                                                                                                            
                pid_t my_pid = getpid();                                                                                                                                                                    
                procctl(P_PID, my_pid, PROC_STACKGAP_CTL, &aslr_var);                                                                                                                                       
        }                                                                                                                                                                                                   
#   endif                          

Ага! Вот и виновник — ASLR. Лезем смотреть в sysctl и видим, что он включён!

# sysctl -a | grep aslr.enable       
kern.elf32.aslr.enable: 1
kern.elf64.aslr.enable: 1

Выключаем и после этого ntpd успешно запускается.

Для сравнения: на другом сервере ASLR был включён, но там ntpd продолжал работать. Видно попал в какой-то участок памяти, где смог запуститься. Тоже самое было, видимо, и до ребута этого сервера.

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

Ваш адрес email не будет опубликован.