[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: command line arguments
Hi,
Here is a simple kernel module, that prints the arguments
of a particular task.
// Print task's arguments, Linux Kernel 2.6.12.2.
//
// A simple kernel module that prints the arguments of a given task.
// After successfull execve(), the arguments (together with the environment)
// reside in user space memory. There is no kernel data structure that
// provides direct access to task's arguments. This fact can be observed
// from how do_execve() and proc_pid_cmdline() work.
//
// The do_execve() first copies the arguments and environment into
// kernel space. Looking at the source code reveals that bprm variable
// holds the copied data and it is freed later.
//
// The proc_pid_cmdline() shows how to access the relevant data from
// user space pages. It uses the access_process_vm() to do this.
// Since this function is not exported, the get_user_pages() is used instead.
//
// This kernel module implements a simple character device with file operations
// open(), release() and read(). The read() method prints the task's arguments.
//
// I hope the code is correct. It is essentially a copy-paste-edit
// of access_process_vm().
//
// # mknod args c 253 0
// # cat args a b c d e f
// # dmesg
//
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/binfmts.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#define FIRST_MINOR 0
#define MINOR_COUNT 1
#define DEVICE_NAME "args"
static dev_t device_number;
static struct cdev device;
static int open_fop(struct inode *, struct file *);
static int release_fop(struct inode *, struct file *);
static ssize_t read_fop(struct file *file, char __user *buf,
size_t size, loff_t *off);
static struct file_operations fops=
{
owner:THIS_MODULE,
open:open_fop,
release:release_fop,
read:read_fop,
};
static void print_args(struct task_struct *task);
static int __init init(void)
{
int ret;
if((ret=alloc_chrdev_region(&device_number, FIRST_MINOR,
MINOR_COUNT, DEVICE_NAME))<0)
goto out;
cdev_init(&device, &fops);
if((ret=cdev_add(&device, device_number, MINOR_COUNT))<0){
unregister_chrdev_region(device_number, MINOR_COUNT);
goto out;
}
out:
return ret;
}
static void __exit exit(void)
{
cdev_del(&device);
unregister_chrdev_region(device_number, MINOR_COUNT);
}
module_init(init);
module_exit(exit);
MODULE_LICENSE("GPL");
static int open_fop(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
return 0;
}
static int release_fop(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
return 0;
}
static ssize_t read_fop(struct file *file, char __user *buf,
size_t size, loff_t *off)
{
print_args(current);
return 0;
}
#define NEWLINE '\n'
#define NULLCHAR 0
#define GUP_LEN 1
#define GUP_WRITE 0
#define GUP_FORCE 1
static void print_args(struct task_struct *task)
{
struct mm_struct *mm=task->mm;
struct page *page=0;
struct vm_area_struct *vma=0;
char *addr=0;
int offset=0;
int bytes=0;
int i=0;
// The task's arguments lie in the user space
// virtual memory range <mm->arg_start, mm->arg_end).
// Therefore the total size of task's arguments is the following.
int args_size=mm->arg_end-mm->arg_start;
int start=mm->arg_start;
struct page *tmp_page=0;
char *tmp_addr=0;
tmp_page=alloc_page(GFP_HIGHUSER);
tmp_addr=kmap(tmp_page);
down_read(&mm->mmap_sem);
// The arguments are printed page by page.
// Every cycle prints the contents of one page.
while(args_size){
// Make the user space page available in kernel space.
// The get_user_pages() creates shared mapping (not a copy
// of the user space contents).
if(get_user_pages(task, mm, start, GUP_LEN, GUP_WRITE,
GUP_FORCE, &page, &vma)<=0)
goto out;
addr=kmap(page);
// Here, the task's arguments are available in kernel space memory.
// Note that the mm->arg_start does not have to be page-aligned,
// therefore the arguments can start in the middle of the page
// (not just at the beginning).
offset=start&(PAGE_SIZE-1);
bytes=PAGE_SIZE-offset;
if(args_size<bytes)
bytes=args_size;
// Every null-character is substituted for newline for the
// purpose of pretty-printing. Because the get_user_pages
// creates shared mapping, the contents are first copied
// to temporary storage.
memcpy(tmp_addr, addr, PAGE_SIZE);
for(i=offset; i<PAGE_SIZE; ++i)
if(tmp_addr[i]==NULLCHAR)
tmp_addr[i]=NEWLINE;
// The printing is not very precise. A single argument can
// overlap two consecutive pages. In that case, its print
// is interrupted by a newline.
printk(KERN_NOTICE "%.*s\n", bytes, tmp_addr+offset);
kunmap(page);
page_cache_release(page);
args_size-=bytes;
start+=bytes;
}
out:
up_read(&mm->mmap_sem);
kunmap(tmp_page);
__free_page(tmp_page);
}
BlackHole
--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ