OpenWrt: Adding Patches to a Kernel Module

This document explains how to apply patches to a Linux kernel module inside the OpenWrt build system, compile it using Kbuild, package it as a kmod-kernel-hello-world module, install it on an OpenWrt image (e.g., QEMU), and test the patched behavior.

In this section, you are going to learn:

How to organize and structure a patched OpenWrt kernel module?

How to patch kernel module source files using OpenWrt’s Build/Patch system?

How to compile a kernel module using Kbuild inside OpenWrt?

How to package and install a patched kernel module in OpenWrt?

How to test kernel module load/unload behavior after patching?

package/my/kernel-hello-world/
├── Makefile
├── patches/
│   └── 0001-change-printk.patch
└── src/
    ├── hello_world.c
    └── Makefile
  • patches/ stores patch files applied during Build/Prepare.

  • src/ contains kernel module source and Kbuild Makefile.

  • Top-level Makefile defines OpenWrt kernel package.

  • Patch application occurs inside $(PKG_BUILD_DIR).

src/hello_world.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int __init hello_world_init(void)
{
    pr_info("hello_world: loaded (base message)\n");
    return 0;
}

static void __exit hello_world_exit(void)
{
    pr_info("hello_world: unloaded (goodbye)\n");
}

module_init(hello_world_init);
module_exit(hello_world_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("you");
MODULE_DESCRIPTION("Minimal Hello-style kernel module (hello_world)");
  • hello_world_init runs at module load.

  • hello_world_exit runs at unload.

  • pr_info logs to kernel buffer via dmesg.

  • Minimal code suitable for patch demo.

src/Makefile

obj-m += hello_world.o
  • Kbuild builds hello_world.ko.

  • Kernel build invocation:

    $(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules
    

patches/0001-change-printk.patch

--- a/hello_world.c
+++ b/hello_world.c
@@ -6,7 +6,7 @@ static int __init hello_world_init(void)
 {
-    pr_info("hello_world: loaded (base message)\n");
+    pr_info("hello_world: loaded — patched message from OpenWrt package\n");
     return 0;
 }
  • Patch modifies printed message.

  • Applied automatically via Build/Patch.

  • Same flow as userland patching.

package/kernel-hello-world/Makefile

include $(TOPDIR)/rules.mk

PKG_NAME:=kernel-hello-world
PKG_RELEASE:=1

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/kernel.mk
include $(INCLUDE_DIR)/package.mk

define KernelPackage/kernel-hello-world
  SUBMENU:=Other modules
  TITLE:=Minimal hello-style kernel module (hello_world)
  FILES:=$(PKG_BUILD_DIR)/hello_world.ko
  AUTOLOAD:=$(call AutoLoad,50,hello_world)
endef

define Build/Prepare
    mkdir -p $(PKG_BUILD_DIR)
    $(CP) ./src/* $(PKG_BUILD_DIR)/
    $(call Build/Patch,$(PKG_BUILD_DIR))
endef

define Build/Compile
    $(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules
endef

define KernelPackage/kernel-hello-world/install
    $(INSTALL_DIR) $(1)/lib/modules
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/hello_world.ko $(1)/lib/modules/
endef

$(eval $(call KernelPackage,kernel-hello-world))
  • kernel.mk provides kernel build logic.

  • AUTOLOAD creates autoload entry.

  • Build/Prepare copies + patches.

  • Build/Compile invokes Kbuild.

Build:

make package/my/kernel-hello-world/compile V=s

Output:

bin/targets/x86/64/packages/kmod-kernel-hello-world*.apk
  • V=s gives verbose logs.

  • Output name includes kernel ABI.

scp -P <QEMU_PORT> bin/targets/x86/64/packages/kmod-kernel-hello-world*.apk \
    root@127.0.0.1:/tmp/
  • /tmp is writable.

  • <QEMU_PORT> depends on hostfwd configuration.

apk add --allow-untrusted /tmp/kmod-kernel-hello-world*.apk
  • Installs module under /lib/modules/<kernel-version>/.

  • AUTOLOAD adds autoload entry.

  • --allow-untrusted needed for local builds.

Load module:

modprobe hello_world

View kernel log:

dmesg | tail -20

Expected:

hello_world: loaded — patched message from OpenWrt package
  • modprobe resolves module path automatically.

  • Patched log confirms patch + build correctness.