Как передать параметры системному вызову Linux? - PullRequest
0 голосов
/ 12 декабря 2018

Я студент колледжа, изучающий ОС.

Я пытаюсь добавить свой системный вызов в ядре Linux, и что-то идет не так.

Моя среда описана ниже:

  • Ядро Linux v.4.19.1
  • 64-разрядная версия Ubuntu LTS 18.04.1 с процессором Intel Core i5-4210M в Oracle VirtualBox 5.2.18
  • 64Windows 10 Home 1803 в качестве хоста

Поскольку я работаю на компьютере с архитектурой x86_64, я начал с arch / x86 / entry / syscalls / syscall_64.tbl .В ядре Linux v.4.19.1 последняя запись -

334     common     rseq             __x64_sys_rseq

, поэтому я добавил эти три строки под ней.

335     common     my_syscall_0     sys_my_syscall_0
336     common     my_syscall_1     sys_my_syscall_1
337     common     my_syscall_2     sys_my_syscall_2

Во-вторых, я добавил прототипы функций в include / linux / syscalls.h .

asmlinkage int sys_my_syscall_0(void);
asmlinkage int sys_my_syscall_1(int);
asmlinkage int sys_my_syscall_2(int, int);

В-третьих, я создал новый файл kernel / my_syscall.c и добавил реализации функций.

asmlinkage int sys_my_syscall_0(void)
{
    printk("my_syscall_0\n");
    return 0;
}

asmlinkage int sys_my_syscall_1(int a)
{
    printk("my_syscall_1 : %d\n", a);
    return 0;
}

asmlinkage int sys_my_syscall_0(int a, int b)
{
    printk("my_syscall_2 : %d, %d\n", a, b);
    return b;
}

Затем я добавил my_syscall.o в kernel / Makefile для компиляции kernel / my_syscall.c .

obj-y = fork.o exec_domain.o panic.o \
        cpu.o exit.o softirq.o resource.o \
        sysctl.o sysctl_binary.o capability.o ptrace.o user.o \
        signal.o sys.o umh.o workqueue.o pid.o task_work.o \
        extable.o params.o \
        kthread.o sys_ni.o nsproxy.o \
        notifier.o ksysfs.o cred.o reboot.o \
        async.o range.o smpboot.o ucount.o \
        my_syscall.o

После компиляции с помощью команд make-kpkg и dpkg я создал тестовую программу.

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main()
{
    printf("1 : %d\n", syscall(335));
    printf("2 : %d\n", syscall(336, 1));
    printf("3 : %d\n", syscall(337, 2, 3));
    return 0;
}

Тем не менее, результат странный. dmesg показывает мне некоторые огромные числа, которые вообще не имеют смысла.

# dmesg
...
my_syscall_0
my_syscall_1 : 1111490392
my_syscall_2 : 1111490392, 1111490392

Кажется, что он меняется каждый раз, когда я запускаю программу.

Очевидно, что существует некоторая проблема с передачей параметров.Тем не менее, команда strace показывает мне, что значения передаются хорошо.

# strace ./syscall
...
syscall_0x14F(0x7ffd21866538, 0x7ffd21866548, ....) = 0
...
syscall_0x150(0x1, 0, 0, 0, 0x7f9e1562f3a0, ....) = 0
...
syscall_0x14F(0x2, 0x3, 0x7f9e1562f3a0, ....) = 0
....

Brief

  1. Я упростилсистемные вызовы.

  2. Передача им параметров не работает так, как они должны быть.

  3. Вопрос: Есть ли проблемы в шагах выше, чтобы добавить новый системный вызов?

  4. Вопрос: Есть ли какие-либо проблемы, о которых мне следует знать при передаче параметров в системный вызов?

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Я нашел решение.Как ответил @Ajay Brahmakshatriya, я должен использовать макрос SYSCALL_DEFINEx.А также, я должен изменить arch / x86 / entry / syscalls / syscall_64.tbl .

Вот окончательное резюме.

Как добавить новые системные вызовы

Во-первых, измените arch / x86 / entry / syscalls / syscall_64.tbl : добавьте эти строки ниже.

335     common     my_syscall_0     __x64_sys_my_syscall_0
336     common     my_syscall_1     __x64_sys_my_syscall_1
337     common     my_syscall_2     __x64_sys_my_syscall_2

Во-вторых, измените include / linux / syscalls.h : добавить эти строки ниже.

asmlinkage long sys_my_syscall_0(void);
asmlinkage long sys_my_syscall_1(int);
asmlinkage long sys_my_syscall_2(int, int);

В-третьих, создать новый файл для реализации.В моем случае kernel / my_syscall.c .

#include <linux/syscalls.h>
#include <linux/kernel.h>

SYSCALL_DEFINE0(my_syscall_0)
{
    printk("my_syscall_0\n");
    return 0;
}

SYSCALL_DEFINE1(my_syscall_1, int, a)
{
    printk("my_syscall_1 : %d\n", a);
    return 0;
}

SYSCALL_DEFINE2(my_syscall_2, int, a, int, b)
{
    printk("my_syscall_2 : %d, %d\n", a, b);
    return b;
}

В-четвертых, добавьте созданный файл в Makefile в его каталог.Для моего случая kernel / Makefile .

...
obj-y = fork.o exec_domain.o panic.o \
        cpu.o exit.o softirq.o resource.o \
        sysctl.o sysctl_binary.o capability.o ptrace.o user.o \
        signal.o sys.o umh.o workqueue.o pid.o task_work.o \
        extable.o params.o \
        kthread.o sys_ni.o nsproxy.o \
        notifier.o ksysfs.o cred.o reboot.o \
        async.o range.o smpboot.o ucount.o \
        my_syscall.o
...

Наконец, скомпилируйте и установите ядро.Теперь вы сможете увидеть, как работают новые системные вызовы.

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

int main()
{
    printf("1 : %d\n", syscall(335));
    printf("2 : %d\n", syscall(336, 1));
    printf("3 : %d\n", syscall(337, 2, 3));
    return 0;
}

dmesg показывает, что системные вызовы работают хорошо.

# dmesg
my_syscall_0
my_syscall_1 : 1
my_syscall_2 : 2, 3
0 голосов
/ 12 декабря 2018

Вы должны сообщить системе сборки, что вашему системному вызову требуется 2 аргумента и что они имеют тип int.Это делается для того, чтобы скрипты, являющиеся частью системы сборки, генерировали соответствующие оболочки для приведения аргументов в требуемый вами тип.Вместо того, чтобы определять фактический обработчик, как вы, вы должны использовать -

SYSCALL_DEFINE2(my_syscall_2, int, a, int, b) // Yes, there is a comma between the types and the argument names
{
    printk("my_syscall_2 : %d, %d\n", a, b);
    return b;
}

SYSCALL_DEFINEx определено в linux / include / linux / syscalls.h .

Вы можете посмотреть пример в linux / fs / read_write.c

...