c - How to send and receive messages from function other than registered callback function in Netlink socket? -
in following kernel module, hooked syscall sys_open, , trying send filename process in userspace using netlink socket, in response process return msg, , according msg, kernel module 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) /* not taint 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 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 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 user\n"); } //===============netlink================= unsigned long **find_sys_call_table() { unsigned long ptr; unsigned long *p; (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 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 & response 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 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 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 memory rw (%d) @ addr %16lx\n", ret, page_align(addr) - page_size); } else { printk(kern_debug "3 pages set 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' callback function sends , receives msgs process how can send msg (i.e. filename) function 'my_sys_open' process in user space? , how wait 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 time ;)
- how can send msg (i.e. filename) function 'my_sys_open' process in user space?
user-space program should create socket af_netlink
, address of socket used send message it. detailed info read man netlink
.
- and how wait response?
you can use standard mechanism make my_sys_open
waiting responce event in hello_nl_recv_msg
, e.g. wait_event. simplified code:
/* * whether responce recieved. * * process concurrent open's should map, * e.g., struct task_struct -> bool. */ int have_responce = 0; declare_wait_queue_head(responce_waitqueue); // waitqueue wait responce. static void hello_nl_recv_msg(struct sk_buff *skb) { ... if(<detect responce 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 received .... }
Comments
Post a Comment