Ядро Linux для Android по-прежнему использует те же номера системных вызовов и ABI, что и обычный Linux, не так ли? (Итак, Как получить доступ к системному вызову из пользовательского пространства?) Таким образом, вы сможете использовать обычные методы с номерами вызовов из <asm/unistd.h>
.
Вы можете использовать встроенные функции системного вызова MUSL libc в arch/x86_64/syscall_arch.h
< /а>. У него разные для каждого разного количества аргументов вместо одного большого.
У MUSL есть версии syscall_arch.h
для ARM, AArch64, i386 и x86-64, а также другие поддерживаемые им архитектуры. Он находится под лицензией разрешающей лицензии MIT, так что вы можете просто скопировать эти заголовки.
Например, их ARM-версия имеет
static inline long __syscall3(long n, long a, long b, long c)
{
register long r7 __ASM____R7__ = n; // macro trickery for not clobbering r7 in thumb mode (where it may be the frame pointer)
register long r0 __asm__("r0") = a;
register long r1 __asm__("r1") = b;
register long r2 __asm__("r2") = c;
__asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2));
// FIXME: add a "memory" clobber because pointed-to memory can be an input or output
}
К сожалению, это не совсем безопасно: это не сообщает компилятору, что операнды указателя разыменованы, поэтому он может рассматривать записи в буфер до write()
как мертвые и оптимизировать их!
Это легко исправить: добавьте "memory"
клобер.
IDK, если это было частью мотивации glibc для удаления аналогичных макросов системных вызовов и предоставления только не встроенной функции системного вызова. Или, может быть, они не хотели побуждать людей встраивать ABI системных вызовов в свои программы, чтобы теоретически он мог измениться и стать более эффективным в будущем.
Вы бы использовали его как
#include <asm/unistd.h> // for __NR_write
#include <stdlib.h> // for ssize_t
#include "syscall_arch.h"
// doesn't set errno or force all error returns to -1
// return values from -1 to -4095 are errors, e.g. -EBADF or -EFAULT
__attribte__((noinline)) // hack for inline asm unsafety
ssize_t my_write(int fd, const void *buf, size_t count) {
return __syscall3(__NR_write, fd, (long)buf, count);
}
И, конечно же, эта функция может быть встроена в вызывающую программу, поэтому сохранение/восстановление r7
происходит один раз для всей функции.
my_write:
str r7, [sp, #-4]!
mov r7, #4
@ system-calling convention mostly matches function-calling convention
@ so args are in the right registers already
svc 0
ldr r7, [sp], #4
bx lr
(редактировать): это было бы небезопасно, если бы было встроено в вызывающую программу, где мертвые хранилища могли бы оптимизироваться. Лучшим вариантом грубой силы будет стирание памяти во встроенном ассемблере, или дополнительная работа будет заключаться в добавлении фиктивного операнда памяти для системных вызовов, которые считывают или записывают память пользовательского пространства (см. at&t asm встроенная проблема С++). Или для munmap
, чтобы убедиться, что не сохраняется в освобождаемые страницы проходят мимо него и происходят после того, как память не отображается.
От какой угрозы вы хотите защититься? Обычно на Android ваше приложение работает в отдельной песочнице, и ни один ненадежный агент не может перехватить функции оболочки системного вызова.
person
Peter Cordes
schedule
29.05.2018