Как использовать функцию из пользовательского модуля ядра?

Я успешно реализовал пользовательский системный вызов getpuid() и теперь мне нужно написать собственный динамически загружаемый модуль для экспорта функции, которая имеет точно такую ​​же функциональность, что и пользовательский системный вызов getpeuid() , Этот системный вызов используется для получения euid родительского процесса вызывающего процесса. И сегмент пользовательского модуля:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/printk.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/cred.h>

static int *getpeuid(pid_t pid, uid_t *uid)
{
    // Code to get the parent process euid
    ......;
}

EXPORT_SYMBOL(getpeuid);

/* This function is called when the module is loaded. */
int getpeuid_init(void)
{
       printk(KERN_INFO "getpeuid() loaded\n");

       return 0;
}

/* This function is called when the module is removed. */
void getpeuid_exit(void) {
    printk(KERN_INFO "Removing getpeuid()\n");
}

/* Macros for registering module entry and exit points. */
module_init( getpeuid_init );
module_exit( getpeuid_exit );

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Return parent euid.");
MODULE_AUTHOR("CGG");

Я успешно скомпилировал этот пользовательский модуль и вставил модуль в ядро. Затем я написал тест для проверки функциональности функции, экспортированной из загружаемого модуля ядра:

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    pid_t pid;
    uid_t *uid;

    uid = (uid_t *)malloc(sizeof(uid_t));

    pid = getppid();
    int retval = getpeuid(pid, uid);

    if( retval < 0 )
    {
        perror("My system call returned with an error code.");
    }

    printf("My syscall's parameters: %ld \n", pid);
    printf("My system call returned %d.\n", retval);
    printf("Current values:  uid=%ld \n", *uid);
    return 0;
}

Но когда я компилирую тестовый скрипт, он выдает мне следующую ошибку:

/tmp/ccV8WTx0.o: В функции 'main': hw5-test.c:(.text+0x33): неопределенная ссылка на `supermom' collect2: ошибка: ld вернул 1 состояние выхода

Я проверил доступные символы в системе, используя cat /proc/kallsyms и символ, который я экспортировал, находится там:

fa0eb000 T getpeuid [getpeuid]

Я просто не знаю, как я должен использовать свою пользовательскую функцию, так как у меня нет заголовочного файла для моего пользовательского модуля, который будет включен в мой тестовый скрипт. Даже если мне нужно написать файл заголовка, я не знаю, как написать файл заголовка для пользовательского модуля ядра.

Может ли кто-нибудь помочь мне здесь?

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

РЕДАКТИРОВАТЬ:

Мне разрешено использовать только динамически загружаемый модуль ядра для имитации функциональности системного вызова.

РЕДАКТИРОВАТЬ:

Мне не разрешено изменять таблицу системных вызовов в коде инициализации модуля.

Я получил следующую ссылку от других в качестве подсказки:

https://www.linux.com/learn/linux-career-center/31161-the-kernel-newbie-corner-kernel-symbols-whats-available-to-your-module-what-isnt

2 ответа

Решение

Используйте sysfs

Ознакомьтесь со списком различных интерфейсов ядра Linux <->.

Чтобы пользовательское пространство могло взаимодействовать с загружаемым модулем ядра, рассмотрите возможность использования sysfs.

Чтобы добавить поддержку sysfs в загружаемый модуль, ознакомьтесь с основами записи sys-fs.

Хорошее руководство с лучшими практиками создания записей sysfs поможет вам начать правильный путь.

Тест пользовательского пространства изменится с

int retval = getpeuid(pid, uid);

к чему-то, что использует open, write() а также read()
взаимодействовать с записью sysfs как обычный файл.
(Почему файл? Потому что все это файл в UNIX.)

Вы можете еще больше упростить это до использования shell-скрипта, который использует echo / cat Команды для передачи / сбора данных из загружаемого модуля ядра через запись sysfs.


Альтернативный вариант: красивый / безобразный хак

Отказ от ответственности: я согласен, что попытка использовать системные вызовы в загружаемом модуле ядра не является ни правильным решением, ни гарантированно всегда работающим. Я знаю, что я делаю.
(Наведите указатель мыши на следующий блок, ТОЛЬКО если вы согласны с вышеуказанным)

Извлеките этот ответ и связанный с ним код, который описывает потенциальный "взлом", позволяющий реализовать пользовательские системные вызовы в загружаемых модулях в любых неиспользуемых местах в текущей таблице системных вызовов ядра.

Также внимательно просмотрите несколько ответов / комментариев к этому вопросу. Они имеют дело с преодолением проблемы невозможности изменить таблицу системных вызовов. В одном из комментариев также подчеркивается тот факт, что гипервизоры, реализующие свои собственные расширения, вряд ли будут затронуты этим "эксплойтом", поскольку они обеспечивают лучшую защиту таблицы системных вызовов.

Обратите внимание, что такие нестандартные интерфейсы могут не всегда работать, и даже если они работают, они могут перестать работать в любое время. Придерживайтесь стандартных интерфейсов для надежности.

EXPORT_SYMBOL экспортирует символ в ядре, чтобы другие модули ядра могли использовать его. Это не сделает его доступным для пользовательских программ. Добавление нового системного вызова не представляется возможным через модуль ядра: https://unix.stackexchange.com/questions/47701/adding-a-new-system-call-to-linux-3-2-x-with-a-loadable-kernel-module

Другие вопросы по тегам