Re: command line arguments

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux