Linux kernel tracepoint: Symbol undefined when connecting a probe function to tracepoint - linux

I'm now practicing with Linux tracepoint.
Basically, I'm trying to make a kernel module where a probe function is defined and connected to a tracepoint("trace_netif_receive_skb" in kernel source file dev.c) in Linux Kernel.
When I compiled and ran the kernel module on SLES11, it works well. But when I did the same things on SLES12, it complained that the symbol is undefined.
The kernel module source code is:
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/skbuff.h>
5 #include <trace/events/net.h>
6
7 static void probe(void *ignore, struct sk_buff *skb)
8 {
9 printk(KERN_INFO "probe, protocol[0X%04X]\n", ntohs(skb->protocol));
10 }
11
12 static int __init init_tracepoint(void)
13 {
14 if (0 != register_trace_netif_receive_skb(probe, NULL))
15 {
16 printk(KERN_INFO "tracepoint init fails\n");
17 }
18
19 printk(KERN_INFO "tracepoint init succeeds\n");
20 return 0;
21 }
22
23 static void __exit cleanup_tracepoint(void)
24 {
25 unregister_trace_netif_receive_skb(probe, NULL);
26 tracepoint_synchronize_unregister();
27
28 printk(KERN_INFO "tracepoint exit\n");
29 }
30
31 module_init(init_tracepoint);
32 module_exit(cleanup_tracepoint);
33
34 MODULE_LICENSE("GPL");
This is the output on SLES11, no error is reported.
suse11-1:~/works/tracepoint # make
make -C /lib/modules/3.0.76-0.11-default/build M=/root/works/tracepoint modules
make[1]: Entering directory `/usr/src/linux-3.0.76-0.11-obj/x86_64/default'
make -C ../../../linux-3.0.76-0.11 O=/usr/src/linux-3.0.76-0.11-obj/x86_64/default/. modules
CC [M] /root/works/tracepoint/tracepoint.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/works/tracepoint/tracepoint.mod.o
LD [M] /root/works/tracepoint/tracepoint.ko
make[1]: Leaving directory `/usr/src/linux-3.0.76-0.11-obj/x86_64/default'
suse11-1:~/works/tracepoint # insmod tracepoint.ko
This is the output on SLES12, it says: WARNING: "__tracepoint_netif_receive_skb" [/root/works/codes/tracepoint/tracepoint.ko] undefined! And I can find "Unknown symbol __tracepoint_netif_receive_skb (err 0)" in /var/log/messages.
suse12-1:~/works/codes/tracepoint # make
make -C /lib/modules/4.4.21-69-default/build M=/root/works/codes/tracepoint modules
make[1]: Entering directory '/usr/src/linux-4.4.21-69-obj/x86_64/default'
CC [M] /root/works/codes/tracepoint/tracepoint.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: "__tracepoint_netif_receive_skb" [/root/works/codes/tracepoint/tracepoint.ko] undefined!
CC /root/works/codes/tracepoint/tracepoint.mod.o
LD [M] /root/works/codes/tracepoint/tracepoint.ko
make[1]: Leaving directory '/usr/src/linux-4.4.21-69-obj/x86_64/default'
suse12-1:~/works/codes/tracepoint #
suse12-1:~/works/codes/tracepoint # insmod tracepoint.ko
insmod: ERROR: could not insert module tracepoint.ko: Unknown symbol in module
I checked the kernel source code of tracepoint framework of both SLES11 and SLES12, the "__tracepoint_##name" defined "include/linux/tracepoint.h" is not exported unless EXPORT_TRACEPOINT_SYMBOL() or EXPORT_TRACEPOINT_SYMBOL_GPL() is called, but I didn't find any place in linux kernel codes where EXPORT_TRACEPOINT_SYMBOL(netif_receive_skb) or EXPORT_TRACEPOINT_SYMBOL_GPL(netif_receive_skb) is called to export symbol __tracepoint_netif_receive_skb.
Then why I didn't meet the problem on SLES11? And how can I get it work on SLES12?

Use for_each_kernel_tracepoint to find target tracepoint and register probe, works for me, good luck.
struct tp_reg {
const char *name;
struct tracepoint *tp;
void *fn;
};
static void each_tracepoint(struct tracepoint *tp, void *priv)
{
struct tp_reg *regs = (struct tp_reg *)priv;
int i;
for (i = 0; regs[i].name; ++i) {
if (strcmp(tp->name, regs[i].name) == 0) {
if (tracepoint_probe_register(tp, regs[i].fn, NULL) == 0) {
regs[i].tp = tp;
}
}
}
}
static void unregister_tp(struct tp_reg *regs)
{
int i;
for (i = 0; regs[i].name; ++i) {
if (regs[i].tp) {
tracepoint_probe_unregister(regs[i].tp, regs[i].fn, NULL);
regs[i].tp = NULL;
}
}
tracepoint_synchronize_unregister();
}
static int register_tp(struct tp_reg *regs)
{
int i;
for_each_kernel_tracepoint(each_tracepoint, regs);
for (i = 0; regs[i].name; ++i) {
if (regs[i].tp == NULL) {
printk(KERN_ALERT "trace point %s not found.\n", regs[i].name);
unregister_tp(regs);
return 1;
}
}
return 0;
}
Sample code:
static void probe_callback(void *ignore, struct pt_regs *regs, long id)
{
if (id == __NR_execve) {
char file[100];
if (strncpy_from_user(file, (void *)PT_REGS_PARM1(regs), sizeof(file)) < 0)
return;
printk(KERN_INFO "execve %s", file);
}
}
static struct tp_reg myreg[] = {
{ .name = "sys_enter", .fn = (void *)probe_callback },
{ .name = NULL }
};
static int __init init_tracepoint(void)
{
return register_tp(myreg);
}
static void __exit cleanup_tracepoint(void)
{
unregister_tp(myreg);
}

Related

nvcc under linux complains: Contains a vector, which is not supported in device code

I have the following code
#include <cuda.h>
#include <cuda_runtime.h>
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
//A bitset for the variable assignments
//The state for non existing variable 0 is stored as well, just to avoid +1/-1 adjustments
struct Atom_t {
enum where { device, host};
enum BoolOp {opXor, opOr, opAnd };
public: //TODO make private later
int VarCount;
bool isValid;
union {
uint32_t raw[1]; //don't worry about alignment, the compiler will not use aligned read/writes anyway.}
uint64_t raw64[1];
__m256i avxraw[1];
};
public:
__host__ __device__ friend bool operator==(const Atom_t& a, const Atom_t& b);
};
__host__ __device__ bool operator==(const Atom_t& a, const Atom_t& b) {
const auto IntCount = a.IntCount();
if (IntCount != b.IntCount()) { return false; }
#ifdef __CUDA_ARCH__
__shared__ bool isDifferent;
isDifferent = false;
for (auto i = ThreadId(); i < IntCount; i += BlockDim()) {
if (a.raw[i] != b.raw[i] || isDifferent) {
isDifferent = true;
break;
}
}
syncthreads();
return !isDifferent;
#else
auto result = true;
#ifdef _DEBUG
for (auto i = 0; i < IntCount; i++) {
if (a.raw[i] != b.raw[i]) { result = false; }
}
#endif
auto AvxCount = a.Avx2Count();
if (AvxCount != b.Avx2Count()) { if (result) { print("Atom_t == is incorrect"); } assert1(!result); return false; }
for (auto i = 0; i < AvxCount; i++) {
const auto packedCompare = _mm256_cmpeq_epi8(a.avxraw[i], b.avxraw[i]);
const auto bitmask = _mm256_movemask_epi8(packedCompare);
if (bitmask != -1) { if (result) { print("Atom_t == is incorrect"); } assert1(!result); return false; }
}
#endif
#ifndef __CUDA_ARCH__
assert(result);
#endif
return true;
}
The compiler complains
Description Resource Path Location Type
"__nv_bool (const Atom_t &, const Atom_t &)" contains a vector, which is not supported in device code
However, the vector is not in device code, only in the host code. How do I make this error go away in NSight Eclipse Edition 9.1 running CUDA 11.
I tried:
#ifdef __CUDA_ARCH__
# define DEAL_II_COMPILER_VECTORIZATION_LEVEL 0
#endif
But that does not work.
However, the vector is not in device code, only in the host code.
The error is coming about due to this line:
__m256i avxraw[1];
which is visible in both the host code and device code compilation trajectory.
According to my testing this may be a possible workaround:
$ cat t32.cpp
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
#include <iostream>
typedef char dummy[sizeof(__m256i)];
struct Atom_t {
enum where { device, host};
enum BoolOp {opXor, opOr, opAnd };
public: //TODO make private later
int VarCount;
bool isValid;
union {
uint32_t raw[1];
uint64_t raw64[1];
#ifndef FOO //hide the vectorized datastruct from cuda's view
__m256i avxraw[1];
#else
alignas(32) dummy foo[1];
#endif
};
};
int main(){
std::cout << sizeof(__m256i) << std::endl;
std::cout << sizeof(Atom_t) << std::endl;
}
$ g++ t32.cpp -o t32
$ ./t32
32
64
$ g++ t32.cpp -o t32 -DFOO
$ ./t32
32
64
(Fedora Core 29)
The alignas(32) directive is still probably somewhat fragile if the definition of __m256i changes dramatically. And, clearly, the above is not CUDA code in the exact frame that was presented. It would need to be adapted (e.g. replace #ifndef FOO with #ifndef __CUDA_ARCH__)
I'm not suggesting that this code is correct, defect-free, or suitable for any particular purpose; it is mostly code provided by OP. My objective here is to identify issues that I see and are asked about in the question, and suggest possible ways to address those issues. Use this at your own risk.
Found it!
The problem is not the code in the method, the problem is the presence of the _m256i within view of cuda.
The following patch fixes the issue:
struct Atom_t {
enum where { device, host};
enum BoolOp {opXor, opOr, opAnd };
public: //TODO make private later
int VarCount;
bool isValid;
union {
uint32_t raw[1]; //don't worry about alignment, the compiler will not use aligned read/writes anyway.}
uint64_t raw64[1];
#ifndef __CUDA_ARCH__ //hide the vectorized datastruct from cuda's view
__m256i avxraw[1];
#endif
};
Now that nvcc does not see the vectorized datatype it will stop worrying.

How could I use `kallsyms_lookup_name` function to fix `unknown character` error when loading Linux kernel module?

I'm trying to complete a hooking sample attachment in a program for my uni assignment. The task requires to get a system call sys_rt_sigaction hooked when initiating a loadable module in Linux kernel (I use Ubuntu 18.04 LTS, kernel version is 5.0.0-23-generic). So, the case I'm struggling originates from an error could not insert module <module name>: Unknown symbol in module once I started sudo insmod <my module name>.ko.
After some googling, I see clear this problem arises due to missing sys_call_table export to run inserting as smoothly as well. Following this post, I want to cope that invoking kallsyms_lookup_name call before kicking off init procedure.
There is .c-file which provides with definitions of operations accessible by module (file name is buffer.c):
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/unistd.h>
void * sys_call_table = (void *) kallsyms_lookup_name("sys_call_table");// some wrongness here, but what exactly?
MODULE_LICENSE("GPL");
int (*real_rt_sigaction)(const char * path); // true syscall prototype
static int __init buffer_init_module(void);
static void __exit buffer_exit_module(void);
static int device_open(struct inode *, struct file *); // driver file opening
static int device_release(struct inode *, struct file *); // return of system resource control
static ssize_t device_read(struct file *, char *, size_t, loff_t *); // reading from driver file
static ssize_t device_write(struct file *, const char *, size_t, loff_t *); // writing into driver file
#define DEVICE_NAME "buffer"
#define BUF_LEN 80
// to be called instead
int alter_rt_sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact, size_t sigsetsize) {
printk(KERN_INFO "Syscall function hooked - you've lost control of your experience");
return 0;
}
static int Major;
static int Device_Open = 0;
static int total_open = 1;
static char Buf[BUF_LEN + 1] = "Buffer is empty, add some input\n";
static char *Msg_ptr;
static int Buf_Char = 50;
static int Bytes_Read = 0;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int __init buffer_init_module(void)
{
printk(KERN_INFO
"Device initializing in progress...");
Major = register_chrdev(0, DEVICE_NAME, &fops);
if(Major < 0) {
printk("Major number hasn't been assigned - Driver registration failed\n");
return Major;
}
printk(KERN_INFO "Registration success - device major number: %d\n", Major);
real_rt_sigaction=sys_call_table[__NR_rt_sigaction];
sys_call_table[__NR_rt_sigaction]=alter_rt_sigaction; // hooking implementation
return 0;
}
static void __exit buffer_exit_module(void)
{
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_INFO "Outside the module - exit successfully completed\n");
sys_call_table[__NR_rt_sigaction]=real_rt_sigaction; // original call reset
}
static int device_open(struct inode *inode, struct file *file)
{
if(Device_Open)
return -EBUSY;
Device_Open++;
printk(KERN_INFO "Device file has been accessed %d time(s)\n", total_open++);
Msg_ptr = Buf;
try_module_get(THIS_MODULE);
Bytes_Read = 0;
return 0;
}
static int device_release(struct inode * node, struct file * filep)
{
Device_Open--;
module_put(THIS_MODULE);
printk(KERN_INFO "Device file gets close\n");
return 0;
}
static ssize_t device_read(struct file * filep, char * buffer, size_t len, loff_t * offset)
{
int got_read = Bytes_Read;
if(Bytes_Read >= Buf_Char)
return 0;
while(len && (Bytes_Read < Buf_Char)) {
put_user(Msg_ptr[Bytes_Read], buffer+Bytes_Read);
len--;
Bytes_Read++;
}
return Bytes_Read-got_read;
}
static ssize_t device_write(struct file * filep, const char * buffer, size_t len, loff_t * offset)
{
Buf_Char = 0;
if(Buf_Char >= BUF_LEN) {
return 0;
}
while(len && (Buf_Char < BUF_LEN))
{
get_user(Msg_ptr[Buf_Char], buffer+Buf_Char);
len--;
Buf_Char++;
}
return Buf_Char;
}
module_init(buffer_init_module);
module_exit(buffer_exit_module);
Additively, there is code in Makefile:
obj-m += buffer.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
The painful moment here is an error message initializer element is not constant whenever I was trying to build module via sudo make in my project folder. As I follow the beginner's tutorials and need for some basic insight, it might be highly appreciable to see any help with solution or even some ideas how to handle the same problem more effectively, indeed.

Unknown symbol flush_tlb_all (err 0)

I tried to make a simple kernel module invalidating all tlb entries through user-level ioctl.
Below is my example code [flush_tlb.c]
/*
* flush_tlb.c
*/
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <asm/tlbflush.h>
#include <asm/tlb.h>
#include "flush_tlb.h"
MODULE_LICENSE("GPL");
static long flush_tlb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct flush_tlb_parv_t flush_tlb_parv;
// copy an argument from user-level
if (size != sizeof(struct flush_tlb_parv_t)) {
ret = -EINVAL;
goto out;
}
if (copy_from_user(&flush_tlb_parv, ubuf, sizeof(flush_tlb_parv))) {
ret = -EFAULT;
goto out;
}
if (flush_tlb_parv.addr) {
// Not Implemented
flush_tlb_all();
} else {
flush_tlb_all();
}
out:
return ret;
}
static const struct file_operations flush_tlb_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = flush_tlb_ioctl,
.compat_ioctl = flush_tlb_ioctl,
};
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "flush_tlb",
.fops = &flush_tlb_fops
};
static int __init flush_tlb_init(void)
{
int ret;
ret = misc_register(&binder_miscdev);
return ret;
}
module_init(flush_tlb_init)
static void __exit flush_tlb_exit(void)
{
misc_deregister(&binder_miscdev);
}
module_exit(flush_tlb_exit)
And here is my [Makefile]
obj-m += flush_tlb.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
It is successfully compiled, but when I insert the module by insmod, it fails with following kernel logs.
"flush_tlb: Unknown symbol flush_tlb_all (err 0)"
Also, I checked the /proc/kallsyms that flush_tlb_all exists in the symbol table.
$cat /proc/kallsyms | grep flush_tlb_all
ffffffff81022f90 T xen_flush_tlb_all
ffffffff810274a0 t trace_raw_output_xen_mmu_flush_tlb_all
ffffffff81027af0 t trace_event_raw_event_xen_mmu_flush_tlb_all
ffffffff81028c20 t perf_trace_xen_mmu_flush_tlb_all
ffffffff81072670 t do_flush_tlb_all
ffffffff81072bf0 T flush_tlb_all
ffffffff810792c0 t __flush_tlb_all
ffffffff8107d7cf t __flush_tlb_all
ffffffff81d76570 r __tracepoint_ptr_xen_mmu_flush_tlb_all
ffffffff81d77630 r __tpstrtab_xen_mmu_flush_tlb_all
ffffffff81e231f8 d print_fmt_xen_mmu_flush_tlb_all
ffffffff81e23f20 d trace_event_type_funcs_xen_mmu_flush_tlb_all
ffffffff81e24780 d event_xen_mmu_flush_tlb_all
ffffffff81f04720 d event_class_xen_mmu_flush_tlb_all
ffffffff81f103a0 D __tracepoint_xen_mmu_flush_tlb_all
ffffffff81f6772c t trace_event_define_fields_xen_mmu_flush_tlb_all
ffffffff8208c080 t __event_xen_mmu_flush_tlb_all
How can I fix it?
Thanks.

KASAN complains when calling copy_from/to_user

We are developing a linux driver, and noticed KASAN complains when I read/write the created device file.
The minimal example is listed as below (so not well designed).
It creates file /dev/test_ctl and enables read/write/ioctl.
We compiled a 4.6.2 kernel with KASAN enabled and this code in updated Fedora.
After modprobe the module, I tried to read(cat)/write(echo foo > ) and called ioctl, all got BUG: KASAN: user-memory-access on address ... .... I expected these operations runs without any warning.
According to the pr_info, I noticed the behavior is caused by copy_to/from_user functions.
How can we get rid of this noise since we use KASAN for memory related runtime checks.
#define pr_fmt(fmt) "test dev : " fmt
#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm-generic/uaccess.h>
#include <asm-generic/ioctl.h>
#include <linux/spinlock.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FOO");
MODULE_DESCRIPTION("BAR");
#define LEN 1024
#define IOCTL_READ _IOR('t', 0xD0, u8[LEN])
#define IOCTL_WRITE _IOW('t', 0xD1, u8[LEN])
static u8 buf[LEN];
static dev_t major;
static struct class *class;
static struct cdev cdev;
static struct device *cdevice;
static long test_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
long err;
void __user *ptr = (void __user *)arg;
pr_info("ioctl: cmd: %08x, arg: %p, local: %p\n", cmd, ptr, buf);
switch (cmd) {
case IOCTL_READ:
pr_info("ioctl/r: calling copy_to_user\n");
if (copy_to_user(ptr, buf, LEN)) {
pr_info("ioctl/r: failed to copy to user\n");
err = -EFAULT;
} else {
pr_info("ioctl/r: buffer copied, val: %8ph\n", buf);
err = 0;
}
break;
case IOCTL_WRITE:
pr_info("ioctl/r: calling copy_from_user\n");
if (copy_from_user(buf, ptr, LEN)) {
pr_info("ioctl/w: failed to copy from user\n");
err = -EFAULT;
} else {
pr_info("ioctl/w: buffer copied, val: %8ph\n", buf);
err = 0;
}
break;
default:
pr_info("ioctl: invalid command\n");
err = -EINVAL;
break;
}
return err;
}
static int test_open(struct inode *inode, struct file *file)
{
return 0;
}
static int test_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t test_read(struct file *filep,
char __user *ptr, size_t len, loff_t *offset)
{
ssize_t r;
if (*offset) {
return 0;
}
if (len > LEN) {
len = LEN;
}
*offset += len;
pr_info("calling copy_to_user\n");
r = copy_to_user(ptr, buf, len) ? -EFAULT : len;
pr_info("called copy_to_user\n");
return r;
}
static ssize_t test_write(struct file *filep,
const char __user *ptr, size_t len, loff_t *offset)
{
ssize_t r;
if (*offset) {
return -EINVAL;
}
if (len > LEN) {
len = LEN;
}
*offset += len;
pr_info("calling copy_from_user\n");
r = copy_from_user(buf, ptr, len) ? -EFAULT : len;
pr_info("called copy_from_user\n");
return r;
}
static const struct file_operations cdev_ops = {
.owner = THIS_MODULE,
.unlocked_ioctl = test_ioctl,
.open = test_open,
.release = test_release,
.read = test_read,
.write = test_write,
};
static int test_init(void)
{
int rc;
pr_info("test device initing\n");
rc = alloc_chrdev_region(&major, 0, 1, "test");
if (rc) {
goto fail_alloc_chrdev_region;
}
pr_info("major assigned: %d\n", (int)MAJOR(major));
class = class_create(THIS_MODULE, "test_ctl");
if (IS_ERR(class)) {
pr_err("failed to create class\n");
rc = PTR_RET(class);
goto fail_create_class;
}
cdev_init(&cdev, &cdev_ops);
cdev.owner = THIS_MODULE;
rc = cdev_add(&cdev, MKDEV(MAJOR(major), 0), 1);
if (rc) {
pr_info("failed to add char dev\n");
goto fail_cdev_add;
}
cdevice = device_create(class, NULL, MKDEV(MAJOR(major), 0), NULL,
"test_ctl");
if (IS_ERR(cdevice)) {
pr_err("failed to create /dev/ file\n");
rc = PTR_RET(cdevice);
goto fail_device_create;
}
pr_info("driver initialized\n");
return 0;
device_destroy(class, MKDEV(major, 0));
fail_device_create:
cdev_del(&cdev);
fail_cdev_add:
class_destroy(class);
fail_create_class:
unregister_chrdev_region(major, 1);
fail_alloc_chrdev_region:
return rc;
}
module_init(test_init);
Here is the kernel message during od /dev/test_ctl
[18088.583185] test dev : called copy_to_user
[18117.378665] test dev : ioctl: cmd: 00005401, arg: 00007ffeb2303070, local: ffffffffa018aba0
[18117.380954] test dev : ioctl: invalid command
[18117.386294] test dev : calling copy_to_user
[18117.388772] ==================================================================
[18117.390903] BUG: KASAN: user-memory-access on address 00007f52831a8000
[18117.392150] Write of size 1024 by task od/2057
[18117.393305] CPU: 1 PID: 2057 Comm: od Tainted: G B O 4.6.2-kasan-outline #1
[18117.395448] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[18117.396655] ffff880009cf8000 00000000da76c32b ffff88000a2efbc8 ffffffff816e1398
[18117.399220] 0000000000000400 ffff88000a2efc60 ffff88000a2efc50 ffffffff8134fe46
[18117.401765] 0000000000000246 ffffffffa0189140 0000000000000292 ffff88000a2efc00
[18117.404304] Call Trace:
[18117.405375] [<ffffffff816e1398>] dump_stack+0x85/0xcd
[18117.406550] [<ffffffff8134fe46>] kasan_report_error+0x456/0x560
[18117.407777] [<ffffffff81197896>] ? debug_lockdep_rcu_enabled+0x26/0x40
[18117.409039] [<ffffffff813504e8>] kasan_report+0x58/0x60
[18117.410222] [<ffffffff8134f498>] ? memcpy+0x28/0x40
[18117.411394] [<ffffffff8134f08d>] __asan_storeN+0x12d/0x180
[18117.412592] [<ffffffff8134f498>] memcpy+0x28/0x40
[18117.413766] [<ffffffffa0188019>] __copy_to_user+0x9/0x10 [test_drv]
[18117.415010] [<ffffffffa0188132>] test_read+0x72/0xa0 [test_drv]
[18117.416233] [<ffffffff8138529d>] __vfs_read+0xdd/0x260
[18117.417419] [<ffffffff813851c0>] ? vfs_iter_write+0x190/0x190
[18117.418644] [<ffffffff813f7140>] ? __fsnotify_update_child_dentry_flags.part.1+0x160/0x160
[18117.442467] [<ffffffff812e0117>] ? vm_mmap_pgoff+0x167/0x1a0
[18117.443686] [<ffffffff8116ff18>] ? up_write+0x28/0x50
[18117.444874] [<ffffffff812e0117>] ? vm_mmap_pgoff+0x167/0x1a0
[18117.446093] [<ffffffff81636dd5>] ? security_file_permission+0xd5/0x100
[18117.447344] [<ffffffff81386bb7>] vfs_read+0xb7/0x1a0
[18117.448536] [<ffffffff81388dba>] SyS_read+0xba/0x150
[18117.449713] [<ffffffff81388d00>] ? vfs_copy_file_range+0x370/0x370
[18117.450945] [<ffffffff811776c6>] ? trace_hardirqs_on_caller+0x16/0x290
[18117.452193] [<ffffffff8100401b>] ? trace_hardirqs_on_thunk+0x1b/0x1d
[18117.453441] [<ffffffff81b386fc>] entry_SYSCALL_64_fastpath+0x1f/0xbd
[18117.454689] [<ffffffff811717b6>] ? trace_hardirqs_off_caller+0x16/0x120
[18117.455943] ==================================================================
[18117.462008] test dev : called copy_to_user
When calling echo 1 > /dev/test_ctl, I got following kernel message:
[18212.023598] test dev : calling copy_from_user
[18212.024844] ==================================================================
[18212.027020] BUG: KASAN: user-memory-access on address 00007f31bf34f000
[18212.028272] Read of size 2 by task bash/1982
[18212.029425] CPU: 1 PID: 1982 Comm: bash Tainted: G B O 4.6.2-kasan-outline #1
[18212.031585] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[18212.032904] ffff8800306e0000 000000003803bec2 ffff88000a2dfbc0 ffffffff816e1398
[18212.035569] 0000000000000002 ffff88000a2dfc58 ffff88000a2dfc48 ffffffff8134fe46
[18212.038169] 0000000000000246 ffffffffa0189040 0000000000000286 ffff88000a2dfbf8
[18212.040760] Call Trace:
[18212.041835] [<ffffffff816e1398>] dump_stack+0x85/0xcd
[18212.043032] [<ffffffff8134fe46>] kasan_report_error+0x456/0x560
[18212.044276] [<ffffffff81197896>] ? debug_lockdep_rcu_enabled+0x26/0x40
[18212.045538] [<ffffffff813504e8>] kasan_report+0x58/0x60
[18212.046742] [<ffffffff8134f48d>] ? memcpy+0x1d/0x40
[18212.047944] [<ffffffff8134ef0a>] __asan_loadN+0x12a/0x180
[18212.049155] [<ffffffff8134f48d>] memcpy+0x1d/0x40
[18212.050340] [<ffffffffa0188019>] __copy_to_user+0x9/0x10 [test_drv]
[18212.051593] [<ffffffffa0188097>] test_write+0x77/0xa0 [test_drv]
[18212.052840] [<ffffffff813854fd>] __vfs_write+0xdd/0x260
[18212.054040] [<ffffffff81385420>] ? __vfs_read+0x260/0x260
[18212.055252] [<ffffffff81300b40>] ? __pmd_alloc+0x250/0x250
[18212.056464] [<ffffffff813b9595>] ? __fd_install+0x5/0x3f0
[18212.057736] [<ffffffff813b92ac>] ? __alloc_fd+0x3c/0x2b0
[18212.058952] [<ffffffff81197896>] ? debug_lockdep_rcu_enabled+0x26/0x40
[18212.060220] [<ffffffff81197896>] ? debug_lockdep_rcu_enabled+0x26/0x40
[18212.061488] [<ffffffff81636d68>] ? security_file_permission+0x68/0x100
[18212.062757] [<ffffffff81386d96>] vfs_write+0xf6/0x260
[18212.063959] [<ffffffff81388f0a>] SyS_write+0xba/0x150
[18212.065165] [<ffffffff81388e50>] ? SyS_read+0x150/0x150
[18212.066382] [<ffffffff811776c6>] ? trace_hardirqs_on_caller+0x16/0x290
[18212.067666] [<ffffffff8100401b>] ? trace_hardirqs_on_thunk+0x1b/0x1d
[18212.068933] [<ffffffff81b386fc>] entry_SYSCALL_64_fastpath+0x1f/0xbd
[18212.070199] [<ffffffff811717b6>] ? trace_hardirqs_off_caller+0x16/0x120
[18212.071470] ==================================================================
[18212.073790] test dev : called copy_from_user
So KASAN complains about user-space accesses. I don't know why. But #include <asm-generic/uaccess.h> looks suspicious: outer code (like modules) should rarely include asm-specific headers. Use standard #include <linux/uaccess.h>. BTW, for x86 asm-generic version of uaccess.h is never used: its asm/uaccess.h header defines user access functions manually. It could be a reason of your problem. The same is true for asm-generic/ioctl.h inclusion. – Tsyvarev
Thank you for your help. I used linux/uaccess.h instead of asm-generic/uaccess.h and this behavior is not happening again. – OstCollector

How my custom module on linux 3.2.28 can make a call to print_cpu_info?

I'm going to implement my custom module in which information for CPU is printed using print_cpu_info(). In order to call print_cpu_info(), I have included the needed header file, but it doesn't work. Here is my module.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/alternative.h>
#include <asm/bugs.h>
#include <asm/processor.h>
#include <asm/mtrr.h>
#include <asm/cacheflush.h>
extern struct cpuinfo_x86 boot_cpu_data;
int cpuinfox86_init(void)
{
print_cpu_info(&boot_cpu_data);
return 0;
}
void cpuinfox86_exit(void)
{
printk("good bye cpu\n");
}
module_init(cpuinfox86_init);
module_exit(cpuinfox86_exit);
MODULE_LICENSE("GPL");
After compiling this module, I get
make -C /lib/modules/3.2.28-2009720166/build SUBDIRS=/home/tracking/1031_oslab modules
make[1]: Entering directory `/usr/src/linux-3.2.28'
CC [M] /home/tracking/1031_oslab/module.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: "print_cpu_info" [/home/tracking/1031_oslab/module.ko] undefined!
CC /home/tracking/1031_oslab/module.mod.o
LD [M] /home/tracking/1031_oslab/module.ko
make[1]: Leaving directory `/usr/src/linux-3.2.28'
any idea?
"print_cpu_info" is not exported symbol, so it can not be used by modules. However, you can use "kallsyms_lookup_name", which is exported, to get the address of "print_cpu_info" and execute the function call using a function pointer.
static void* find_sym( const char *sym ) { // find address kernel symbol sym
static unsigned long faddr = 0; // static !!!
// ----------- nested functions are a GCC extension ---------
int symb_fn( void* data, const char* sym, struct module* mod, unsigned long addr ) {
if( 0 == strcmp( (char*)data, sym ) ) {
faddr = addr;
return 1;
}
else return 0;
};
// --------------------------------------------------------
kallsyms_on_each_symbol( symb_fn, (void*)sym );
return (void*)faddr;
}
static void (*cpuInfo)(struct cpuinfo_x86 *);
How to use it:
unsigned int cpu = 0;
struct cpuinfo_x86 *c;
cpuInfo = find_sym("print_cpu_info");
for_each_online_cpu(cpu)
{
c = &cpu_data(cpu);
cpuInfo(c);
}

Resources