Внедренный системный вызов mprotect в отслеживаемый процесс завершается с ошибкой EFAULT

Я ввожу вызов mprotect в отслеживаемый процесс:

static int inject_mprotect(pid_t child, void *addr, size_t len, int prot)
{
    // Machine code:
    //  int $0x80       (system call)
    //  int3            (trap)
    char code[] = {0xcd,0x80,0xcc,0};
    char orig_code[3];
    struct user_regs_struct regs;
    struct user_regs_struct orig_regs;

    // Take a copy of current state
    __check_ptrace(PTRACE_GETREGS, child, NULL, &orig_regs);
    getdata(child, INSTRUCTION_POINTER(regs), orig_code, 3);

    // Inject the code, update registers
    putdata(child, INSTRUCTION_POINTER(regs), code, 3);
    __check_ptrace(PTRACE_GETREGS, child, NULL, &regs);
    XAX_REGISTER(regs) = MPROTECT_SYSCALL;
    MPROTECT_ARG_START(regs) = (unsigned long)addr;
    MPROTECT_ARG_LEN(regs) = len;
    MPROTECT_ARG_PROT(regs) = prot;   
    __check_ptrace(PTRACE_SETREGS, child, NULL, &regs);

    // Snip

Однако вызов терпит неудачу, возвращая -14 (EFAULT). Я просмотрел исходный код mprotect (ядро 3.13) и не понимаю, почему мой системный вызов возвращает это.

Если я отследю свой введенный вызов и распечатаю регистры, я увижу следующее:

SIGTRAP: eip: 0x34646ef8d4, syscall 10, rc = -38
PARENT 10 MPROTECT(start: 0x00007f45b9611000, len: 4096, prot: 0)
EIP: 0x00000034646ef8d4 AX: 0xffffffffffffffda  BX: 0x0000000000000005  CX: 0xffffffffffffffff
 DX: 0x0000000000000000 DI: 0x00007f45b9611000  BP: 0x00007fffcb93bc20  SI: 0x0000000000001000
 R8: 0x0000000000000000 R9: 0x0000000000000000  R10: 0x0000000000000000
SIGTRAP: eip: 0x34646ef8d4, syscall 10, rc = -14 Bad address (trap after system call exit)

Чтобы проверить формат системного вызова, я добавил вызов mprotect дочернему элементу и выгрузил его аргументы и регистры:

SIGTRAP: eip: 0x34646ef927, syscall 10, rc = -38
CHILD  10 MPROTECT(start: 0x00007f45b9611000, len: 4096, prot: 0)
EIP: 0x00000034646ef927 AX: 0xffffffffffffffda  BX: 0x0000000000000005  CX: 0xffffffffffffffff
 DX: 0x0000000000000000 DI: 0x00007f45b9611000  BP: 0x00007fffcb93bc20  SI: 0x0000000000001000
 R8: 0x000000000000004e R9: 0x746f72706d206c6c  R10: 0x00007fffcb93b9a0
SIGTRAP (child return): eip: 0x34646ef927, syscall 10, rc = 0

Звонок от ребенка проходит успешно. Итак, учитывая, что я делаю тот же системный вызов (10) с теми же аргументами, почему введенный вызов завершается ошибкой с EFAULT, в то время как вызов от дочернего элемента выполняется успешно?

Единственная разница между вызовами — некоторый мусор в regs.r8, regs.r9 и regs.r10, однако основанный на эта таблица системных вызовов на X86_64 Я не думаю, что содержимое этих регистров повлияет на системный вызов.


person Chiggs    schedule 31.05.2014    source источник
comment
Просто дикое предположение: может быть, это связано с этим вопросом? (Любопытно, потому что ваша ссылка говорит, что системный вызов 10 — это 64-битный mprotect, но int 0x80 — это 32-битный синтаксис)   -  person Phillip    schedule 02.06.2014
comment
@Phillip спасибо, это звучит очень многообещающе - я сосредоточился на том, чтобы сделать сам системный вызов и архитектуру аргументов независимыми, что я не думал о int 0x80 против syscall!   -  person Chiggs    schedule 02.06.2014
comment
@Phillip, ты был прав, потому что я использовал 32-битный системный вызов. Теперь это решено, и я отправил свой рабочий код на github. Можете ли вы опубликовать ответ, чтобы я мог его принять?   -  person Chiggs    schedule 02.06.2014
comment
Отлично, сделано. (И спасибо за ссылку. И проект в целом, и ваша ловушка mmap выглядят довольно интересно.)   -  person Phillip    schedule 03.06.2014


Ответы (1)


Проблема связана с этим вопросом: i386 и x86_64 используют разные вызовы соглашения для системных вызовов. В вашем примере кода используется int 0x80, вариант i386, но syscall_number = 10, 64-битный номер системного вызова для mprotect. В 32-разрядных средах системный вызов 10 ядер соответствует unlink согласно этот список, который может возвращать EFAULT (Bad address).

На 64-разрядных платформах проблему решает последовательное использование 32-разрядного или 64-разрядного варианта.

person Phillip    schedule 03.06.2014