⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ksh_svr.c

📁 linux内核调试小工具.可以读写指定地址上的数据
💻 C
字号:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/net.h>
#include <linux/version.h>
#include <net/sock.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/list.h>

#include "ksh_svr.h"

MODULE_AUTHOR("Dupree");


#ifdef FUNCTRACE
#define ENTERFUNCTION   printk("Enter: %s, line %i\n", __func__,__LINE__)
#define LEAVEFUNCTION   printk("Leave: %s, line %i\n", __func__,__LINE__)
#else
#define ENTERFUNCTION   do {} while (0)
#define LEAVEFUNCTION   do {} while (0)
#endif

/*macro*/
#define MAX_SESSION_NUM 8
#define MAX_SOCKET_READ_LEN 1000
#define MAX_SOCKET_WRITE_LEN 8000

struct session_info{
    struct list_head list;
    pid_t session_pid;
    struct socket* sock;
    struct completion thread_exit; 
    wait_queue_head_t wait_queue;
};

/*var*/
static LIST_HEAD(session_list_head);
unsigned int session_sum = 0;
char *sym = "/proc/ksyms";
MODULE_PARM(sym, "s");

struct file *sym_file = NULL;
static DECLARE_MUTEX(exec_sem);

/*func*/
static struct socket *listen_and_bind(const int port);
static struct socket *ksh_svr_accept(struct socket *sock);
void thread_init(struct session_info* psession);
static void read_data(struct socket *sock);
static int new_session(void *arg);
static void send_data(struct socket *sock, char *buffer, int len);

extern int execute_cmd(char *usr_input, char *output);

#if 1 //def DEBUG
void dump_data(char *addr, int length);
#endif



#if 1 //def DEBUG
void dump_data(char *addr, int length)
{
    int i;
    printk("length = %d", length);
    for(i = 0; i < length; i++)
    {
        if((i%16)==0)
        {
            printk("\n%08x: ", (unsigned int)&addr[i]);
        }else if((i%8)==0)
        {
            printk("- ");
        }
        printk("%2.2x ", (unsigned char)addr[i]);
    }
    printk("\n");
}
#endif


void thread_init(struct session_info* psession)
{
    daemonize();
    reparent_to_init();
    spin_lock_irq(&current->sigmask_lock);
    sigfillset(&current->blocked);
    siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)|sigmask(SIGTERM));
    recalc_sigpending(current);
    spin_unlock_irq(&current->sigmask_lock);
    
    init_completion(&psession->thread_exit);
    init_waitqueue_head(&psession->wait_queue);
}

/*
 * read data from socket, reference ip_vs_receive()
 */
 
static void read_data(struct socket *sock)
{
    struct msghdr msg;
    struct iovec iov;
    mm_segment_t oldfs;
    int len = 0, output_len = 0;

    char *buffer = (char *)kmalloc(MAX_SOCKET_READ_LEN, GFP_KERNEL);
    
    if(buffer == NULL){
        printk("malloc memory failed\n");
        return;
    }
    
    memset(buffer, 0, MAX_SOCKET_READ_LEN);
	msg.msg_name = 0;
	msg.msg_namelen = 0;
	msg.msg_iov	= &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;
	
	msg.msg_iov->iov_base = buffer;
	msg.msg_iov->iov_len  = (size_t)MAX_SOCKET_READ_LEN;
	
	
	oldfs = get_fs(); 
    set_fs(KERNEL_DS);
    /*len = sock_recvmsg(sock, &msg, 4000, MSG_PEEK);*/
	len = sock_recvmsg(sock, &msg, MAX_SOCKET_READ_LEN, 0);

    if(len >0){
        
	    //dump_data(buffer, len);

	    char *output = (char *)kmalloc(MAX_SOCKET_WRITE_LEN, GFP_KERNEL);
        
        if(output == NULL){
        	set_fs(oldfs);
        	kfree(buffer);            
            return;
        }
        memset(output, 0, MAX_SOCKET_WRITE_LEN);
        /*execute_cmd会访问一些全局变量*/
        down_interruptible(&exec_sem);
        output_len = execute_cmd(buffer, output);
        //printk("output_len = %d\n", output_len);
        //printk("%s\n", output);
        send_data(sock, output, output_len);
        
        kfree(output);
        up(&exec_sem);
    }
    
	set_fs(oldfs);
	kfree(buffer);
}

static void send_data(struct socket *sock, char *buffer, int len)
{
    struct msghdr msg;
    struct iovec iov;
    mm_segment_t oldfs;

    if(buffer == NULL){
        printk("buffer == NULL\n");
        return;
    }
    
    
	msg.msg_name = 0;
	msg.msg_namelen = 0;
	msg.msg_iov	= &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;
	
	msg.msg_iov->iov_base = buffer;
	msg.msg_iov->iov_len  = len;
	
	
	oldfs = get_fs(); 
    set_fs(KERNEL_DS);
    
    len = sock_sendmsg(sock, &msg, len);
    //printk("server say send msg len = %d\n", len);
	set_fs(oldfs);
}

static int new_session(void *arg)
{
    struct session_info *psession = (struct session_info *)arg;
    struct socket *sock = psession->sock;
    struct sock *sk = sock->sk;
    
    ENTERFUNCTION;
    sprintf(current->comm, "ksh_session%d", current->pid);
    thread_init(psession);
    
    while(1){
        /*If this is no data, then sleep*/
        if(!skb_queue_empty(&sk->receive_queue)){
            read_data(psession->sock);
        }

        interruptible_sleep_on_timeout(&psession->wait_queue, 1*HZ);

        if (sock->sk->state == TCP_CLOSE){
            break;
		} 
        
        if(signal_pending(current)){
            break;
        }
    }

    LEAVEFUNCTION;
    
    session_sum--;
    sock_release(sock);
    
    list_del(&psession->list);
    complete_and_exit(&psession->thread_exit, 0);     
    kfree(psession);

    printk("%s exit\n", current->comm);
   
    return 0;       
}

static int main_daemon(void *arg)
{
    struct socket *sock = NULL;
    struct socket *new_sock = NULL;
    struct session_info *psession = (struct session_info *)arg;
    int err = 0;
    
    sprintf(current->comm, "ksh_daemon");
    thread_init(psession); 
    
    sock = listen_and_bind(KSH_SVR_PORT);
    if(sock == NULL){
        printk("listen on port %d failed\n", KSH_SVR_PORT);
        goto failed;
    }
       
    while(1){
        
        new_sock = ksh_svr_accept(sock);
        
        /*go to sleep*/
        if(new_sock == NULL){
            interruptible_sleep_on_timeout(&psession->wait_queue, 1*HZ);
        }
        
        if(signal_pending(current)){
            printk("thread %s receive a signal\n", current->comm);
            break;
        }

        if(new_sock != NULL){
            
            if(session_sum < MAX_SESSION_NUM){
                struct session_info *psi = (struct session_info *)kmalloc(sizeof(struct session_info), GFP_KERNEL);

                if(psi == NULL){
                    printk("[%s]kmalloc memory for session %d failed\n", __func__, session_sum);
                    break;
                }
                
                memset(psi, 0, sizeof(struct session_info));
                psi->sock = new_sock;
                list_add(&psi->list, &session_list_head);
                psi->session_pid = kernel_thread(new_session, psi, CLONE_FS | CLONE_FILES);

                printk("Someone connected, spawn new task[%d]\n", psi->session_pid);
                session_sum++;
            }else{
                sock_release(new_sock);
                printk("Too many connects\n");
            }
        }

    }

    /*close socket*/
    err = sock->ops->shutdown(sock, 2);
    if(err){
        printk(KERN_ERR"Close sock failed!!\n");
    }
    sock_release(sock);

failed:
    
    list_del(&psession->list);
    complete_and_exit(&psession->thread_exit, 0);
    kfree(psession);  
    return 0;
}

static struct socket *ksh_svr_accept(struct socket *sock)
{
    int error = 0;
    struct socket *new_sock = NULL;

#if 0 /*直接使用阻塞的accept*/
    if(sock->sk->tp_pinfo.af_tcp.accept_queue == NULL){
        return NULL;
    }
#endif

    new_sock = sock_alloc();
    if (new_sock == NULL){
        printk("sock_alloc failed!\n");
        return NULL;
    }
    
    new_sock->type = sock->type;
    new_sock->ops = sock->ops;
    
    /*	00 - read-only
     *	01 - write-only
     *	10 - read-write
     */
    /*确保accept会被阻塞 O_RDONLY , NOT O_NONBLOCK*/
    error = sock->ops->accept(sock, new_sock, O_RDONLY);  /*read only*/
    
    if(error == 0){
        return new_sock;
    }else{
        sock_release(new_sock);
        return NULL;
    }    
}

static struct socket *listen_and_bind(const int port)
{
	struct socket *sock;
	struct sockaddr_in sin;
	int error;
		
	error = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
	if (error < 0)
    { 
	     printk(KERN_ERR "create ksh svr socket error!!\n");
	     return NULL;
    }
	
	sin.sin_family	     = AF_INET;
	sin.sin_addr.s_addr  = INADDR_ANY;
	sin.sin_port         = htons((unsigned short)port);
	
	error = sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
	if (error < 0)
	{
		printk(KERN_ERR " Error binding socket, using port %i. error = %d\n", port, -error);
		return NULL;	
	}

	sock->sk->reuse   = 1;

	error = sock->ops->listen(sock, MAX_SESSION_NUM);	
	if (error != 0)
	{
		printk(KERN_ERR "Error listening on socket \n");
		return NULL;
    }
    printk("listen and bind to port %d successful\n", port);
	return sock;
            
}


static int __init ksh_dev_init(void)
{
    struct session_info *psi = NULL;

    sym_file = filp_open(sym, O_RDONLY, 0);
    if(IS_ERR(sym_file)){
        printk("open symbol file:%s failed\n", sym);
        return -1;
    }
    
    psi = (struct session_info *)kmalloc(sizeof(struct session_info), GFP_KERNEL);
    if(psi == NULL){
        printk("[%s]kmalloc memory failed\n", __func__);
        return -1;
    }
    list_add(&psi->list, &session_list_head);
    psi->session_pid = kernel_thread(main_daemon, psi, CLONE_FS | CLONE_FILES);

    printk("symbol file = %s\n", sym);
    return 0;
}

static void __exit ksh_dev_exit(void)
{
    int ret;
    struct list_head *p, *n;
    struct session_info *psi;
    
    /*kill all session*/
    list_for_each_safe(p, n, &session_list_head){
    
        psi = list_entry(p, struct session_info, list);
        if(psi->session_pid > 0){
            ret = kill_proc(psi->session_pid, SIGTERM, 1);
            if(ret){
                printk("unable to send signal to pid %d\n", psi->session_pid);
            }else{
                wait_for_completion(&psi->thread_exit);
                /*printk("sesion pid[%d] exit\n", psi->session_pid);*/
            }
        }       
    }
    printk("ksh module removed successful\n");
    
    filp_close(sym_file, NULL);
    return;
}

module_init(ksh_dev_init);
module_exit(ksh_dev_exit); 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -