From e05eb91addeb30a8486fa0926270a36aafe58fe7 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Fri, 6 Jul 2018 08:56:22 +0100 Subject: [PATCH] netlink: move docs to README --- README.adoc | 36 ++++++++++++++++++++++++++++++++++++ kernel_module/README.adoc | 2 -- kernel_module/netlink.c | 34 +++++++++++----------------------- kernel_module/netlink.h | 10 ++++++++++ kernel_module/user/netlink.c | 11 +++++++---- rootfs_overlay/netlink.sh | 7 +++++++ rootfs_overlay/test_all.sh | 1 + 7 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 kernel_module/netlink.h create mode 100755 rootfs_overlay/netlink.sh diff --git a/README.adoc b/README.adoc index 65330e0..8bd5274 100644 --- a/README.adoc +++ b/README.adoc @@ -3920,6 +3920,42 @@ Reads to that inode return the sequence: `1`, `10`, `100`, ... `10000000`, `1`, Bibliography: https://stackoverflow.com/questions/4508998/what-is-an-anonymous-inode-in-linux +==== netlink sockets + +Netlink sockets offer a socket API for kernel / userland communication: + +.... +/netlink.sh +echo $? +.... + +Outcome: the test passes: + +.... +0 +.... + +Sources: + +* link:kernel_module/netlink.c[] +* link:kernel_module/netlink.h[] +* link:kernel_module/user/netlink.c[] +* link:rootfs_overlay/netlink.sh[] + +Launch multiple user requests in parallel to stress our socket: + +.... +insmod /netlink.ko sleep=1 +for i in `seq 16`; do /netlink.out & done +.... + +TODO: what is the advantage over `read`, `write` and `poll`? https://stackoverflow.com/questions/16727212/how-netlink-socket-in-linux-kernel-is-different-from-normal-polling-done-by-appl + +Bibliography: + +* https://stackoverflow.com/questions/3299386/how-to-use-netlink-socket-to-communicate-with-a-kernel-module +* https://en.wikipedia.org/wiki/Netlink + === Linux kernel asynchronous APIs In this section we will document asynchronous APIs of Linux kernel, especially kthread-related scheduled events. diff --git a/kernel_module/README.adoc b/kernel_module/README.adoc index 078176e..a27240b 100644 --- a/kernel_module/README.adoc +++ b/kernel_module/README.adoc @@ -9,8 +9,6 @@ Our kernel modules! .. link:timer.c[] .. link:work_from_work.c[] .. link:workqueue_cheat.c[] -. Misc -.. link:netlink.c[] . Hardening .. link:strlen_overflow.c[] . Tracing diff --git a/kernel_module/netlink.c b/kernel_module/netlink.c index 76500a2..970b3bc 100644 --- a/kernel_module/netlink.c +++ b/kernel_module/netlink.c @@ -1,46 +1,34 @@ -/* -https://en.wikipedia.org/wiki/Netlink - -https://stackoverflow.com/questions/3299386/how-to-use-netlink-socket-to-communicate-with-a-kernel-module -*/ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#netlink-sockets */ #include /* usleep_range */ -#include #include #include #include #include -/* Socket identifier, matches userland. TODO can be anything? - * Is there a more scalable way to do it? E.g. ioctl device, - * kernel generates one on the fly, then give it back and connect? - * https://stackoverflow.com/questions/32898173/can-i-have-more-than-32-netlink-sockets-in-kernelspace */ -#define NETLINK_USER 31 +#include "netlink.h" struct sock *nl_sk = NULL; +static u32 count; +static u32 sleep; +module_param(sleep, int, S_IRUSR | S_IWUSR); + static void callback(struct sk_buff *skb) { - char readbuf[1024]; + char readbuf[9]; size_t readbuflen; int pid; int res; struct nlmsghdr *nlh; struct sk_buff *skb_out; - /* Read user message. */ nlh = (struct nlmsghdr *)skb->data; pr_info("kernel received: %s\n", (char *)nlmsg_data(nlh)); - - /* Add an artificial sleep to see what happens when - * multiple requests come in at the same time. - * - * Try this out (it works): - * for i in `seq 16`; do /netlink.out & done */ - usleep_range(1000000, 1000001); - - /* Reply with jiffies. */ - readbuflen = snprintf(readbuf, sizeof(readbuf), "%llu", (unsigned long long)jiffies); + if (sleep) + usleep_range(1000000, 1000001); + readbuflen = snprintf(readbuf, sizeof(readbuf), "%x", count); + count++; pid = nlh->nlmsg_pid; skb_out = nlmsg_new(readbuflen, 0); if (!skb_out) { diff --git a/kernel_module/netlink.h b/kernel_module/netlink.h new file mode 100644 index 0000000..927f51d --- /dev/null +++ b/kernel_module/netlink.h @@ -0,0 +1,10 @@ +#ifndef NETLINK_H +#define NETLINK_H + +/* Socket identifier, matches userland. TODO can be anything? + * Is there a more scalable way to do it? E.g. ioctl device, + * kernel generates one on the fly, then give it back and connect? + * https://stackoverflow.com/questions/32898173/can-i-have-more-than-32-netlink-sockets-in-kernelspace */ +#define NETLINK_USER 31 + +#endif diff --git a/kernel_module/user/netlink.c b/kernel_module/user/netlink.c index d96b152..c9cbf25 100644 --- a/kernel_module/user/netlink.c +++ b/kernel_module/user/netlink.c @@ -1,3 +1,5 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#netlink-sockets */ + #include #include #include @@ -5,8 +7,9 @@ #include #include +#include "../netlink.h" + #define MAX_PAYLOAD 1024 -#define NETLINK_USER 31 /* Some of these structs fields must be zeroed. * We could brute force memset them, but @@ -40,10 +43,10 @@ int main() msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; - printf("before sendmsg\n"); + fprintf(stderr, "before sendmsg\n"); sendmsg(sock_fd, &msg, 0); - printf("after sendmsg\n"); + fprintf(stderr, "after sendmsg\n"); recvmsg(sock_fd, &msg, 0); - printf("userland received: %s\n", (char *)NLMSG_DATA(nlh)); + printf("%s\n", (char *)NLMSG_DATA(nlh)); close(sock_fd); } diff --git a/rootfs_overlay/netlink.sh b/rootfs_overlay/netlink.sh new file mode 100755 index 0000000..9d4c0a5 --- /dev/null +++ b/rootfs_overlay/netlink.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -e +insmod /netlink.ko +[ "$(/netlink.out)" = 0 ] +[ "$(/netlink.out)" = 1 ] +[ "$(/netlink.out)" = 2 ] +rmmod netlink diff --git a/rootfs_overlay/test_all.sh b/rootfs_overlay/test_all.sh index fd13fdf..39b59b8 100755 --- a/rootfs_overlay/test_all.sh +++ b/rootfs_overlay/test_all.sh @@ -10,6 +10,7 @@ for test in \ /ioctl.sh \ /kstrto.sh \ /mmap.sh \ + /netlink.sh \ /params.sh \ /procfs.sh \ /seq_file.sh \