Kernel Module to reboot linux - kernel-module

How can I EXPORT_SYMBOL in my dynamic module to reboot my linux system.
EXPORT_SYMBOL(register_restart_handler);
EXPORT_SYMBOL(unregister_restart_handler);
EXPORT_SYMBOL_GPL(kernel_restart);
how to use struct notifier_block and char *cmd in void kernel_restart(char *cmd) ?

I have Found the solution just add kernel_restart(NULL). No need to register handler.
int init_module(void)
{
mdelay(5000);
kernel_restart(NULL);
return 0;
}

Related

How to load a module (not a driver) when a USB device is plugged in

#include<linux/init.h>
#include<linux/module.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
/*
* Version information
*/
#define DRIVER_VERSION ""
#define DRIVER_DESC "Hello World module"
#define DRIVER_LICENSE "GPL"
MODULE_LICENSE(DRIVER_LICENSE);
MODULE_AUTHOR(DRIVER_AUTHOR);
static void __exit hello_world_exit(void)
{
pr_debug("Bye!\n");
}
static int __init hello_world_init(void)
{
pr_debug("Hello, USB!");
return 0;
}
static struct usb_device_id usb_kbd_id_table[] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_KEYBOARD) },
{}
};
MODULE_DEVICE_TABLE(usb, usb_kbd_id_table);
module_init(hello_world_init);
module_exit(hello_world_exit);
How do I make the kernel load this module load when a USB mouse is plugged in (using the userspace hotplug tools) ? Right now, I have put the hello_world.ko file in /lib/modules/$(uname -r) and run depmod -a.
In modern Linux the functionality for loading drivers/modules (or invoking any other commands) whenever new hardware is detected is handled by udev. You will have to write a udev rule for your device that will instruct the kernel to load your module when your device has been detected and the corresponding event has occurred. Read more about it here.

Get Linux system information in C

I have to check Linux system information. I can execute system commands in C, but doing so I create a new process for every one, which is pretty expensive. I was wondering if there is a way to obtain system information without being forced to execute a shell command. I've been looking around for a while and I found nothing. Actually, I'm not even sure if it's more convenient to execute commands via Bash calling them from my C program or find a way to accomplish the tasks using only C.
Linux exposes a lot of information under /proc. You can read the data from there. For example, fopen the file at /proc/cpuinfo and read its contents.
A presumably less known (and more complicated) way to do that, is that you can also use the api interface to sysctl. To use it under Linux, you need to #include <unistd.h>, #include <linux/sysctl.h>. A code example of that is available in the man page:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/sysctl.h>
int _sysctl(struct __sysctl_args *args );
#define OSNAMESZ 100
int
main(void)
{
struct __sysctl_args args;
char osname[OSNAMESZ];
size_t osnamelth;
int name[] = { CTL_KERN, KERN_OSTYPE };
memset(&args, 0, sizeof(struct __sysctl_args));
args.name = name;
args.nlen = sizeof(name)/sizeof(name[0]);
args.oldval = osname;
args.oldlenp = &osnamelth;
osnamelth = sizeof(osname);
if (syscall(SYS__sysctl, &args) == -1) {
perror("_sysctl");
exit(EXIT_FAILURE);
}
printf("This machine is running %*s\n", osnamelth, osname);
exit(EXIT_SUCCESS);
}
However, the man page linked also notes:
Glibc does not provide a wrapper for this system call; call it using
syscall(2). Or rather... don't call it: use of this system call has
long been discouraged, and it is so unloved that it is likely to
disappear in a future kernel version. Since Linux 2.6.24, uses of this
system call result in warnings in the kernel log. Remove it from your
programs now; use the /proc/sys interface instead.
This system call is available only if the kernel was configured with
the CONFIG_SYSCTL_SYSCALL option.
Please keep in mind that anything you can do with sysctl(), you can also just read() from /proc/sys. Also note that I do understand that the usefulness of that syscall is questionable, I just put it here for reference.
You can also use the sys/utsname.h header file to get the kernel version, hostname, operating system, machine hardware name, etc. More about sys/utsname.h is here. This is an example of getting the current kernel release.
#include <stdio.h> // I/O
#include <sys/utsname.h>
int main(int argc, char const *argv[])
{
struct utsname buff;
printf("Kernel Release = %s\n", buff.release); // kernel release
return 0;
}
This is the same as using the uname command. You can also use the -a option which stands for all information.
uname -r # -r stands for kernel release

How to get data segment of Linux kernel from LKM

I'm writing a kernel module which involves the tasklist_lock, __bss_start.
These symbols are not exported. I'm pretty sure even if not exported, we can access the symbols from text sections using kernsym_lookup_name()
Reference How my custom module on linux 3.2.28 can make a call to print_cpu_info?
$ vim System.map
...
80017be0 T register_undef_hook
80017c28 T unregister_undef_hook
80017c70 T do_unexp_fiq
...
806eb000 D mmlist_lock
806eb040 D tasklist_lock
806eb080 d softirq_vec
....
T represents text symbol.
D and d represents data segment symbol.
I'm able to access register_undef_hook() and unregister_undef_hook() using kallsyms_lookup_name().
But not tasklist_lock.
Please share your knowledge to access tasklist_lock from kernel module(LKM).
See this noble post
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/string.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Access non-exported symbols");
MODULE_AUTHOR("Stephen Zhang");
static int __init lkm_init(void)
{
char *sym_name = "__bss_start";
unsigned long sym_addr = kallsyms_lookup_name(sym_name);
char filename[256];
strncpy(filename, (char *)sym_addr, 255);
printk(KERN_INFO "[%s] %s (0x%lx): %s\n", __this_module.name, sym_name, sym_addr, filename);
return 0;
}
static void __exit lkm_exit(void)
{
}
module_init(lkm_init);
module_exit(lkm_exit);

System call interception in linux-kernel module (kernel 3.5)

I need to replace a standard system call (e.g. SYS_mkdir) with my own implementation.
As I read in some sources, including this question on Stackoverflow, the sys_call_table is not exported symbol since kernel version 2.6.
I tried the following code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <asm/syscall.h>
int (*orig_mkdir)(const char *path);
....
int init_module(void)
{
orig_mkdir=sys_call_table[__NR_mkdir];
sys_call_table[__NR_mkdir]=own_mkdir;
printk("sys_mkdir replaced\n");
return(0);
}
....
Unfortunately I receive compiler error:
error: assignment of read-only location ‘sys_call_table[83]’
How can I replace the system call?
EDIT: Is there any solution without kernel patching?
this works for me.
See
Linux Kernel: System call hooking example
and
https://bbs.archlinux.org/viewtopic.php?id=139406
asmlinkage long (*ref_sys_open)(const char __user *filename, int flags, umode_t mode);
asmlinkage long new_sys_open(const char __user *filename, int flags, umode_t mode)
{
return ref_sys_open(filename, flags, mode);
}
static unsigned long **aquire_sys_call_table(void)
{
unsigned long int offset = PAGE_OFFSET;
unsigned long **sct;
while (offset < ULLONG_MAX) {
sct = (unsigned long **)offset;
if (sct[__NR_close] == (unsigned long *) sys_close)
return sct;
offset += sizeof(void *);
}
print("Getting syscall table failed. :(");
return NULL;
}
// Crazy copypasted asm stuff. Could use linux function as well...
// but this works and will work in the future they say.
static void disable_page_protection(void)
{
unsigned long value;
asm volatile("mov %%cr0, %0" : "=r" (value));
if(!(value & 0x00010000))
return;
asm volatile("mov %0, %%cr0" : : "r" (value & ~0x00010000));
}
static void enable_page_protection(void)
{
unsigned long value;
asm volatile("mov %%cr0, %0" : "=r" (value));
if((value & 0x00010000))
return;
asm volatile("mov %0, %%cr0" : : "r" (value | 0x00010000));
}
static int __init rootkit_start(void)
{
//Hide me
print("loaded");
if(!(sys_call_table = aquire_sys_call_table()))
return -1;
disable_page_protection();
{
ref_sys_open = (void *)sys_call_table[__NR_open];
sys_call_table[__NR_open] = (unsigned long *)new_sys_open;
}
enable_page_protection();
return 0;
}
static void __exit rootkit_end(void)
{
print("exiting");
if(!sys_call_table) {
return;
}
disable_page_protection();
{
sys_call_table[__NR_open] = (unsigned long *)ref_sys_open;
}
enable_page_protection();
}
Yes there is a solution without patching/rebuilding the kernel. Use the Kprobes infrastructure (or SystemTap).
This will allow you to place "probes" (functions) at any point(s) within the kernel, using a kernel module.
Doing similar stuff by modifying the sys_call_table is now prevented (it's read-only) & is considered a dirty hack! Kprobes/Jprobes/etc are a "clean" way to do so..Also, the documentation and samples provided in the kernel source tree is excellent (look under the kernel src tree- Documentation/kprobes.txt).
The problem is caused due to the fact that sys_call_table is read only. In order to avoid the error, before manipulating the sys_call_table, you have to make it writable as well. The kernel provides a function to achieve it. And that function is given as set_mem_rw().
Just add the below code snippet before manipulating the sys_call_table
set_mem_rw((long unsigned int)sys_call_table,1);
In the exit function of the kernel module,please do not forget to revert back the sys_call_table back to read only.It can be achieved as below.
set_mem_ro((long unsigned int)sys_call_table,1);
First, you need to determine the location of sys_call_table. See here.
Before writing into the just located system table, you have to make its memory pages writable. For that check here and if that doesn't work, try this.
Use LSM infrustructure.
Look at LSM hooks path_mkdir or inode_mkdir for details. One question that needs to be solved is how to register your own LSM module while the system don't allow it explicitly. See the answer for details here:
How can I implement my own hook function with LSM?

Sometimes, LD_PRELOAD in HPUX and Solaris cannot take effect

I get some problem about LD_PRELOAD.
When I use LD_PRELOAD in HPUX and Solaris, I found that I cannot attach my open64/open/creat64/creat function in /usr/bin/touch, but my unlink can take effect in /usr/bin/rm, why?
I have do a simple test:
int open(int fd, int flag, mode_t mode)
{
return -1;
}
int open64(int fd, int flag, mode_t mode)
{
return -1;
}
int creat(int fd, mode_t mode)
{
return -1;
}
int creat64(int fd, mode_t mode)
{
return -1;
}
when i do this, i found : normally, i cannot open file, but touch can do it!
why!i was puzzled by this for long time.
who can help me.thx
at last, sorry for my poor English
i think your function signature is wrong. (int instead of char *)
on my system i see the following signature:
grep -w creat /usr/include/*
/usr/include/fcntl.h:#define creat64 creat
/usr/include/fcntl.h:extern int creat(const char *, mode_t);
grep -w open /usr/include/*
/usr/include/fcntl.h:#define open64 open
/usr/include/fcntl.h:extern int open(const char *, int, ...);

Resources