Undefined symbol when using insmod - c

I write a linux-kernel module, but when I run this command insmod ./...ko, the kernel posts an error: Undefined symbol ...
After that, I searched for a long time, all the solutions are to use EXPORT_SYMBOL(), so I write it in kernel codes and rebuild the kernel. Interesting things happen, the kernel says exports duplicate symbol ... (owned by kernel). It seems that the symbol is exported more than once, but if so, why can I not use it before?
This is related code in my module:
extern struct task_struct *find_task_by_vpid(pid_t nr);
target_tsk = pid == -1 ? current : find_task_by_vpid(pid);
and I changed the kernel file linux/sched.h to this format:
extern struct task_struct *find_task_by_vpid(pid_t nr);
EXPORT_SYMBOL_GPL(find_task_by_vpid);

Symbol exporting (EXPORT_SYMBOL) should be performed in a source file (.c), not in a header file (.h).
This is because exporting symbol is a definition of (some other) symbol, and header files a not suitable for such things.

Related

Unknown symbol when loading a kernel module

I tried to redo the code of the kernel module found in this topic How can I obtain battery level inside a Linux kernel module?. But when I try to use the functions contained in the power_supply.h header file, the loading of the module fails because it does not recognize the power_supply_get_by_name function.
Here is the code that I am using on Ubuntu 18.04 with kernel version 4.15.0-101-generic:
#include <linux/module.h>
#include <linux/power_supply.h>
static int __init test_init (void)
{
struct power_supply *psy;
char name[] = "BAT1";
psy = power_supply_get_by_name(name);
printk(KERN_DEBUG "Test module inserted");
return 0;
}
static void __exit test_exit (void)
{
printk(KERN_DEBUG "Test module removed");
}
module_init (test_init);
module_exit (test_exit);
I get no error at compiling except a warning concerning the module license which is I think not related to my problem but I get the following errors:
when running insmod in the terminal: "insmod: ERROR: could not insert module test.ko: Unknown symbol in module"
in the /var/log/kern.log file: "test: Unknown symbol power_supply_get_by_name (err 0)"
I checked the kallsyms proc file and the function is indicated as usable in other kernel modules if I understood well this topic What is the difference between T and t in /proc/kallsyms. Here is the output from reading the kallsyms file:
ffffffff8e9bd270 T power_supply_get_by_name
Does anyone knows why this is not working while I can use other linux headers functions without any problem and, if so, how I can fix my problem?
Thanks in advance
This may actually be related to the module license! If you look at the kernel source code, the function power_supply_get_by_name is exported here. You can see it's using EXPORT_SYMBOL_GPL. As this answer explains:
EXPORT_SYMBOL_GPL will show the symbol only in GPL-licensed modules
The use of this macro is controversial, but that's the way the project operates... To gain access to the symbols you need, you'll need to license your module as GPL:
MODULE_LICENSE("GPL");

Why can't some functions be used in kernel modules?

For examples, in pgtable_types.h, the function prototype:
extern pte_t *lookup_address(unsigned long address, unsigned int *level);
Is clearly present in the header file.
However when I compile a kernel module with this function and then insmod the .ko output file I get a lookup_address symbol not found error.
Why is this?
Does your module have a MODULE_LICENSE("GPL v2") line in it? If not, it is assumed to be proprietary and will not allow access to GPL symbols which lookup_address is marked as.

Can anybody explain about following structure

What is the use of the below structure in linux kernel? I need to know it because I need to add a variable inside this structure.
static const struct modversion_info ____versions[]
It includes symbols referenced by the module and their checksums, when the module is inserted those symbols are checked to make sure the module is compiled for the running kernel.
On Ubnutu the kernel-headers package contains this file which has all the symbols exported by the kernel and their checksums, you should be able to find this file if you compiled your own kernel too
usr/src/linux-headers-2.6.38-generic/Module.symvers
Note, I'm not sure what you're trying to do but you shouldn't be adding symbols to your module, when you compile a module this structure is generated for you.

How to call exported kernel module functions from another module?

I'm writing an API as a kernel module that provides device drivers with various functions. I wrote three functions in mycode.c. I then built and loaded the module, then copied mycode.h into < kernel >/include/linux. In a device driver, I have a #include < linux/mycode.h > and call those three functions. But when I build the driver module, I get three linker warnings saying that those functions are undefined.
Notes:
The functions are declared extern in mycode.h
The functions are exported using EXPORT_SYMBOL(func_name) in mycode.c
Running the command nm mycode.ko shows all three functions as being available in the symbol table (capital T next to them, meaning the symbols are found in the text (code) section)
After loading the module, the command grep func_name /proc/kallsyms shows all three functions as being loaded
So clearly the functions are being exported correctly and the kernel knows what and where they are. So why can't the driver see their definitions? Any idea what am I missing?
EDIT: I found some information about this here: http://www.kernel.org/doc/Documentation/kbuild/modules.txt
Sometimes, an external module uses exported symbols from another
external module. kbuild needs to have full knowledge of all symbols
to avoid spitting out warnings about undefined symbols. Three
solutions exist for this situation.
NOTE: The method with a top-level kbuild file is recommended but may
be impractical in certain situations.
Use a top-level kbuild file If you have two modules, foo.ko and
bar.ko, where foo.ko needs symbols from bar.ko, you can use a
common top-level kbuild file so both modules are compiled in the
same build. Consider the following directory layout:
./foo/ <= contains foo.ko
./bar/ <= contains bar.ko
The top-level kbuild file would then look like:
#./Kbuild (or ./Makefile):
obj-y := foo/ bar/
And executing
$ make -C $KDIR M=$PWD
will then do the expected and compile both modules with full
knowledge of symbols from either module.
Use an extra Module.symvers file When an external module is built,
a Module.symvers file is generated containing all exported symbols
which are not defined in the kernel. To get access to symbols from
bar.ko, copy the Module.symvers file from the compilation of bar.ko
to the directory where foo.ko is built. During the module build,
kbuild will read the Module.symvers file in the directory of the
external module, and when the build is finished, a new
Module.symvers file is created containing the sum of all symbols
defined and not part of the kernel.
Use "make" variable KBUILD_EXTRA_SYMBOLS If it is impractical to
copy Module.symvers from another module, you can assign a space
separated list of files to KBUILD_EXTRA_SYMBOLS in your build file.
These files will be loaded by modpost during the initialization of
its symbol tables.
But with all three of these solutions, in order for any driver to use my API, it would have to either create a new Makefile or have direct access to my Module.symvers file? That seems a bit inconvenient. I was hoping they'd just be able to #include my header file and be good to go. Do no other alternatives exist?
From my research, it seems that those are the only three ways to handle this situation, and I've gotten each of them to work, so I think I'll just pick my favorite out of those.
Minimal QEMU + Buildroot example
I have tested the following in a fully reproducible QEMU + Buildroot environment, so maybe having this working version version will help you find out what is wong with your code.
GitHub upstream is centered on the files:
dep.c
dep2.c
Makefile
dep.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
int lkmc_dep = 0;
EXPORT_SYMBOL(lkmc_dep);
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", lkmc_dep);
usleep_range(1000000, 1000001);
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
dep2.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
extern int lkmc_dep;
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
usleep_range(1000000, 1000001);
lkmc_dep++;
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
And now you can do:
insmod dep.ko
insmod dep2.ko
With that Buildroot setup, things are already configuring depmod /lib/module/*/depmod with the dependency, so just this is enough to load both:
modprobe dep
Also, if you built your kernel with CONFIG_KALLSYMS_ALL=y, then the exported symbol can be seen with:
grep lkmc_dep /proc/kallsyms
see also: Does kallsyms have all the symbol of kernel functions?
OK: You have one module where the function is and one place what wants to import it right?
You must use "EXPORT_SYMBOL("name of the function") such as foo in the place where the function is. So in the "c" file have the function "foo" defined and put in:
EXPORT_SYMBOL(foo)
Make sure you have the prototype for "foo" in a common header file (you can have it in separate places for each module and it will work but you are asking for trouble if the signatures change). So say: void foo(void *arg);
Then the other module that wants it just invoke "foo" and you are good.
Also: Make sure that you load the module with foo first. If you have cross dependencies like module2 needs foo from module1 and module1 needs bar from module2 you need to have one register functions with another. If you want to know please ask a separate Q.

How to prevent "error: 'symbol' undeclared here" despite EXPORT_SYMBOL in a Linux kernel module?

I'm embedding some driver into a Linux kernel when I get this error (I'm adding the device in the board file and registering it):
error: 'kxtf9_get_slave_descr' undeclared here (not in a function)
I located the function above in a driver file
struct ext_slave_descr *kxtf9_get_slave_descr(void)
{
return &kxtf9_descr;
}
EXPORT_SYMBOL(kxtf9_get_slave_descr);
Shouldn't it made "visible" by EXPORT_SYMBOL?
The C file containing the code above has no header file (I didn't write it, I just found it here and I'm implementing. They say it's tested so I assume an header is not needed?
The rest of the code compiles perfectly (so it "sees" the code in the folder), and the file containing the code above compiles as well!
EXPORT_SYMBOL exports the symbol for dynamic linking. What you have is not a linking error but a compilation error due to a missing function declaration. You have to either write a header file for the C file and include that header file, or you declare the function the C file you're compiling.
Option 1:
kxtf9.h:
#ifndef KXTF9_H
#define KXTF9_H
struct ext_slave_descr *kxtf9_get_slave_descr(void);
#endif
your_file.c:
#include "kxtf9.h"
/* your code where you use the function ... */
Option 2:
your_file.c:
struct ext_slave_descr *kxtf9_get_slave_descr(void);
/* your code where you use the function ... */
Also note that the EXPORT_SYMBOL in the file kxtf9.c has #ifdef __KERNEL__ around it, so you have to have set up your build environment (Makefile) correctly - otherwise you'll get a link error.

Resources