Whether UMH_NO_WAIT in call_usermodehelper() is working? - c

I am doubtful whether UMH_NO_WAIT option in call_usermodehelper() is working, or I am missing something.
This is with reference to the following thread,
Kernel module periodically calling user space program
#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/jiffies.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/hrtimer.h>
#include <linux/sched.h>
#include <linux/delay.h>
#define TIME_PERIOD 5000000000
static struct hrtimer hr_timer;
static ktime_t ktime_period_ns;
static enum hrtimer_restart timer_callback(struct hrtimer *timer){
char userprog[] = "test.sh";
char *argv[] = {userprog, "2", NULL };
char *envp[] = {"HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
printk("\n Timer is running");
hrtimer_forward_now(&hr_timer, ktime_period_ns);
printk("callmodule: %s\n", userprog);
call_usermodehelper(userprog, argv, envp, UMH_NO_WAIT);
return HRTIMER_RESTART;
}
static int __init timer_init() {
ktime_period_ns= ktime_set( 0, TIME_PERIOD);
hrtimer_init ( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
hr_timer.function = timer_callback;
hrtimer_start( &hr_timer, ktime_period_ns, HRTIMER_MODE_REL );
return 0;
}
static int __exit timer_exit(){
int cancelled = hrtimer_cancel(&hr_timer);
if (cancelled)
printk(KERN_ERR "Timer is still running\n");
else
printk(KERN_ERR "Timer is cancelled\n");
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
I think because of the call_usermodehelper() call, the system hangs.Because, at the time of call_usermodehelper() function call only the system freezes. So, I have tried with the option UMH_NO_WAIT, so that the kernel code will not wait for the user process to execute.Then also the system hangs.kindly check www.kernel.org/doc/htmldocs/kernel-api/API-call-usermodehelper.html

Related

How to read file from kernel

I want to read file from kernel module which contains some parameters
I used the following source code
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/fs.h> // Needed by filp
#include <linux/rbtree.h>
#include <linux/time.h>
#include <linux/atomic.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/inetdevice.h>
#include <linux/if_ether.h>
int init_module(void)
{
// Create variables
struct file *f;
char buf[128];
mm_segment_t fs;
int i;
unsigned long long offset = 0;
// Init the buffer with 0
for(i=0;i<128;i++)
buf[i] = 0;
// To see in /var/log/messages that the module is operating
// I am using Fedora and for the test I have chosen following file
// Obviously it is much smaller than the 128 bytes, but hell with it =)
f = filp_open("/etc/lsb-release", O_RDONLY, 0);
if(f == NULL)
printk(KERN_ALERT "filp_open error!!.\n");
else{
// Get current segment descriptor
fs = get_fs();
// Set segment descriptor associated to kernel space
set_fs(get_ds());
// Read the file
f->f_op->read(f, buf, 128, &f->f_pos);
// Restore segment descriptor
set_fs(fs);
// See what we read from file
printk(KERN_INFO "buf:%s\n",buf);
}
filp_close(f,NULL);
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "My module is unloaded\n");
}
But this function crash. I debug it and I found that f->f_op->read is NULL
My kernel version is 4.15 and my ubuntu is 16
What I am missing?
Why f->f_op->read is NULL ?
How to read some parameter from user space in the load of module ? I think better to use file. If so, How to read file in kernel ?

fail to scan a chain of task_struct

I am trying to get a list of all PIDs in a kernel module without useful APIs for some reason.
The code is here. I tried to scan all existing task_struct objects connected with sibling/children member in struct task_struct.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init_task.h>
MODULE_LICENSE("Dual BSD/GPL");
#define MODNAME "list_pid"
#define MINOR_COUNT 1
static void printk_pid_children(struct task_struct *parent_ts){
struct task_struct *fst = container_of(parent_ts->children.next, struct task_struct, sibling);
struct task_struct *t = fst;
if(fst != parent_ts){
do {
printk("%d,", t->tgid);
printk_pid_children(t);
t = list_next_entry(t, sibling);
} while(t != fst);
}
}
static int __init list_pid_init(void){
printk("%s\n",__func__);
printk("%d,", init_task.pid);
printk_pid_children(&init_task);
printk("\n");
return 0;
}
module_init(list_pid_init);
static void __exit list_pid_exit(void){
}
module_exit(list_pid_exit);
However, after sudo insmod list_pid.ko, the system hangs up.
What is wrong in the above code?
Thank you.

How to immediately cancel a work item of a workqueue in a Linux kernel module?

Kernel module code:
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
static struct workqueue_struct *queue;
static void work_func(struct work_struct *work)
{
int i = 0;
while (i < 5) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
}
}
DECLARE_WORK(work, work_func);
int init_module(void)
{
queue = create_workqueue("myworkqueue");
queue_work(queue, &work);
return 0;
}
void cleanup_module(void)
{
cancel_work_sync(&work);
destroy_workqueue(queue);
}
If I do:
insmod mymod.ko
rmmod mymod
rmmod hangs on cancel_work_sync, which first waits for the work to finish, until the counting is over.
Is it possible to immediately cancel that work item?
Minimal runnable example here.
Tested in Linux kernel 4.9.
There is another way to stop kthread with signals. This approach is better than yours because it doesn't require your thread to wake up regularly and poll the stop variable with kthread_should_stop(). No wasting CPU time, it allows your thread to sleep as long as it neeeded.
static int kthread_handle(void *param)
{
allow_signal(SIGINT);
allow_signal(SIGKILL);
for (;;)
{
// ...
// Some blocking functions such as kernel_read()/kernel_write()
// ...
if (signal_pending(current))
{
goto end;
}
// ...
// Some interruptible functions
// ...
if (mutex_lock_interruptible(...) == -EINTR)
{
goto end;
}
}
end:
while (!kthread_should_stop())
{
schedule();
}
return 0;
}
static int __init drv_init(void)
{
// Create and start kernel thread
kthread = kthread_run(kthread_handle, NULL, "kthread");
return 0;
}
static void __exit drv_exit(void)
{
send_sig(SIGKILL, kthread, 1);
kthread_stop(kthread);
}
module_init(drv_init);
module_exit(drv_exit);
I don't know how to send signals to work queues, so the solution is only for kthreads by now.
Atomic control variable
I could not find a way to stop work in a workqueue, but using a simple control variable is a possible solution.
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h> /* atomic_t */
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
static struct workqueue_struct *queue;
static atomic_t run = ATOMIC_INIT(1);
static void work_func(struct work_struct *work)
{
int i = 0;
while (atomic_read(&run)) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
if (i == 10)
i = 0;
}
}
DECLARE_WORK(work, work_func);
int init_module(void)
{
queue = create_workqueue("myworkqueue");
queue_work(queue, &work);
return 0;
}
void cleanup_module(void)
{
atomic_set(&run, 0);
destroy_workqueue(queue);
}
kthread kthread_stop
Work queues are based on kthreads, and a work queue is basically useless in that example, so we could use the kthreads directly.
kthread_stop waits for the thread to return.
See also:
Proper way of handling threads in kernel?
How to wait for a linux kernel thread (kthread)to exit?
Signal handling in kthreads seems to have been a polemic subject, and is now not possible: https://unix.stackexchange.com/questions/355280/how-signals-are-handled-in-kernel
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static struct task_struct *kthread;
static int work_func(void *data)
{
int i = 0;
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
if (i == 10)
i = 0;
}
return 0;
}
int init_module(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
void cleanup_module(void)
{
kthread_stop(kthread);
}
Timer
Run in interrupt context directly, so more accurate, but more restricted.
See also: How to use timers in Linux kernel device drivers?
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
static void callback(unsigned long data);
static unsigned long onesec;
DEFINE_TIMER(mytimer, callback, 0, 0);
static void callback(unsigned long data)
{
pr_info("%u\n", (unsigned)jiffies);
mod_timer(&mytimer, jiffies + onesec);
}
int init_module(void)
{
onesec = msecs_to_jiffies(1000);
mod_timer(&mytimer, jiffies + onesec);
return 0;
}
void cleanup_module(void)
{
del_timer(&mytimer);
}

request_irq returns -22 (-EINVAL)

The prototype of request_irq is:
int request_irq ( unsigned int irq,
irq_handler_t handler,
unsigned long irqflags,
const char * devname,
void * dev_id);
I've noticed a similar question "Simple interrupt handler: request_irq returns error code -22", but I didn't use IRQF_SHARED flag, so there is no reason that it might conflict with dev_id being NULL. But it still fail to register test irq and the errno is always -22(-EINVAL).
Here is my simple irq test module:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/interrupt.h>
static irqreturn_t irq_handle(int irq, void *dev_id)
{
printk("irq happened\n");
return IRQ_HANDLED;
}
static int irq_test_init(void)
{
int rc = request_irq(50, irq_handle, IRQF_DISABLED, "irq_test", NULL);
if(rc!=0){
printk(KERN_INFO "fail to register test irq, errno:%d\n",rc);
return -1;
}
printk(KERN_INFO "success request irq\n");
return 0;
}
static void irq_test_exit(void)
{
free_irq(50, NULL);
printk(KERN_INFO "irq module removed!\n");
return;
}
module_init(irq_test_init);
module_exit(irq_test_exit);
MODULE_LICENSE("GPL");

Segmentation fault in linux driver

I'm trying to write a linux driver. The kernel version is 2.4.18 and the distribution is Red Hat linux 8.0.
The code of my driver is:
#define LINUX
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/fs.h>
#include <asm-i386/semaphore.h>
#include "rng.h"
#include <linux/random.h>
#include <linux/slab.h>
#define DEVICE_NAME "rng"
#define BUF_LEN 80
static int major;
int init_module();
void cleanup_module();
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
struct file_operations my_fops = {
open: device_open,
release: device_release,
};
/* Init and Cleanup */
int init_module() {
SET_MODULE_OWNER(&my_fops);
major = register_chrdev(0, DEVICE_NAME, &my_fops);
return 0;
}
void cleanup_module() {
int ret = unregister_chrdev(major, DEVICE_NAME);
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
}
static int device_open(struct inode *inode, struct file *file) {
file->f_op=&my_fops;
return 1;
}
static int device_release(struct inode *inode, struct file *file) {
return 0;
}
And the code I'm using in order to test my driver is:
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int openTest() {
int game1 = open("/dev/game1", O_RDONLY); // SEGMENTATION FAULT
int retValue=1;
close(game1);
return retValue;
}
int main() {
int res;
if (openTest() < 1) {
fprintf(stderr, "open didnt work\n");
return -1;
}
fprintf(stderr, "everything works :)\n");
return 0;
}
In the code above, I'm getting a segmentation fault when I'm trying to open the device. Can somebody explain to me why I'm getting this segmentation fault? I really don't understand.
Thanks a lot!
In Linux kernel land, it is convention to return a 0 (zero) when there are no errors. Your device_open() routine is hardcoded to return a 1 (one), which may be causing your segfault.
This Linux Device Drivers book may be helpful to you. The linked edition is written for kernel 2.0.x - 2.4.x, so the information should be appropriate for the dusty and ancient kernel you are using.
This line seems to be wrong file->f_op=&my_fops;
Basically when writing a linux driver operations are setup at build time itself.

Resources