LinuxQuestions.org
Visit the LQ Articles and Editorials section
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 11-12-2007, 02:42 AM   #1
Ljunge
LQ Newbie
 
Registered: Nov 2007
Posts: 2

Rep: Reputation: 0
Question LKM talking to another LKM?


Hi everyone. This is my very first post on these forums but this certainly looks like a nice place to bring my newbie questions

I've just started programming kernel modules. Currently I'm trying to write a Shared Watchdog Application where applications that share the same hw can register and be able to share a single hw watchdog.

I want the application to be transparent to the applications in user space and the hw watchdog so that I don't need to change that much code in the already existing applications.

If the user space application does an IOCTL on my module I want to perform some logic and then send it to the "real" watchdog module that resets the timer on the hw watchdog etc.

By doing it like this I came to the conclusion that I needed standard file operations like open, close, ioctl etc. First I used these but that resolved in compling errors (implicit declaration of function...). I then found the sys_open, sys_close and sys_ioctl functions that I tried to use instead. I got no compling errors _but_ I got unresolved symbols (except sys_close) when trying to insmod the module. When doing a cat on /proc/ksyms I found that just 'sys_close' was known to the kernel. I then went into kernel/ksyms.c and exported sys_open and sys_close, recompiled the kernel and tried to insmod the module again. The unresolved symbol for sys_open went away but it still left me with sys_ioctl as an unresolved symbol. I'm compling for a linux 2.4.20 kernel btw.

I don't know how to make it known to my kernel or if it's at all possible to make a LKM communicate with another LKM in this manner?

Maybe this is a terrible solution to what I want to achieve, I don't know, but at least at first sight it sounded better than my other idea of implementation which was to create a daemon in user space that used some sort of IPC to communicate with the other user space applications and then use the /proc filesystem to communicate with the kernel module. But from what I've seen of the proc file system it's mostly used by the kernel to communicate information to user space. But what do I know Maybe it's possible to do it like this as well?

Anyways, any help pointing me in the right direction would be greatly appreciated. The whole kernel hacking thing is all new to me so please be gentle with me

Cheers!
 
Old 11-12-2007, 10:03 PM   #2
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 70
Quote:
Originally Posted by Ljunge View Post
Maybe this is a terrible solution to what I want to achieve, I don't know,
If I understand it correctly, yes it is .

The function sys_open() is a system call. It is called on every file opened from userspace (ever!). In turn, that function (and others such as sys_read(), sys_write(), sys_ioctl(), etc.) eventually end up looking at the filesystem on which the file resides, and ask the relevant functions how to deal with the queries.

But more to the point, you don’t want to design your own filesystem, you want to use an existing one. I couldn’t tell what kind of file you are provided to userspace (you said: “…user space application does an IOCTL on my module…”) these operations are not performed on “modules” but on “files” controlled by said modules. In most cases this file is a “character device” file that resides in the /dev directory. In other cases, you create your own file under /proc. The second case makes it easy to control reads and writes (though ioctl use in /proc is discouraged—in fact, any newly introduced ioctl use is discouraged in general). The first case might be more tedious. Both cases (the second with greater difficulty) allow you to define any and all callbacks available in struct file_operations.

So you could create a write handling function for that file. This function would perform some error-checking and discard (usually by returning -EINVAL) most data written to it (after all, it’s not an on-disk file, but a special kernel interface). You could chose to interpret only specially-crafted strings which mean something to your module. For example, you might make your write handler respond to this userspace event:
Code:
echo "reset" > /proc/watchdog_helper
by resetting the timer.

The method you go about doing this varies depending on what files your module has already created, but they all involve changing an instance of type struct file_operations. This happens directly in the case of a character device, and usually indirectly in the case of a proc entry (though if you really want, you can do it directly for proc entries as well). If you specify what type of file you have (chardev vs. proc entry) and what you want to go with (specialized writes vs. ioctls), it would be easier to help you with specifics.
 
Old 11-12-2007, 10:16 PM   #3
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 70
If you don’t already have your type of file chosen here is a spectrum of difficulty in implementation (pairing chardev vs. proc entry with types of file operations) summarizing the previous post:
Code:
EASY----------------------------------MEDIUM----------------------------------HARD
proc_entry read                    chardev read                  proc_entry ioctl
proc_entry write                   chardev write                 proc_entry other*
                                   chardev ioctl
                                   chardev other*
*Here other refers any other more arcane file operation, including llseek, aio_read, aio_write, readdir, poll, mmap, flush, fsync, aio_fsync, fasync, lock, sendpage, get_unmapped_area, check_flags, dir_notify, flock, splice_write, splice_read, and setlease.
 
Old 11-13-2007, 03:03 AM   #4
Ljunge
LQ Newbie
 
Registered: Nov 2007
Posts: 2

Original Poster
Rep: Reputation: 0
Thank you very much for the quick and extensive response osor, it's very much appreciated. I'll try and explain the current design and the different solutions (as I see it) that may be available.

Today there are two (or more) user-space applications that want to make use of the same hw-watchdog. This hw-watchdog has an associated driver (in the form of a module that resides in kernel space). As we both know it's not easy, or at all possible, to accomplish this because the watchdog is unaware of who is actually kicking on him. It looks something like this:

http://img213.imageshack.us/my.php?image=todaykz2.jpg

What I wanted to achieve is an application that makes it possible for user-space applications to share this common hw-watchdog. My first suggested solution looked like this:

http://img240.imageshack.us/my.php?image=driverqc6.jpg

Here I mounted a /dev/wd_helper and wrote a driver for that one. This driver basically has the same logic as the user-space applications, with the exception that it is aware of who's currently a registred user of it. I wanted to make this driver transparent in the way that, when it gets an ioctl from user-space to reset the watchdog, all it does is interpret the command, opens the /dev/watchdog and send the very same ioctl on to the associated driver of the hw-watchdog. It's when I tried to insmod this module that I got the unresolved symbols for the sys_open and sys_ioctl functions and that's when I thought that this solution might not be possible to achieve because two LKM might not be able to talk to each other in this manner. But it would save me some work because then I don't have to change code in either the user-space applications or the watchdog driver. Is it at all possible to achieve this effect in this way or is it considered an ugly and non-recommened approach?

I went back to the sketchboard and came up with another solution I thought might work. It looks like this:

http://img260.imageshack.us/my.php?image=daemonrb4.jpg

Here I've moved the logic from the wd_helper_driver to a daemon in user-space. My initial thought was to use the proc file system to communicate with the watchdog_driver. But maybe it's possible to use the /dev/watchdog directly and achieve the same effect? That would save me from rewriting parts of the watchdog_driver to make it able to use /proc. I think an ioctl approach would be preferable over specialized writes because I already have most of the code to handle that (in the watchdog driver). But I'm open for any feasible solution.

So my questions are:

Is it possible to make two LKMs communicate with each other in a similar way of my first example?
Is it a bad way of doing it and do you think I should use another solution? My second suggestion maybe?
If I want to use a daemon I would have to change the way the user-space applications communicate. Instead of doing open, ioctl etc on /dev/watchdog, I would have to use some sort of Inter Process Communication between the applications and the daemon right? Is there anyone in particular you recommend in this case?

Sorry for the rather long post Hope it makes sense.

Cheers!

Last edited by Ljunge; 11-13-2007 at 03:57 AM.
 
Old 11-13-2007, 01:29 PM   #5
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 70
I misunderstood your original post. I thought you were trying to use the sys_*() functions directly to intercept userspace reads, writes, ioctls, etc. What (I currently think) you are talking about is calling userspace system calls from kernelspace. Coincidentally, there was a similar question on this not long ago. Here is an old article explaining the process in greater detail. In general, this is not recommended, and in this case, it may be overcome easily.

But first, some questions for you:
Quote:
Originally Posted by Ljunge View Post
the watchdog is unaware of who is actually kicking on him.
I don’t understand what you mean by this statement.
Quote:
Originally Posted by Ljunge View Post
What I wanted to achieve is an application that makes it possible for user-space applications to share this common hw-watchdog. My first suggested solution looked like this:

http://img240.imageshack.us/my.php?image=driverqc6.jpg

Here I mounted a /dev/wd_helper and wrote a driver for that one. This driver basically has the same logic as the user-space applications, with the exception that it is aware of who's currently a registred user of it.
How is /dev/wd_helper made aware of who’s currently a registered user? Why can’t you just use the same approach and instead apply it to the main driver instead?
Quote:
Originally Posted by Ljunge View Post
I wanted to make this driver transparent in the way that, when it gets an ioctl from user-space to reset the watchdog, all it does is interpret the command, opens the /dev/watchdog and send the very same ioctl on to the associated driver of the hw-watchdog.
So why don’t you make it so when it gets an ioctl, it calls /dev/watchdog’s ioctl handler directly (instead of through a system call)? You can export the symbols for the module’s functions you need to be “cross-module”. You can then simply call the functions (provided that the prototypes are declared in your code) from the secondary module.
Quote:
Originally Posted by Ljunge View Post
It's when I tried to insmod this module that I got the unresolved symbols for the sys_open and sys_ioctl functions and that's when I thought that this solution might not be possible to achieve because two LKM might not be able to talk to each other in this manner.
The errors you received are because the older (i.e., <=2.4) kernels had a awkward policy for exporting kernel symbols (symbol was only exported if it was necessary for use by other modules). So you cannot use non-exported functions such as sys_open and friends. What you have to do on these kernels is:
Code:
struct file *f = filp_open("/dev/watchdog", 0, 0);
f->f_op->ioctl(f->f_dentry->d_inode, f, FFOO, &bar);
/* file_ioctl(f, FOO, &bar); is an alternative*/
fput(f);
f = NULL;
You actually can accomplish this even if you want to use syscalls:
Code:
long (*sys_open)(const char * filename, int flags, int mode) = sys_call_table[__NR_open];
long (*sys_ioctl)(unsigned int fd, unsigned int cmd, unsigned long arg) = sys_call_table[__NR_ioctl];
int fd = sys_open("/dev/watchdog", 0, 0);
sys_ioctl(fd, FFOO, &bar);
sys_close(fd);
Both of these code segments must be armored by setfs(KERNEL_DS) and setfs(oldfs) as explained in the article. Also, you need to implement error checking if you are actually going to use them.
Quote:
Originally Posted by Ljunge View Post
Is it at all possible to achieve this effect in this way or is it considered an ugly and non-recommened approach?
As you see above, it is certainly possible. It is also considered an ugly and non-recommended approach.
Quote:
Originally Posted by Ljunge View Post
Here I've moved the logic from the wd_helper_driver to a daemon in user-space. My initial thought was to use the proc file system to communicate with the watchdog_driver. But maybe it's possible to use the /dev/watchdog directly and achieve the same effect? That would save me from rewriting parts of the watchdog_driver to make it able to use /proc. I think an ioctl approach would be preferable over specialized writes because I already have most of the code to handle that (in the watchdog driver). But I'm open for any feasible solution.
Why not have a list of registered users. A client might register himself on the list through a proc interface (implemented as a helper module). The list head (and thus the rest of the list) would be visible to the main driver. When a registered client would use the driver directly (with ioctls or what have you), the driver would know how to respond by searching for the client in the list.
Quote:
Originally Posted by Ljunge View Post
Is it possible to make two LKMs communicate with each other in a similar way of my first example?
Is it a bad way of doing it and do you think I should use another solution? My second suggestion maybe?
If I want to use a daemon I would have to change the way the user-space applications communicate. Instead of doing open, ioctl etc on /dev/watchdog, I would have to use some sort of Inter Process Communication between the applications and the daemon right? Is there anyone in particular you recommend in this case?
  1. Yes, but it’s not pretty nor recommended (see details above).
  2. I think you could either execute the real ioctl function (or whatever lies underneath it) directly when a client ioctls the helper driver. Another solution is the registered list that I described above.
  3. I would recommend against using a userspace helper daemon for such a simple job. If I understand correctly that was your second solution.
  4. Yes, probably.
  5. I would recommend whichever IPC fits the job. Since I don’t know much about the specifics, I can’t really give you a specific IPC to use.
Quote:
Originally Posted by Ljunge View Post
Sorry for the rather long post
Sorry for mine

Last edited by osor; 11-13-2007 at 01:32 PM. Reason: Misnumbered answers
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
problem in LKM kumar.manoj412 Linux - General 2 05-26-2007 12:19 PM
LKM rootkit help GodSendDeath Programming 1 05-01-2004 11:49 AM
LKM trojan? help! synaptical Linux - Security 3 03-07-2004 07:16 AM
lkm trojan nullpt *BSD 3 12-25-2003 12:09 AM
chkrootkit and lkm Crashed_Again Linux - Security 3 06-08-2003 08:54 PM


All times are GMT -5. The time now is 08:29 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration