Constellation Scorpius

Technical notes

Importing Hidden (Non-exported) Kernel Symbols

I’ve created import-kernel-symbols, which is a tiny python script to generate headers importing non-exported (non EXPORT_SYMBOL decorated) kernel symbols.

Motivation

When crafting / testing / experimenting kernel modules, occationally you need to call non-exported kernel symbols. If you can call non-exported symbols without attaching EXPORT_SYMBOL to those symbols, you can try using these functions without modifying / recompiling the kernel. In addition to this benefit, you can keep your kernel module simple, loadable and external. It’s a desirable feature for in-house kernel modules. (When you to upstream it, you simply modify the kernel :))

This python script generates references to the specified non-exported symbols. It extracts symbol kernel space address from System.map, and generates header for easy use.

Usage

First you need to create the importing header template, imported.h.in. This sample is located under example/ directory.

1
2
3
4
5
6
7
8
9
10
11
/*
 * Header importing symbols.
 */
#ifndef SAMPLE_H_
#define SAMPLE_H_
#include <linux/mm.h>

IMPORT_SYMBOL_PROLOGUE

IMPORT_SYMBOL(handle_mm_fault);
#endif  /* SAMPLE_H_ */

Next, passing it and appropriate System.map to import-kernel-symbols.py script. System.map is a file containing symbols and addresses in kernel itself. Typically (in Ubuntu case) it is located under /boot/System.map-$(uname -r), or /lib/modules/$(uname -r)/build/System.map. Note that this System.map file permission is sometimes set as -rw------- with owner root. In this case, you need to sudo to read System.map or change permission of this file. After hitting the command such as python import-kernel-symbols.py imported.h.in System.map, it will dump the generated header. The example is below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * Header importing symbols.
 */
#ifndef SAMPLE_H_
#define SAMPLE_H_
#include <linux/mm.h>

#define IMPORT_SYMBOL_VALUE_FOR_handle_mm_fault (0xffffffff81198a10UL)
#define IMPORT_SYMBOL(name) \
    static typeof(&name) IMPORTED(name) __attribute__((unused)) = (typeof(&name))IMPORT_SYMBOL_VALUE_FOR_ ## name
#define IMPORTED(name) __i__ ## name


IMPORT_SYMBOL(handle_mm_fault);
#endif  /* SAMPLE_H_ */

OK! Now, since all symbols are resolved by this header correctly, you can call the hidden symbol via special syntax. In the case of handle_mm_fault,

1
ret = IMPORTED(handle_mm_fault)(mm, vma, addr, flags);

Note that since it skips EXPORT_SYMBOL_GPL license check, take care of the license of your module. In this case, maybe, releasing code as GPL is the most conservative approach I think.

Happy Hacking ;)

Comments