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.
Related
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.
How can i load module2.ko in kernel before module1.ko. module2.ko is
dependent on module1.ko, because module1.ko is having the definition
of function and module2.ko have its calling. I have inserted a condition in module2.c to check if the module1 is loaded in kernel or not. If its loaded it would perform the function, otherwise it should print an error message. I have mentioned my code below.
module1.c:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/fs.h> // Needed by filp
#include <asm/uaccess.h>
MODULE_LICENSE("Test");
int mul(void)
{
printk("Running module1.c\n");
int a=2,b=620;
int ans = 0;
ans = a * b;
printk("The value sent to module1.c = %d\n", ans);
return ans;
}
EXPORT_SYMBOL(mul);
static int start(void)
{
return 0;
}
static void end(void)
{
printk(KERN_INFO "Goodbye.\n");
}
module_init(start);
module_exit(end);
module2.c:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/fs.h> // Needed by filp
MODULE_LICENSE("Test");
MODULE_AUTHOR("Ali");
MODULE_DESCRIPTION("Making two dependent Modules");
MODULE_VERSION("0.1");
void display(void){
printk("Running module2.c\n");
}
static int hello_start(void)
{
int res = 0;
display();
int fd;
fd = filp_open("/sys/module/module1", O_RDONLY, 0);
printk(KERN_INFO "This is flag %d\n",fd);
if(fd > 0)
{
printk(KERN_INFO "Module not exists in Kernel!!.\n");
return 0;
}
else
{
extern int mul(void);
printk(KERN_ALERT "Module exists in Kernel!!.\n");
printk(KERN_ALERT"The value recieved from module1.c = %d\n", res=mul());
}
return 0;
}
static void hello_end(void)
{
printk(KERN_INFO "Goodbye123.\n");
}
module_init(hello_start);
module_exit(hello_end);
Makefile:
obj-m = module1.o module2.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
In the Linux kernel the opened file is indicated by struct file, and the file descriptor table contains a pointers which is point to struct file. f_count is an important member in the struct file. f_count, which means Reference Count. The system call dup() and fork() make other file descriptor point to same struct file.
As shown in the picture (sorry, my reputation is too low, the picture can not be uploaded), fd1 and fd2 point to the struct file, so the Reference Count is equal to 2, thus f_count = 2.
My question is how can i get the value of the f_count by programming.
UPDATE:ok,In order to make myself more clear i will show my code, both the char device driver,Makefile and my application.:D
deviceDriver.c
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/fs.h"
#include "linux/init.h"
#include "linux/types.h"
#include "linux/errno.h"
#include "linux/uaccess.h"
#include "linux/kdev_t.h"
#define MAX_SIZE 1024
static int my_open(struct inode *inode, struct file *file);
static int my_release(struct inode *inode, struct file *file);
static ssize_t my_read(struct file *file, char __user *user, size_t t, loff_t *f);
static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f);
static char message[MAX_SIZE] = "-------congratulations--------!";
static int device_num = 0;//device number
static int counter = 0;
static int mutex = 0;
static char* devName = "myDevice";//device name
struct file_operations pStruct =
{ open:my_open, release:my_release, read:my_read, write:my_write, };
/* regist the module */
int init_module()
{
int ret;
/ **/
ret = register_chrdev(0, devName, &pStruct);
if (ret < 0)
{
printk("regist failure!\n");
return -1;
}
else
{
printk("the device has been registered!\n");
device_num = ret;
printk("<1>the virtual device's major number %d.\n", device_num);
printk("<1>Or you can see it by using\n");
printk("<1>------more /proc/devices-------\n");
printk("<1>To talk to the driver,create a dev file with\n");
printk("<1>------'mknod /dev/myDevice c %d 0'-------\n", device_num);
printk("<1>Use \"rmmode\" to remove the module\n");
return 0;
}
}
void cleanup_module()
{
unregister_chrdev(device_num, devName);
printk("unregister it success!\n");
}
static int my_open(struct inode *inode, struct file *file)
{
if(mutex)
return -EBUSY;
mutex = 1;//lock
printk("<1>main device : %d\n", MAJOR(inode->i_rdev));
printk("<1>slave device : %d\n", MINOR(inode->i_rdev));
printk("<1>%d times to call the device\n", ++counter);
try_module_get(THIS_MODULE);
return 0;
}
/* release */
static int my_release(struct inode *inode, struct file *file)
{
printk("Device released!\n");
module_put(THIS_MODULE);
mutex = 0;//unlock
return 0;
}
static ssize_t my_read(struct file *file, char __user *user, size_t t, loff_t *f)
{
if(copy_to_user(user,message,sizeof(message)))
{
return -EFAULT;
}
return sizeof(message);
}
static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f)
{
if(copy_from_user(message,user,sizeof(message)))
{
return -EFAULT;
}
return sizeof(message);
}
Makefile:
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifeq ($(KERNELRELEASE),)
# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
# called from kernel build system: just declare what our modules are
obj-m := devDrv.o
endif
application.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define MAX_SIZE 1024
int main(void)
{
int fd;
char buf[MAX_SIZE];
char get[MAX_SIZE];
char devName[20], dir[50] = "/dev/";
system("ls /dev/");
printf("Please input the device's name you wanna to use :");
gets(devName);
strcat(dir, devName);
fd = open(dir, O_RDWR | O_NONBLOCK);
if (fd != -1)
{
read(fd, buf, sizeof(buf));
printf("The device was inited with a string : %s\n", buf);
/* test fot writing */
printf("Please input a string :\n");
gets(get);
write(fd, get, sizeof(get));
/* test for reading */
read(fd, buf, sizeof(buf));
system("dmesg");
printf("\nThe string in the device now is : %s\n", buf);
close(fd);
return 0;
}
else
{
printf("Device open failed\n");
return -1;
}
}
Any idea to get the struct file's(char device file) f_count? Is it poassible get it by the way of printk?
You should divide reference counter to module from other module and from user-space application. lsmod show how many modules use your module.
sctp 247143 4
libcrc32c 12644 1 sctp
It is impossible load sctp without libcrc32c because sctp use exported function from libcrc32 to calculate control sum for packets.
The reference counter itself is embedded in the module data structure and can be obtained with the function uint module_refcount(struct module* module);
You can use:
printk("Module reference counter: %d\n", (int)module_refcount(THIS_MODULE));
THIS_MODULE it is a reference to current loadable module (for build-in module it is NULL) inside .owner field (inside struct file_operations).
If there is a need manually modify module's counter use:
int try_module_get(struct module* module);
void module_put(struct module* module);
If module unloaded it will return false. You also can move thru all modules. Modules linked via list.
File opening inside kernel it is bad idea. Inside kernel you can get access to inode. Try read man pages for dup and fork. In you system you can investigate lsof tools.
I wrote a small device driver for a "coin" device. I create an entry in /drivers/char/Kconfig
and corresponding Makefile, then selected built-in option in menuconfig. The kernel compiled fine (built-in.o file was created). But I still can't access the device (/dev/coin was not created) and there was no entry under /proc/devices.
Please help!!
I am cross-compiling for powerpc
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/random.h>
#include <linux/debugfs.h>
#include <linux/init.h>
#define DEVNAME "coin"
#define LEN 20
enum values {HEAD, TAIL};
struct dentry *dir, *file;
int file_value;
int stats[2] = {0, 0};
char *msg[2] = {"head\n", "tail\n"};
static int major;
static struct class *class_coin;
static struct device *dev_coin;
static ssize_t r_coin(struct file *f, char __user *b,
size_t cnt, loff_t *lf)
{
char *ret;
u32 value = random32() % 2;
ret = msg[value];
stats[value]++;
return simple_read_from_buffer(b, cnt,
lf, ret,
strlen(ret));
}
static struct file_operations fops = { .read = r_coin };
#ifdef CONFIG_COIN_STAT
static ssize_t r_stat(struct file *f, char __user *b,
size_t cnt, loff_t *lf)
{
char buf[LEN];
snprintf(buf, LEN, "head=%d tail=%d\n",
stats[HEAD], stats[TAIL]);
return simple_read_from_buffer(b, cnt,
lf, buf,
strlen(buf));
}
static struct file_operations fstat = { .read = r_stat };
#endif
static int __init coin_init(void)
{
void *ptr_err;
major = register_chrdev(0, DEVNAME, &fops);
if (major < 0)
return major;
class_coin = class_create(THIS_MODULE,
DEVNAME);
if (IS_ERR(class_coin)) {
ptr_err = class_coin;
goto err_class;
}
dev_coin = device_create(class_coin, NULL,
MKDEV(major, 0),
NULL, DEVNAME);
if (IS_ERR(dev_coin))
goto err_dev;
#ifdef CONFIG_COIN_STAT
dir = debugfs_create_dir("coin", NULL);
file = debugfs_create_file("stats", 0644,
dir, &file_value,
&fstat);
#endif
return 0;
err_dev:
ptr_err = class_coin;
class_destroy(class_coin);
err_class:
unregister_chrdev(major, DEVNAME);
return PTR_ERR(ptr_err);
}
static void __exit coin_exit(void)
{
#ifdef CONFIG_COIN_STAT
debugfs_remove(file);
debugfs_remove(dir);
#endif
device_destroy(class_coin, MKDEV(major, 0));
class_destroy(class_coin);
return unregister_chrdev(major, DEVNAME);
}
module_init(coin_init);
module_exit(coin_exit);
What if you manually insert module into kernel using insmod? Does it work? Any messages in dmesg?
As I remember entries in /dev (/dev/coin) should be created manually using mknod, but you need major number of registered device. Just printk it after register_chrdev().
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);
}