0

I'm trying to send a string to the kernel module from the user space and the kernel returns back the string reversed. I followed a simple example code and added strrev() function in the kernel code which is defined in the string.h header. But that gives me an error "fatal error: string.h: No such file or directory" and no other error. The user code is same as the sample code from the link. Can anybody explain why this is happening ?

User Code

#include <linux/netlink.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define NETLINK_USER 31

#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;

int main()
{   
    char str[20];

    sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_USER);
    if (sock_fd < 0)
        return -1;

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid(); /* self pid */

    bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));

    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; /* For Linux Kernel */
    dest_addr.nl_groups = 0; /* unicast */

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    
    printf("Enter a string for reversal:- ");
    scanf("%s",str);
    
    strcpy(NLMSG_DATA(nlh),str);

    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    printf("\nSending message to kernel\n");
    sendmsg(sock_fd, &msg, 0);
    printf("Waiting for message from kernel\n");

    /* Read message from kernel */
    recvmsg(sock_fd, &msg, 0);
    printf("Received message payload: %s\n", NLMSG_DATA(nlh));
    close(sock_fd);
    return 0;
}

Kernel Code

#include <linux/module.h>
#include <net/sock.h> 
#include <linux/netlink.h>
#include <linux/skbuff.h> 
#include<string.h>
#define NETLINK_USER 31

struct sock *nl_sk = NULL;

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[20];
    int res;


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

    
    
    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 */
    strcpy(msg,strrev((char *)nlmsg_data(nlh)));
    msg_size = strlen(msg);
        
    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");
}

static int __init hello_init(void)
{

    printk("Entering: %s\n", __FUNCTION__);
    //nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);
    struct netlink_kernel_cfg cfg = {
        .input = hello_nl_recv_msg,
    };

    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
    if (!nl_sk) {
        printk(KERN_ALERT "Error creating socket.\n");
        return -10;
    }

    return 0;
}

static void __exit hello_exit(void)
{

    printk(KERN_INFO "exiting hello module\n");
    netlink_kernel_release(nl_sk);
}

module_init(hello_init); 
module_exit(hello_exit);

MODULE_LICENSE("GPL");

Terminal window

make -C /lib/modules/4.15.0-1096-oem/build/ M=/home/Username/Documents/Task_KtoUcom modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-1096-oem'
  CC [M]  /home/Username/Documents/Task_KtoUcom/kernl.o
/home/Username/Documents/Task_KtoUcom/kernl.c:5:9: fatal error: string.h: No such file or directory
 #include<string.h>
         ^~~~~~~~~~
compilation terminated.
scripts/Makefile.build:337: recipe for target '/home/Username/Documents/Task_KtoUcom/kernl.o' failed
make[2]: *** [/home/Username/Documents/Task_KtoUcom/kernl.o] Error 1
Makefile:1585: recipe for target '_module_/home/Username/Documents/Task_KtoUcom' failed
make[1]: *** [_module_/home/Username/Documents/Task_KtoUcom] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-1096-oem'
Makefile:4: recipe for target 'all' failed
make: *** [all] Error 2
  • Post the actual compiler command line. – 0___________ Oct 09 '20 at 19:50
  • Best to post your code here. – chux - Reinstate Monica Oct 09 '20 at 19:53
  • Do no include std library in kernel sources. It is just a different environment, things may break. For strings: standard library known that it can access also bytes after the string (e.g. to parallelize string operation, with full 32-bit or 64-bit operators), because it manage also the memory. So it uses it to speed up operations. Kernel has not such privilege. – Giacomo Catenazzi Oct 12 '20 at 08:42
  • Is the message payload `nlmsg_data(nlh)` actually a null-terminated string? It seems doubtful to me. Also, the kernel does not have the `strrev()` function. – Ian Abbott Oct 20 '20 at 15:24
  • @IanAbbott You are right. It does not have strrev() – Clavin Rali Nov 19 '20 at 10:20

1 Answers1

2

Linux kernel provides string functions in the linux/string.h header:

#include <linux/string.h>

Different header name has been chosen on purpose: a set of functions, provided by the Linux kernel <linux/string.h>, differs from the set of functions, provided by standard <string.h>.

The header <linux/string.h> provides most of standard string functions, and has replacement for some other ones.

E.g. functions strlen, strcpy and strncpy are provided by that header and have the same semantic, as in C standard.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153