OP, вероятно, использует ядро / архитектуру, которая использует «оболочки системных вызовов», где таблица системных вызовов содержит функцию-оболочку, которая вызывает настоящую функцию системного вызова (возможно, как встроенный вызов функции). В архитектуре x86_64 используются оболочки syscall начиная с версии ядра 4.17.
Для x86_64 в ядре 4.17 или новее sys_call_table[__NR_open]
указывает на __x64_sys_open
(с прототипом asmlinkage long __x64_sys_open(const struct pt_regs *regs)
), что вызывает static
function __se_sys_open
(с прототипом static long __se_sys_open(const __user *filename, int flags, umode_t mode)
), который вызывает встроенную функцию __do_sys_open
(с прототипом static inline long __do_sys_open(const __user *filename, int flags, umode_t mode)
. Все они будут определены макро вызовом SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
в "fs / open. c" и теле функции, которое следует за вызовом макроса.
SYSCALL_DEFINE3
определен в «include / linux / syscalls.h» и использует макрос SYSCALL_DEFINEx
в том же файле, который использует макрос __SYSCALL_DEFINEx
. Поскольку x86_64 определяет CONFIG_ARCH_HAS_SYSCALL_WRAPPER
, макрос __SYSCALL_DEFINEx
определяется как #include <asm/syscall_wrapper.h>
, который отображается в "arch / x86 / include / asm / syscall_wrapper.h".
Информацию об этом изменении см.
Кажется, мотивация - передать указатель только на pt_regs
, instea d наличие множества значений пространства пользователя в регистрах по цепочке вызовов. (Возможно, чтобы повысить устойчивость к атакам Призраков, сделав гаджеты менее полезными?)
Почему open
все еще работает, хотя оболочка не :
Если OP действительно использует ядро x86_64 4.17 или новее и заменяет запись sys_call_table[__NR_open]
указателем на функцию, которая использует другой прототип и вызывает исходную функцию (на которую указывает old_open
) с теми же параметрами, что объясняет почему не удалось дозвониться до strncpy_from_user(user_msg, filename, sizeof(user_msg))
Хотя объявленный как const char * __user filename
, указатель filename
фактически указывает на исходный struct pt_regs
в пространстве ядра.
При последующем вызове old_open(filename, flags, mode)
первый параметр filename
все еще указывает на исходный struct pt_regs
, поэтому старая функция (которая ожидает один параметр типа struct pt_regs *
) по-прежнему работает, как и ожидалось.
, то есть функция, переданная по ее первому указателю, остается неизменной, несмотря на вызов другого типа.