您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

从内核模块写入eventfd

从内核模块写入eventfd

我终于想出了怎么做。我意识到,系统上的每个打开文件都可以由打开该文件的进程之一的pid以及与该文件相对应的fd标识(在该进程的上下文中)。因此,如果我的内核模块知道pid和fd,则可以查找进程的 ,并从中查找 ,最后使用fd,它可以获取指向eventfd的 的指针。然后,使用最后一个指针,它可以写入eventfd的计数器。

这是我为演示该概念而编写的用户空间程序和内核模块的代码(现已可用):

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>     //DeFinition of uint64_t
#include <sys/eventfd.h>

int efd; //Eventfd file descriptor
uint64_t eftd_ctr;

int retval;     //for select()
fd_set rfds;        //for select()

int s;

int main() {


    //Create eventfd
    efd = eventfd(0,0);
    if (efd == -1){
        printf("\nUnable to create eventfd! Exiting...\n");
        exit(EXIT_FAILURE);
    }

    printf("\nefd=%d pid=%d",efd,getpid());

    //Watch efd
    FD_ZERO(&rfds);
    FD_SET(efd, &rfds);

    printf("\nNow waiting on select()...");
    fflush(stdout);

    retval = select(efd+1, &rfds, NULL, NULL, NULL);

    if (retval == -1){
        printf("\nselect() error. Exiting...");
        exit(EXIT_FAILURE);
    } else if (retval > 0) {
        printf("\nselect() says data is available Now. Exiting...");
        printf("\nreturned from select(), Now executing read()...");
        s = read(efd, &eftd_ctr, sizeof(uint64_t));
        if (s != sizeof(uint64_t)){
            printf("\neventfd read error. Exiting...");
        } else {
            printf("\nReturned from read(), value read = %lld",eftd_ctr);
        }
    } else if (retval == 0) {
        printf("\nselect() says that no data was available");
    }

    printf("\nClosing eventfd. Exiting...");
    close(efd);
    printf("\n");
    exit(EXIT_SUCCESS);
}

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pid.h>
#include <linux/sched.h>
#include <linux/fdtable.h>
#include <linux/rcupdate.h>
#include <linux/eventfd.h>

//Received from userspace. Process ID and eventfd's File descriptor are enough to uniquely identify an eventfd object.
int pid;
int efd;

//Resolved references...
struct task_struct * userspace_task = NULL; //...to userspace program's task struct
struct file * efd_file = NULL;          //...to eventfd's file struct
struct eventfd_ctx * efd_ctx = NULL;        //...and finally to eventfd context

//Increment Counter by 1
static uint64_t plus_one = 1;

int init_module(void) {
    printk(KERN_ALERT "~~~Received from userspace: pid=%d efd=%d\n",pid,efd);

    userspace_task = pid_task(find_vpid(pid), PIDTYPE_PID);
    printk(KERN_ALERT "~~~Resolved pointer to the userspace program's task struct: %p\n",userspace_task);

    printk(KERN_ALERT "~~~Resolved pointer to the userspace program's files struct: %p\n",userspace_task->files);

    rcu_read_lock();
    efd_file = fcheck_files(userspace_task->files, efd);
    rcu_read_unlock();
    printk(KERN_ALERT "~~~Resolved pointer to the userspace program's eventfd's file struct: %p\n",efd_file);


    efd_ctx = eventfd_ctx_fileget(efd_file);
    if (!efd_ctx) {
        printk(KERN_ALERT "~~~eventfd_ctx_fileget() Jhol, Bye.\n");
        return -1;
    }
    printk(KERN_ALERT "~~~Resolved pointer to the userspace program's eventfd's context: %p\n",efd_ctx);

    eventfd_signal(efd_ctx, plus_one);

    printk(KERN_ALERT "~~~Incremented userspace program's eventfd's counter by 1\n");

    eventfd_ctx_put(efd_ctx);

    return 0;
}


void cleanup_module(void) {
    printk(KERN_ALERT "~~~Module Exiting...\n");
}

MODULE_LICENSE("GPL");
module_param(pid, int, 0);
module_param(efd, int, 0);

要运行此程序,请执行以下步骤:

其他 2022/1/1 18:19:59 有240人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶