How to send and receive messages from function other than registered callback function in Netlink socket?

混江龙づ霸主 提交于 2021-02-18 19:07:13

问题


In following kernel module, I hooked syscall sys_open, and now trying to send filename to process in userspace using Netlink socket, in response process will return a msg, and then according to msg, the kernel module will proceed further.

source code: 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);

The function 'hello_nl_recv_msg' which is a callback function sends and receives msgs to the process but How can I send msg (i.e. filename) from function 'my_sys_open' to process in user space? and how to wait for response?

Makefile :

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

Thanks for your time ;)


回答1:


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

User-space program should create socket AF_NETLINK, address of this socket will be used to send message to it. For detailed info read man netlink.

  1. and how to wait for response?

You can use any standard mechanism for make my_sys_open waiting responce event in hello_nl_recv_msg, e.g. wait_event. Simplified code:

/* 
 * 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
    ....
}


来源:https://stackoverflow.com/questions/31653257/how-to-send-and-receive-messages-from-function-other-than-registered-callback-fu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!