如何使用自定义内核模块中的函数?

How to use the function from a custom kernel module?

我已经成功实现了一个自定义系统调用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: In function 'main': hw5-test.c:(.text+0x33): undefined reference to `supermom' collect2: error: ld returned 1 exit status

我使用cat /proc/kallsyms检查了系统中可用的符号,我导出的符号在那里:

fa0eb000 T getpeuid [getpeuid]

我只是不知道我应该如何使用我的自定义函数,因为我没有要包含在我的测试脚本中的自定义模块的头文件。就算需要写头文件,也不知道怎么写自定义内核模块的头文件

有人可以帮我吗?

提前致谢!

编辑:

我只允许使用可动态加载的内核模块来模拟系统调用的功能。

编辑:

不允许修改模块初始化代码中的系统调用table

我从别人那里得到以下link提示:

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

EXPORT_SYMBOL 在内核中导出符号,以便其他内核模块可以使用它。它不会使其对用户空间程序可用。 似乎无法通过内核模块添加新的系统调用: https://unix.stackexchange.com/questions/47701/adding-a-new-system-call-to-linux-3-2-x-with-a-loadable-kernel-module

使用 sysfs

查看 list of various Linux kernel <--> Userspace interfaces

To allow userspace to interact with a loadable kernel module, consider using sysfs.

要在您的可加载模块中添加对 sysfs 的支持,请查看 a sys-fs entry 的基础知识。

一个很好的 best practices of creating sysfs entries 指南应该可以让您以正确的方式开始。

用户空间测试将从

int retval = getpeuid(pid, uid);

使用 openwrite()read()
的东西 像普通文件一样与 sysfs 条目交互。
( 为什么归档?因为 everything is a file on UNIX。)

您可以进一步将其简化为使用 shell-脚本,该脚本使用 echo/cat 命令通过 sysfs 条目从可加载内核模块 pass/gather 数据.


替代选项:A beautiful/ugly Hack

免责声明: 我同意尝试在可加载内核模块中使用系统调用既不是合适的解决方案,也不能保证始终有效。我知道我在做什么。
(将鼠标悬停在以下区块上, 如果您同意以上内容)

查看这个 answer and related code,它描述了一个潜在的“hack”,允许在当前系统调用中任何未使用的位置的可加载模块中实现自定义系统调用 table的内核。

还要仔细过一遍answers/comments到这个question。他们解决了无法修改系统调用 table 的问题。其中一条评论还强调了这样一个事实,即实现自己扩展的管理程序不太可能受到这种“利用”的影响,因为它们可以更好地保护系统调用 table。

请注意,此类非标准接口可能并不总是有效,即使有效,也可能随时停止工作。坚持使用标准接口以获得可靠性。