OSC:User-Kernel Space Communication
From SOFTICE
|
User-kernel space communication
- Introduce Kernel Data Structures: struct proc_dir_entry
- Introduce Kernel APIs: procfile_read, procfile_write, create_proc_entry, remove_proc_entry, memcpy, copy_from_user
- Big picture:
- Kernel Data Structures related to ProcFS and SysFS
- Registering entries in /proc from a LKM
- Strengthen students' system call interception techniques & general LKM writting skills
- Alessio Gaspar
- This laboratory is heavily based on [lkmpg], credits go to its authors; Peter Jay Salzman, Michael Burian and Ori Pomerantz
Synopsis
We want to write a loadable kernel module which will communicate with user space using the /proc pseudo file system. We will apply this to enhance our previous LKMs so that they can receive information from user space at run time in a more dynamic manner.
[Briefing] PROCFS & LKMs
ProcFS
The briefing material useful for this laboratory is already available in sections #5.1 & #5.2 of [LKMPG], check this reference, read it, and answer the following questions (some will require additional research in the references or on the web):
- What is the role of the /proc/ filesystem?
- How is it used by ps to retrieve the information it needs from the kernel?
- How is it used by netstat to retrieve the information it needs from the kenel?
- What are the new kernel data structures used in these examples and what are their roles?
- What are the new kernel functions used in these examples and what are their roles?
SysFS
[LWN] summarises the way that SysFS is now used for you to read and write to the sysfs entries which represent the LKM's parameters. Here is a quote-summary of the explanations provided in this reference about the LKM parameters's new API:
- module_param(name, type, perm);
Declares that the LKM will received a parameter named name and of type type. Beside the typing, you must pay particular attention to the third field; perm. The latter stands for permission and allows you to have this particular parameter accessible through sysfs at /sys/module/mylkm/parameters/name. If your permission is 0, then the parameter won't be made accessible through ssyfs.
- module_param_named(name, value, type, perm);
This variant allows you to have the parameter name represented as the LKM variable specified as value field.
- module_param_string(name, string, len, perm);
[LWN] explains that while all string parameters will be declared as charp, this variant can be used to get a copy of the string directly into character array located in the LKM. The len parameter has to be accordingly specified as the sizeof(string).
- module_param_array(name, type, num, perm);
This last variant is meant to facilitate passing array parameters to LKMs. Array arguments are specified as a comman-separated list of num elements and will be stored in the LKM variable name.
[Solved] Simple ProcFS-enabled LKMs
Hello world LKM
Write a LKM that registers a /proc/helloworld file which, when displayed, always responds "hello world". This code example is taken from section #5.1 of [LKMPG], we only modified it slightly to follow the same conventions as the previous LKM examples presented in these labs.
/*
* procfs1.c - create a "file" in /proc
*
*/
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LKMPG maintainers");
MODULE_DESCRIPTION("refer to http://www.tldp.org/LDP/lkmpg/2.6/html/index.html");
#define procfs_name "helloworld"
/**
* This structure hold information about the /proc file
*
*/
struct proc_dir_entry *Our_Proc_File;
/* Put data into the proc fs file.
*
* Arguments
* =========
* 1. The buffer where the data is to be inserted, if
* you decide to use it.
* 2. A pointer to a pointer to characters. This is
* useful if you don't want to use the buffer
* allocated by the kernel.
* 3. The current position in the file
* 4. The size of the buffer in the first argument.
* 5. Write a "1" here to indicate EOF.
* 6. A pointer to data (useful in case one common
* read for multiple /proc/... entries)
*
* Usage and Return Value
* ======================
* A return value of zero means you have no further
* information at this time (end of file). A negative
* return value is an error condition.
*
* For More Information
* ====================
* The way I discovered what to do with this function
* wasn't by reading documentation, but by reading the
* code which used it. I just looked to see what uses
* the get_info field of proc_dir_entry struct (I used a
* combination of find and grep, if you're interested),
* and I saw that it is used in <kernel source
* directory>/fs/proc/array.c.
*
* If something is unknown about the kernel, this is
* usually the way to go. In Linux we have the great
* advantage of having the kernel source code for
* free - use it.
*/
int procfile_read( char *buffer,
char **buffer_location,
off_t offset,
int buffer_length,
int *eof,
void *data)
{
int ret;
printk(KERN_INFO "[edu-03] procfile_read (/proc/%s) called\n", procfs_name);
/*
* We give all of our information in one go, so if the
* user asks us if we have more information the
* answer should always be no.
*
* This is important because the standard read
* function from the library would continue to issue
* the read system call until the kernel replies
* that it has no more information, or until its
* buffer is filled.
*/
if (offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
ret = sprintf(buffer, "HelloWorld!\n");
}
return ret;
}
int init_module()
{
printk( KERN_ALERT "[edu-03] Module successfully loaded\n");
Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL);
if (Our_Proc_File == NULL) {
remove_proc_entry(procfs_name, &proc_root);
printk(KERN_ALERT "[edu-03] Error: Could not initialize /proc/%s\n",
procfs_name);
return -ENOMEM;
}
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_INFO "[edu-03] /proc/%s created\n", procfs_name);
return 0; /* everything is ok */
}
void cleanup_module()
{
remove_proc_entry(procfs_name, &proc_root);
printk(KERN_INFO "[edu-03] /proc/%s removed\n", procfs_name);
}
module_init(init_module); module_exit(cleanup_module);
Echo LKM
Write a LKM that write a message in a proc entry that can be changed by writting to another of its proc entries. Look at section 5.2 in [LKMPG].
/**
* procfs2.c - create a "file" in /proc
*
*/
#include <linux/module.h> /* Specifically, a module */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#include <asm/uaccess.h> /* for copy_from_user */
#define PROCFS_MAX_SIZE 1024
#define PROCFS_NAME "buffer1k"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LKMPG maintainers");
MODULE_DESCRIPTION("refer to http://www.tldp.org/LDP/lkmpg/2.6/html/index.html");
/**
* This structure hold information about the /proc file
*
*/
static struct proc_dir_entry *Our_Proc_File;
/**
* The buffer used to store character for this module
*
*/
static char procfs_buffer[PROCFS_MAX_SIZE];
/**
* The size of the buffer
*
*/
static unsigned long procfs_buffer_size = 0;
/**
* This function is called then the /proc file is read
*
*/
int procfile_read( char *buffer,
char **buffer_location,
off_t offset,
int buffer_length,
int *eof,
void *data)
{
int ret;
printk(KERN_INFO "[edu-03] procfile_read (/proc/%s) called\n", PROCFS_NAME);
if (offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
memcpy(buffer, procfs_buffer, procfs_buffer_size);
ret = procfs_buffer_size;
}
return ret;
}
/**
* This function is called with the /proc file is written
*
*/
int procfile_write( struct file *file,
const char *buffer,
unsigned long count,
void *data)
{
/* get buffer size */
procfs_buffer_size = count;
if (procfs_buffer_size > PROCFS_MAX_SIZE ) {
procfs_buffer_size = PROCFS_MAX_SIZE;
}
/* write data to the buffer */
if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) {
return -EFAULT;
}
return procfs_buffer_size;
}
/**
*This function is called when the module is loaded
*
*/
int init_module()
{
/* create the /proc file */
Our_Proc_File = create_proc_entry(PROCFS_NAME, 0644, NULL);
if (Our_Proc_File == NULL) {
remove_proc_entry(PROCFS_NAME, &proc_root);
printk(KERN_ALERT "[edu-03] Error: Could not initialize /proc/%s\n",
PROCFS_NAME);
return -ENOMEM;
}
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->write_proc = procfile_write;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_INFO "[edu-03] /proc/%s created\n", PROCFS_NAME);
return 0; /* everything is ok */
}
/**
*This function is called when the module is unloaded
*
*/
void cleanup_module()
{
remove_proc_entry(PROCFS_NAME, &proc_root);
printk(KERN_INFO "[edu-03] /proc/%s removed\n", PROCFS_NAME);
}
module_init(init_module); module_exit(cleanup_module);
[Exercises]
Exercise 01: Warming up with /proc
Write a userland program that, given a specific PID, reports the following information about the process:
- Name.
- Run state (running, sleeping, interruptibly sleeping, zombie, traced, or paging).
- PID of the parent.
- Nice value.
- Terminal it is attached to.
Exercise 2: What about SysFS
Rewrite the solved exercise on the "Echo LKM" using only sysfs.
[Projects]
Project 1: Improved forkban
We want to improve the previously developed fork-ban LKM. Instead of having to pass the pid of the process to which we want to deny the fork syscall when we load the module, we want to be able to write it, after the LKM is loaded, to a /proc interface. Your LKM must maintain a file in the /proc filesystem: /proc/forkban. Writing a PID to this file should change which process is denied access to the fork() system call; reading from this file should give the PID of the limited process.
References
[LDD] Linux Device Drivers, 3/e (safary reference)
- Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman
- O'Reilly, Third Edition February 2005
- http://www.oreilly.com/catalog/linuxdrive3/book/index.csp
- Chapter(s): 2, Building and Running Modules (p.35)
[LKMPG] Loadable Kernel Modules Programmer's Guide 2.6.x
- Peter Jay Salzman, Michael Burian, Ori Pomerantz
- 2005-12-31 ver 2.6.3
- http://www.tldp.org/LDP/lkmpg/2.6/html/
- Chapter(s): #5.1 & #5.2 (/proc filesystem)
[LWN] Driver porting: more module changes
- Linux Weekly News, Corbet, 02/11/2003
- http://lwn.net/Articles/22197/
References (Textbooks)
[NUTT] Operating Systems, 3/e
- Gary Nutt, Addison Wesley, ISBN 0-210-77344-9
- http://www.cs.colorado.edu/~nutt/osamp.html
- Chapter(s): #2 (Using the Operating System)
[STALL] Operating Systems, Internals and Design Principles
- William Stallings, Prentice Hall, ISBN 0-13-1479-54-7
- http://williamstallings.com/
- Chapter(s): #3 (Process Description and Control)
[SILB] Operating System Concepts with Java
- http://os-book.com/
- Abraham Silberschatz, Peter Baer Galvin, Greg Gagne
- Wiley, ISBN: 978-0-471-76907-1
- Chapter(s): #3 (Processes)
[DEIT] Operating Systems
- Deitel, ISBN: 0131828274
- Chapter(s): #3 (Processes)

