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

时间:2015-04-05 03:24:27

标签: c linux-kernel system-calls kernel-module archlinux

我已经成功实现了自定义系统调用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 个答案:

答案 0 :(得分:2)

使用sysfs

结帐list of various Linux kernel <--> Userspace interfaces

  

要允许用户空间可加载内核模块进行交互,请考虑使用 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条目从可加载内核模块传递/收集数据。


替代选项:美丽/丑陋的哈克

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

  

查看此 answer 以及相关的 code ,其中描述了允许在任何未使用位置的可加载模块中实施自定义系统调用的潜在“黑客”在内核的当前syscall表中。

 另外,请仔细阅读此question的几个答案/评论。他们处理克服无法修改系统调用表的问题。其中一条评论还强调了这样一个事实:实现自己的扩展的虚拟机管理程序不太可能受到这种“漏洞利用”的影响,因为它们可以更好地保护系统调用表。

 请注意,此类非标准接口可能并不总是有效,即使这样,它们也可以随时停止工作。坚持标准接口以确保可靠性。

答案 1 :(得分:1)

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