gpt4 book ai didi

c - 如何从 Netlink 套接字中注册的回调函数以外的函数发送和接收消息?

转载 作者:太空宇宙 更新时间:2023-11-04 03:37:12 30 4
gpt4 key购买 nike

在接下来的内核模块中,我 hook 了系统调用 sys_open,现在尝试使用 Netlink socket 将文件名发送到用户空间中的进程,响应进程将返回一个 msg,然后根据 msg,内核模块将继续进行。

源代码:foo.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#include <linux/syscalls.h>
#include <linux/delay.h> // loops_per_jiffy

//===============netlink=================
#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>

#define NETLINK_USER 31
struct sock *nl_sk = NULL;
//===============netlink=================

#define CR0_WP 0x00010000 // Write Protect Bit (CR0:16)

/* Just so we do not taint the kernel */
MODULE_LICENSE("GPL");

void **syscall_table;
unsigned long **find_sys_call_table(void);


long (*orig_sys_open)(const char __user *filename, int flags, int mode);
//===============netlink=================
static void hello_nl_recv_msg(struct sk_buff *skb)
{

struct nlmsghdr *nlh;
int pid;
struct sk_buff *skb_out;
int msg_size;
char *msg = "Hello from kernel";
int res;

printk(KERN_INFO "Entering: %s\n", __FUNCTION__);

msg_size = strlen(msg);

nlh = (struct nlmsghdr *)skb->data;
printk(KERN_INFO "Netlink received msg payload: %s\n", (char *)nlmsg_data(nlh));
pid = nlh->nlmsg_pid; /*pid of sending process */

skb_out = nlmsg_new(msg_size, 0);

if (!skb_out)
{

printk(KERN_ERR "Failed to allocate new skb\n");
return;

}
nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
strncpy(nlmsg_data(nlh), msg, msg_size);
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res < 0)
printk(KERN_INFO "Error while sending bak to user\n");
}
//===============netlink=================

unsigned long **find_sys_call_table()
{

unsigned long ptr;
unsigned long *p;

for (ptr = (unsigned long)sys_close;
ptr < (unsigned long)&loops_per_jiffy;
ptr += sizeof(void *))
{

p = (unsigned long *)ptr;

if (p[__NR_close] == (unsigned long)sys_close)
{
printk(KERN_DEBUG "Found the sys_call_table!!!\n");
return (unsigned long **)p;
}
}

return NULL;
}

long my_sys_open(const char __user *filename, int flags, int mode)
{
long ret;

//Send filename & get response from user space app

if(/*user_space_response ==*/ 0)
{
/*Other processing*/
}
ret = orig_sys_open(filename, flags, mode);
printk(KERN_DEBUG "file %s has been opened with mode %d\n", filename, mode);

return ret;
}

static int __init syscall_init(void)
{
int ret;
unsigned long addr;
unsigned long cr0;

syscall_table = (void **)find_sys_call_table();

if (!syscall_table)
{
printk(KERN_DEBUG "Cannot find the system call address\n");
return -1;
}

//===============netlink=================
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);
if (!nl_sk)
{
printk(KERN_DEBUG "Error creating socket.\n");
return -1;
}
//===============netlink=================

cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);

addr = (unsigned long)syscall_table;
ret = set_memory_rw(PAGE_ALIGN(addr) - PAGE_SIZE, 3);
if(ret)
{
printk(KERN_DEBUG "Cannot set the memory to rw (%d) at addr %16lX\n", ret, PAGE_ALIGN(addr) - PAGE_SIZE);
}
else
{
printk(KERN_DEBUG "3 pages set to rw");
}

orig_sys_open = syscall_table[__NR_open];
syscall_table[__NR_open] = my_sys_open;

write_cr0(cr0);

return 0;
}

static void __exit syscall_release(void)
{
unsigned long cr0;

cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);

syscall_table[__NR_open] = orig_sys_open;

write_cr0(cr0);
netlink_kernel_release(nl_sk);
}

module_init(syscall_init);
module_exit(syscall_release);

作为回调函数的函数“hello_nl_recv_msg”向进程发送和接收消息,但是如何从函数“my_sys_open”发送消息(即文件名)以在用户空间中处理?以及如何等待响应?

生成文件:

obj-m += foo.o

all:
make -C /usr/src/linux-headers-3.2.0-23-generic/ M=$(PWD) modules

clean:
make -C /usr/src/linux-headers-3.2.0-23-generic/ M=$(PWD) clean

感谢您的宝贵时间 ;)

最佳答案

  1. How can I send msg (i.e. filename) from function 'my_sys_open' to process in user space?

用户空间程序应该创建套接字AF_NETLINK,这个套接字的地址将用于向它发送消息。有关详细信息,请阅读 man netlink

  1. and how to wait for response?

您可以使用任何标准机制让 my_sys_open 等待 hello_nl_recv_msg 中的响应事件,例如wait_event .简化代码:

/* 
* Whether responce is recieved.
*
* For process concurrent open's this should be map,
* e.g., struct task_struct -> bool.
*/
int have_responce = 0;
DECLARE_WAIT_QUEUE_HEAD(responce_waitqueue); // Waitqueue for wait responce.

static void hello_nl_recv_msg(struct sk_buff *skb)
{
...
if(<detect responce from user program>)
{
have_responce = 1;
wake_up_all(responce_waitqueue);
}
...
}

long my_sys_open(const char __user *filename, int flags, int mode)
{
struct sk_buff *skb_out;
...
have_responce = 0; // clear responce flag
nlmsg_unicast(nl_sk, skb_out, <stored_user_pid>);// send message
wait_event(responce_waitqueue, have_responce); //wait until responce is received
....
}

关于c - 如何从 Netlink 套接字中注册的回调函数以外的函数发送和接收消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31653257/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com