clinuxmodulelinux-kernelnetfilter

LKM Running call_usermodehelper from netfilter hook


I am trying to execute a linux terminal command from a linux kernel module in linux 5.10 by using call_usermodehelper, which is called from within a netfilter hook, but since from what i know it's running in softirq context i just can't seem to be able to execute it either way. Using 'UMH_WAIT_EXEC' i get the scheduling while atomic: nc/16886/0x00000101 upon sending the udp packet that i am watching for with the filter and if i use 'UMH_NO_WAIT' i get a null reference. The code looks something like this:

static unsigned int hfunc(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{          

        // --snipp--
    
        if (ntohs(udph->dest) == 1337) {
            
             char *argv[4];
             char *envp[4];
             argv[0] = "/bin/bash";
             argv[1] = "-c";
             argv[2] = "/bin/ls";
             argv[3] = NULL;

             envp[0] = "HOME=/";
             envp[1] = "TERM=linux";
             envp[2] = "PATH=/sbin:/usr/sbin:/bin:/usr/bin";
             envp[3] = NULL;

             call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
   }
}

How can i run that program from the softirq context of the netfilter hook?


Solution

  • I fixed this by using scheduling.

    static struct nf_hook_ops *nfho = NULL;
    
    struct work_arg_struct {
        struct work_struct work;
        char *data;
    };
    
    static struct work_arg_struct my_work;
    
    void bash_work_handler(struct work_struct *work){
    
        struct work_arg_struct *work_arg;
        work_arg = container_of(work, struct work_arg_struct, work);
        // --snip--
    
        call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
        return;
    }
    static unsigned int hfunc(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
    {   
      if (ntohs(udph->dest) == 1337) {
            // setup arguments
            schedule_work(&my_work.work);
                 
       }
    }
    
    --snip--
    
    static int __init module_init(void)
    {
     //--snip--
     INIT_WORK(&my_work.work, bash_work_handler);
    }