7.2 Examples
1. Read Something in Kernel Space
Following example is a a Loadable Kernel Module (LKM) that creates a file in /proc so you can read something from the kernel space using user-space commands like cat.
LKM That Adds a File to /proc
This module creates a file /proc/helloproc that you can read with cat.
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/uaccess.h>  // for copy_to_user()
#define PROC_NAME "helloproc"#define MESSAGE "Hello from the kernel!\n"
static ssize_t proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {    return simple_read_from_buffer(buf, count, ppos, MESSAGE, strlen(MESSAGE));}
static struct proc_ops proc_file_ops = {    .proc_read = proc_read,};
static int __init hello_init(void) {    proc_create(PROC_NAME, 0, NULL, &proc_file_ops);    printk(KERN_INFO "/proc/%s created\n", PROC_NAME);    return 0;}
static void __exit hello_exit(void) {    remove_proc_entry(PROC_NAME, NULL);    printk(KERN_INFO "/proc/%s removed\n", PROC_NAME);}
module_init(hello_init);module_exit(hello_exit);
MODULE_LICENSE("GPL");MODULE_AUTHOR("You");MODULE_DESCRIPTION("Kernel module with /proc file");π Makefile (same as before)
obj-m += helloproc.o
all:  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) cleanπ Usage
makesudo insmod helloproc.kocat /proc/helloproc     # Output: Hello from the kernel!sudo rmmod helloprocYou can also run dmesg | tail to see kernel logs.
1.1 Extending the Example
Now your LKM will read and write from a /proc file. Youβll be able to do:
echo "Hi kernel!" > /proc/helloproccat /proc/helloprocand see your message echoed back.
π Read/Write LKM Using /proc
This module creates /proc/helloproc, and stores a message that you can update with echo.
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/uaccess.h>
#define PROC_NAME "helloproc"#define MAX_LEN 100
static char message[MAX_LEN] = "Hello from kernel!\n";static ssize_t message_len = 0;
static ssize_t proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {    return simple_read_from_buffer(buf, count, ppos, message, message_len);}
static ssize_t proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {    if (count > MAX_LEN) count = MAX_LEN;    if (copy_from_user(message, buf, count)) return -EFAULT;    message_len = count;    return count;}
static struct proc_ops proc_file_ops = {    .proc_read = proc_read,    .proc_write = proc_write,};
static int __init hello_init(void) {    proc_create(PROC_NAME, 0666, NULL, &proc_file_ops);    printk(KERN_INFO "/proc/%s created (RW)\n", PROC_NAME);    return 0;}
static void __exit hello_exit(void) {    remove_proc_entry(PROC_NAME, NULL);    printk(KERN_INFO "/proc/%s removed\n", PROC_NAME);}
module_init(hello_init);module_exit(hello_exit);
MODULE_LICENSE("GPL");MODULE_AUTHOR("You");MODULE_DESCRIPTION("Proc RW Kernel Module");π Makefile
obj-m += helloproc_rw.o
all:  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) cleanπ§ͺ Try it out:
makesudo insmod helloproc_rw.ko
# Read default messagecat /proc/helloproc
# Write a new messageecho "Hi kernel!" | sudo tee /proc/helloproc
# Read the updated messagecat /proc/helloproc
# Clean upsudo rmmod helloproc_rw1.2 π§© Kernel Module: Responds to "uptime"
Now weβll make a user-space C program that talks to our kernel module via /proc/helloproc. Weβll also change the kernel module a bit to show the current uptime in seconds whenever a user writes "uptime" to it.
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/uaccess.h>#include <linux/jiffies.h>#include <linux/ktime.h>
#define PROC_NAME "helloproc"#define MAX_LEN 100
static char message[MAX_LEN];static ssize_t message_len;
static ssize_t proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {    return simple_read_from_buffer(buf, count, ppos, message, message_len);}
static ssize_t proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {    char input[MAX_LEN];
    if (count > MAX_LEN - 1) count = MAX_LEN - 1;    if (copy_from_user(input, buf, count)) return -EFAULT;    input[count] = '\0';
    if (strncmp(input, "uptime", 6) == 0) {        unsigned long uptime = jiffies / HZ;        message_len = snprintf(message, MAX_LEN, "Uptime: %lu seconds\n", uptime);    } else {        message_len = snprintf(message, MAX_LEN, "You said: %s", input);    }
    return count;}
static struct proc_ops proc_file_ops = {    .proc_read = proc_read,    .proc_write = proc_write,};
static int __init hello_init(void) {    proc_create(PROC_NAME, 0666, NULL, &proc_file_ops);    printk(KERN_INFO "/proc/%s created (uptime enabled)\n", PROC_NAME);    return 0;}
static void __exit hello_exit(void) {    remove_proc_entry(PROC_NAME, NULL);    printk(KERN_INFO "/proc/%s removed\n", PROC_NAME);}
module_init(hello_init);module_exit(hello_exit);
MODULE_LICENSE("GPL");MODULE_AUTHOR("You");MODULE_DESCRIPTION("Proc RW Kernel Module with uptime");π§βπ» User-Space C Program
#include <stdio.h>#include <stdlib.h>#include <string.h>
int main() {    const char *path = "/proc/helloproc";    FILE *fp;
    // Write "uptime" to kernel    fp = fopen(path, "w");    if (!fp) {        perror("fopen write");        return 1;    }    fprintf(fp, "uptime\n");    fclose(fp);
    // Read response    fp = fopen(path, "r");    if (!fp) {        perror("fopen read");        return 1;    }
    char buffer[128];    while (fgets(buffer, sizeof(buffer), fp)) {        printf("Kernel says: %s", buffer);    }
    fclose(fp);    return 0;}Compile it:
gcc userprog.c -o userprogπ§ͺ Try It Out
- 
Compile and load your module:
Terminal window makesudo insmod helloproc_uptime.ko - 
Run the user-space program:
Terminal window ./userprogβ Output:
Kernel says: Uptime: 12345 seconds - 
Cleanup:
Terminal window sudo rmmod helloproc_uptime 
1.3 Creating a Device File
Youβre going full kernel hacker mode now π. Letβs level up from /proc to creating a real device file in /dev, using the misc device API, which is much closer to how real drivers work.
π¦ Whatβs a misc device?
Itβs a simpler way to register a character device. You get:
- A real file under 
/dev/mydevice - Full control over read, write, ioctl, etc.
 - Clean and minimal boilerplate
 
π§ͺ Goal
/dev/mydevicethat responds to input
Behavior:
- Write 
"uptime"β responds with system uptime - Write anything else β echoes it back
 
πΈ Kernel Module: mydevice.c
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/uaccess.h>#include <linux/jiffies.h>
#define BUFFER_SIZE 256
static char message[BUFFER_SIZE];static ssize_t message_len;
static ssize_t device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {    return simple_read_from_buffer(buf, count, ppos, message, message_len);}
static ssize_t device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {    char input[BUFFER_SIZE];
    if (count >= BUFFER_SIZE)        count = BUFFER_SIZE - 1;
    if (copy_from_user(input, buf, count))        return -EFAULT;
    input[count] = '\0';
    if (strncmp(input, "uptime", 6) == 0) {        unsigned long uptime = jiffies / HZ;        message_len = snprintf(message, BUFFER_SIZE, "Uptime: %lu seconds\n", uptime);    } else {        message_len = snprintf(message, BUFFER_SIZE, "You said: %s", input);    }
    return count;}
static struct file_operations fops = {    .owner = THIS_MODULE,    .read = device_read,    .write = device_write,};
static struct miscdevice my_misc_device = {    .minor = MISC_DYNAMIC_MINOR,    .name = "mydevice",    .fops = &fops,    .mode = 0666};
static int __init mydevice_init(void) {    int ret = misc_register(&my_misc_device);    if (ret)        printk(KERN_ERR "Failed to register misc device\n");    else        printk(KERN_INFO "/dev/mydevice registered\n");    return ret;}
static void __exit mydevice_exit(void) {    misc_deregister(&my_misc_device);    printk(KERN_INFO "/dev/mydevice unregistered\n");}
module_init(mydevice_init);module_exit(mydevice_exit);
MODULE_LICENSE("GPL");MODULE_AUTHOR("You");MODULE_DESCRIPTION("Simple misc device example");π Makefile
obj-m += mydevice.o
all:  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) cleanπ§ͺ Run It!
makesudo insmod mydevice.ko
# Check that the device was createdls -l /dev/mydevice
# Interact with itecho "uptime" | sudo tee /dev/mydevicecat /dev/mydevice
echo "hello from user" | sudo tee /dev/mydevicecat /dev/mydevice
sudo rmmod mydeviceπ§βπ» Want to write a user-space C client for /dev/mydevice too?
Or maybe want bidirectional communication with a user-space daemon (e.g., using ioctl) or notifications from the kernel (poll, select, or fasync)?
2. Extending netfilter
#include <linux/kernel.h>#include <linux/module.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>
static struct nf_hook_ops netfilter_ops_in;static struct nf_hook_ops netfilter_ops_out;
unsigned int main_hook(void* priv,                        struct sk_buff* skb,                        const struct nf_hook_state* state){    printk(KERN_INFO "packet received\n");    return NF_ACCEPT; // NF_ACCEPT allows packets, NF_DROP rejects them}
static int __init hello_init(void){    netfilter_ops_in.hook = main_hook; // What function to call?    netfilter_ops_in.pf = PF_INET; // Protocol Family    netfilter_ops_in.hooknum = NF_INET_PRE_ROUTING; // Incoming traffic    netfilter_ops_in.priority = NF_IP_PRI_FIRST; // What priority is this hook?
    netfilter_ops_out.hook = main_hook;    netfilter_ops_out.pf = PF_INET;    netfilter_ops_out.hooknum = NF_INET_POST_ROUTING; // Outgoing traffic    netfilter_ops_out.priority = NF_IP_PRI_FIRST;
    nf_register_net_hook(&init_net, &netfilter_ops_in); // Register the incoming traffic hook    nf_register_net_hook(&init_net, &netfilter_ops_out); // Register the outgoing traffic hook    return 0;}
static void __exit hello_exit(void){    nf_unregister_net_hook(&init_net, &netfilter_ops_in);    nf_unregister_net_hook(&init_net, &netfilter_ops_out);}
module_init(hello_init);module_exit(hello_exit);