2

I am trying to make Kernel (Android, kernel 4.9.59) communicate with userspace applications. I found a solution using Netlink sockets: https://stackoverflow.com/a/25071310/4190159

The first issue with the solution is that struct netlink_skb_parms used in the solution does not have a member named 'pid', instead has a member named 'portid', which I believe is not the same as pid. Anyway, to compile my kernel side code/solution I used 'portid' member of struct netlink_skb_parms instead for initialization. However, now I am getting a different error.

My Kernel side Netlink socket code as follows:

#include <linux/sched.h>
//For netlink socket -->
#include <net/sock.h>
//#include <net/netlink.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/string.h>

#define MY_GROUP    1 //For netlink socket
struct sock* socket; //For netlink socket
struct sk_buff* socket_buff; //For netlink socket

static void nl_receive_callback (struct sk_buff *skb)
{
    nlmsg_free(skb);
}

static void kernel_send_nl_msg(void)
{
    struct nlmsghdr *nlsk_mh;
    char* msg = "hello from kernel";

    socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 1, nl_receive_callback, NULL, THIS_MODULE);

    socket_buff = nlmsg_new(256, GFP_KERNEL);
    nlsk_mh = nlmsg_put(socket_buff, 0, 0, NLMSG_DONE, strlen(msg), 0);
    //NETLINK_CB(socket_buff).pid = 0;    // kernel pid is deprecated
    NETLINK_CB(socket_buff).portid = 0;
    NETLINK_CB(socket_buff).dst_group = MY_GROUP;
    strcpy(nlmsg_data(nlsk_mh), msg);

    nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);
    pr_info("%s", msg);//Print out the message to kernel

    return;
}

My userspace application side code to intercept the message from the kernel as follows:

#include <sys/socket.h>
#include <linux/netlink.h>

#define MY_GROUP    1

void user_recieve_nl_msg(void)
{
    int sock_fd;
    struct sockaddr_nl user_sockaddr;
    struct nlmsghdr *nl_msghdr;
    struct msghdr msghdr;
    struct iovec iov;

    char* kernel_msg;

    sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);

    memset(&user_sockaddr, 0, sizeof(user_sockaddr));
    user_sockaddr.nl_family = AF_NETLINK;
    user_sockaddr.nl_pid = getpid();
    user_sockaddr.nl_groups = MY_GROUP; 

    bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
    while (1) {
        nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(256));
        memset(nl_msghdr, 0, NLMSG_SPACE(256));

        iov.iov_base = (void*) nl_msghdr;
        iov.iov_len = NLMSG_SPACE(256);

        msghdr.msg_name = (void*) &user_sockaddr;
        msghdr.msg_namelen = sizeof(user_sockaddr);
        msghdr.msg_iov = &iov;
        msghdr.msg_iovlen = 1;

        recvmsg(sock_fd, &msghdr, 0);

        kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
        print("Kernel message: %s\n", kernel_msg); // print to android logs
    }

    close(sock_fd);
}

When I am trying to build the android kernel I am receiving the fllowing error:

kernel/sched/custom_code.h:34:65: error: passing argument 3 of 'netlink_kernel_create' makes pointer from integer without a cast [-Werror]

kernel/sched/custom_code.h:34:14: error: too many arguments to function 'netlink_kernel_create'

Note the code for the Kernel side is written in custom_code.h.

My questions are as follows:

  1. I have checked the function 'netlink_kernel_create' and I am sending the right number of arguments then why is the aformentioned error coming up? How this error could be resolved?

  2. What should I do to establish a valid communication between the kernel and the userspace application so that messages could be passed (to and fro) between them?

jww
  • 97,681
  • 90
  • 411
  • 885
Somdip Dey
  • 3,346
  • 6
  • 28
  • 60

1 Answers1

3

1. Let's check netlink_kernel_create function in linux kernel:

static inline struct sock *
netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
{
    return __netlink_kernel_create(net, unit, THIS_MODULE, cfg);
}

from here https://elixir.bootlin.com/linux/v4.9.59/source/include/linux/netlink.h#L60 Notice, that this function takes only 3 arguments ( instead of 6 in your code )

This function have been changed in kernel 3.6 ( from 6 parameters to 4 ) https://elixir.bootlin.com/linux/v3.6/source/include/linux/netlink.h#L185

And then renamed to __netlink_kernel_create in kernel 3.7

netlink_kernel_create function from 3.7 accepts 3 arguments https://elixir.bootlin.com/linux/v3.7/source/include/linux/netlink.h#L48

Try change this

socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 1, nl_receive_callback, NULL, THIS_MODULE);

to this

struct netlink_kernel_cfg cfg = {
    .input  = nl_receive_callback,
    .groups = 1,
};
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
  1. Now you can send data in direction "kernel => application".

When you start your application, it will bind socket with user_sockaddr.nl_groups = MY_GROUP; bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));.

After this you can send data from kernel to application with NETLINK_CB(socket_buff).dst_group = MY_GROUP; nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL); and it will be received by application with recvmsg(sock_fd, &msghdr, 0);

How can I call kernel_send_nl_msg() function to actually communicate with the userspace?

You can call it from kernel module, which you write, compile and insmod into kernel. Or you can call it directly from kernel, but for this you will need to rebuild whole kernel.

If you want to send data in direction "application = > kernel", then you need to do things in reverse: bind new socket with another MY_GROUP2 in kernel and send data from application with nlmsg_multicast

Roman Zaitsev
  • 1,328
  • 5
  • 20
  • 28
  • 1
    Hi @Roman thank you for your answer and reply. First you have mentioned that the updated netlink_kernel_create function accepts 3 arguments and not 4, however, your answer is passing 4 of them. Secondly, even after using you solution I am getting the following error: ./include/linux/export.h:37:21: error: passing argument 3 of 'netlink_kernel_create' from incompatible pointer type [-Werror] kernel/sched/custom_code.h:39:14: error: too many arguments to function 'netlink_kernel_create' – Somdip Dey Apr 24 '19 at 13:11
  • 1
    I have edited your anser, which now works. However, will it be possible to answer my question 2? How can I call kernel_send_nl_msg() function to actually communicate with the userspace? Thank you in advance. – Somdip Dey Apr 24 '19 at 14:32
  • Thanks for fixing my mistake. Check my edit to answer – Roman Zaitsev Apr 25 '19 at 08:49
  • Hi @Roman, will you interested to help me with this problem:https://stackoverflow.com/questions/55870596/kernel-android-to-userspace-message-multicast-error-netlink-broadcast-filtere ? – Somdip Dey Apr 26 '19 at 16:45