Почему я получаю ошибку сегментации в Python, когда /tmp монтируется с помощью noexec?

Я запускаю пользовательское приложение Python 2.7.3 на CherryPy в Linux. Когда я использовал сценарий службы в /etc/init.d/ для запуска или остановки службы, я столкнулся с ошибкой сегментации (SIGSEGV). Как ни странно, я не получил SIGSEGV, если запускал команду запуска или остановки вручную из оболочки, используя «python /path/to/file.py --stop». Сервисный скрипт выполняет ту же команду.

После некоторой отладки я случайно обнаружил, что мой /tmp был смонтирован с параметром «noexec». Я удалил параметр «noexec», и приложение могло запускаться и останавливаться с помощью служебных сценариев без каких-либо ошибок сегментации.

Когда я впервые столкнулся с проблемой, я запустил strace и создал дамп ядра. Ни один из инструментов не дал мне никаких указаний на то, что /tmp был виновником. Мой вопрос таков: как я мог использовать strace или gdb, чтобы помочь мне определить, что «noexec» в /tmp вызывает ошибки сегментации?

Вот некоторый вывод gdb при анализе дампа ядра:


    (gdb) bt full
    #0  PyObject_Malloc (nbytes=4) at Objects/obmalloc.c:788
            bp = 0x7f6b0fd1c6e800 \Address 0x7f6b0fd1c6e800 out of bounds\
            pool = 0x7f6b0fd1c000
            next = \value optimized out\
            size = 0
    #1  0x00007f6b0f7fd8e6 in _PyUnicode_New (length=1) at Objects/unicodeobject.c:345
            new_size = 4
            unicode = 0x3873480
    #2  0x00007f6b0f7fdd4e in PyUnicodeUCS2_FromUnicode (u=0x38367cc, size=)
        at Objects/unicodeobject.c:461
            unicode = \value optimized out\

(Есть гораздо больше вывода, это только первые несколько строк)

Вот некоторый вывод strace об ошибке:


    3046  open("/usr/local/python2.7/lib/python2.7/site-packages/oauthlib/common.py", O_RDONLY) = 9
    3046  fstat(9, {st_mode=S_IFREG|0644, st_size=13310, ...}) = 0
    3046  open("/usr/local/python2.7/lib/python2.7/site-packages/oauthlib/common.pyc", O_RDONLY) = 10
    3046  fstat(10, {st_mode=S_IFREG|0644, st_size=16043, ...}) = 0
    3046  mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbc9ff9d000
    3046  read(10, "\3\363\r\n}\321\322Tc\0\0\0\0\0\0\0\0\5\0\0\0@@\2\0sd\2\0\0d\0"..., 4096) = 4096
    3046  fstat(10, {st_mode=S_IFREG|0644, st_size=16043, ...}) = 0
    3046  read(10, "\0\0\0C@\2\0s\330\0\0\0t\0\0|\0\0t\1\0\203\2\0s\36\0t\0\0|\0"..., 8192) = 8192
    3046  read(10, "thon2.7/site-packages/oauthlib/c"..., 4096) = 3755
    3046  read(10, "", 4096)                = 0
    3046  close(10)                         = 0
    3046  munmap(0x7fbc9ff9d000, 4096)      = 0
    3046  --- SIGSEGV (Segmentation fault) @ 0 (0) ---

После устранения проблемы, вот фрагмент из strace, из того же места, где он пытается загрузить oauthlib/common.pyc — обратите внимание, что единственное отличие заключается в том, что brk() перед munmap():

    3416  open("/usr/local/python2.7/lib/python2.7/site-packages/oauthlib/common.pyc", O_RDONLY) = 10
    3416  fstat(10, {st_mode=S_IFREG|0644, st_size=16043, ...}) = 0
    3416  mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5791f2c000
    3416  read(10, "\3\363\r\n}\321\322Tc\0\0\0\0\0\0\0\0\5\0\0\0@@\2\0sd\2\0\0d\0"..., 4096) = 4096
    3416  fstat(10, {st_mode=S_IFREG|0644, st_size=16043, ...}) = 0
    3416  read(10, "\0\0\0C@\2\0s\330\0\0\0t\0\0|\0\0t\1\0\203\2\0s\36\0t\0\0|\0"..., 8192) = 8192
    3416  read(10, "thon2.7/site-packages/oauthlib/c"..., 4096) = 3755
    3416  read(10, "", 4096)                = 0
    3416  brk(0x372f000)                    = 0x372f000
    3416  close(10)                         = 0
    3416  munmap(0x7f5791f2c000, 4096)      = 0
    3416  close(9)                          = 0

Какая информация может помочь мне обвинить параметры монтирования /tmp?


person curious_george    schedule 05.02.2015    source источник
comment
strace diff, вероятно, бесполезен; скорее, получите отладочную сборку python (легко в Ubuntu, но она должна быть общесистемной, а не virtualenv) и попытайтесь выяснить, какое выделенное пространство для указателя оказывается недействительным. P.S. различия между строкой cmd и init.d/cron.d заключаются в переменных среды — зарегистрируйте env в своем сценарии запуска, и вы сможете имитировать выполнение из строки cmd. Например, $TMP $PATH $LD_LIBRARY_PATH может быть другим.   -  person Dima Tisnek    schedule 06.02.2015
comment
blog.siphos.be/2013/04/securely-handling-libffi вместо этого говорит о /var/tmp...   -  person Dima Tisnek    schedule 06.02.2015
comment
также bugzilla.redhat.com/show_bug.cgi?id=674369, отслеживайте это вниз и открыть ошибку для python вверх по течению   -  person Dima Tisnek    schedule 06.02.2015
comment
Является ли ваше приложение чистым python или вы вызываете код, написанный на C?   -  person Mark Plotnick    schedule 06.02.2015
comment
@MarkPlotnick - это чистый Python. Я считаю, что интерпретатор Python иногда вызывает код C   -  person curious_george    schedule 06.02.2015
comment
@qarma: Спасибо за ссылку. Это было очень информативно. Действительно, установив в скрипте каталог HOME, я смог решить проблему другим способом. Это была проблема LibFFI.   -  person curious_george    schedule 07.02.2015
comment
Спасибо @qarma за ваши полезные комментарии. Я все еще отслеживаю его, но предварительно есть еще два возможных способа определить источник: 1) Как указано в сообщении в блоге, используйте SELinux для сбора дополнительной информации и создания контрольного сообщения. Декодируйте шестнадцатеричный путь в этом сообщении в реальный путь, который будет указывать на файл libffi как на виновника, или, 2) В strace найдите вызовы mmap(), которые привели к -1 EPERM (Операция не разрешена) и никогда не были успешными. . Эти вызовы ссылаются на файлы libffi. Это может помочь в отладке проблемы.   -  person curious_george    schedule 09.02.2015


Ответы (1)


Для тех, у кого была бы та же проблема, что и у меня, и найти эту страницу: Мой сервер CherryPy server.py работал нормально в моей системе Win10 на python3.8, но произошел сбой сегментации в моей системе Linux с python3.6.1. Переход на python3.8 в Linux решил мою проблему.

person Ádám Koczka    schedule 27.02.2020