10.13 High Sierra OSX - Python mprotect всегда дает сбой при предоставлении разрешения exec с ENOMEM - PullRequest
0 голосов
/ 04 июня 2018

Справочная информация:

Написание подтверждения концепции, которая включает в себя выполнение машинного кода в программе Python.Чтобы сделать это на OSX, мне пришлось использовать ctypes и libc.dylib и следующие вызовы функций:

(с отключенным SIP)

  1. valloc для выделения выровненной памяти
  2. mprotect для предоставления разрешения wrx на выделенную память
  3. memmove для копирования исполняемого кода в выделенную память;бросать;и выполнить ...

Проблема :

Проблема возникает при вызове функции mprotect, где она всегда возвращает -1 в случае сбоя.

Сценарий: (логика почти идентична системе linux, поскольку они оба относятся к семейству posix)

import ctypes

buf = "machine code..."
libc = cytpes.CDLL('libc.dylib')
size = len(buf)
buf_ptr = ctypes.c_char_p(buf)

# allocate aligned memory space
alloc_space = ctypes.c_void_p(ctypes.valloc(size))

# this always evaluates true, and mprotect fails every attempt
if 0 != libc.mprotect(alloc_space, size, 1 |2 |4):
  print "mprotect failed"

ctypes.mmove(alloc_space, buf_ptr, size)

Теперь mmove завершится ошибкой с сообщением об ошибке segfault (b/ c записывает пространство памяти, которое, вероятно, имело только право на чтение), и программа приходит в хаот ...

Проблема в mprotect, этот метод очень хорошо работает в Linux, теперь я вижу, что результатысильно отличаются для Mac OSX

Вопрос:

Есть ли в Mac OSX дополнительные функции безопасности (даже с отключенным SIP), которые ограничивают тип операции mprotect?И если да, то как можно это обойти?

ОБНОВЛЕНИЕ:

Согласно @DietrichEpp, предложенному в комментариях, использование use_errno = True для вызова ctypes.CDLL сгенерировалоERRNO.Это оценивается как errno: 12, Невозможно выделить память.Это errno - значение для ENOMEM на странице руководства mprotect.

Хотя на странице руководства было несколько ENOMEM, я подозреваю, что это последний сценарий: (б / с не было ошибки при вызове valloc)

   ENOMEM Changing the protection of a memory region would result in the
          total number of mappings with distinct attributes (e.g., read
          versus read/write protection) exceeding the allowed maximum.
          (For example, making the protection of a range PROT_READ in
          the middle of a region currently protected as
          PROT_READ|PROT_WRITE would result in three mappings: two
          read/write mappings at each end and a read-only mapping in the
          middle.)

Я подозреваю, что osx имеет особые ограничения и установил максимальные сопоставления для каждого процесса, следовательно, добавив больше разрешений, новое сопоставление того же процесса превысит такой максимальный предел (сколько сопоставлений с привилегиями exec / write на процесс),Если мои предположения были верны, как мы можем обойти это?

1 Ответ

0 голосов
/ 05 июня 2018

Справочные страницы Apple больше не подключены к Интернету, но обратитесь к справочной странице POSIX для mprotect :

Поведение этой функции не определено, если сопоставление не было установленовызов mmap ().

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

Если подумать, это разумное требование.Память, предоставляемая valloc (), управляется распределителем и должна быть позже возвращена распределителю с помощью free (), а mprotect () в некотором смысле обходит спину распределителя и изменяет способ работы памяти.Это не относится к mmap () и munmap (), которые относятся к тому же семейству системных вызовов, что и mprotect ().

...