LKM入出力用LKM


LKMからのファイル出力での多少は使えるかな(?)ってレベルの、端末を通してLKMで入出力するLKMを作ってみました。関数名はtty_writek/tty_readkです。printkのかわりにtty_writekといった具合です。端末はカレントプロセスとなります。通常カレントプロセスは、insmodした端末となります。入出力は標準入出力で行っています。従って、入力でのプロンプトは表示されませんが、LKMからの出力はリダイレクトして、ファイルに落とし込むことが可能です。

LKM入出力用LKM

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <asm-generic/mman-common.h>
#include <linux/stat.h>

MODULE_DESCRIPTION("ttyk");
MODULE_AUTHOR("y.kitamura");
MODULE_LICENSE("GPL");

struct lkm_prn_buff {
   char prompt[64];
   char msg[];
};
int         tty_writek(char const * buff);
int         tty_readk(char *buf);
static int  is_ireg(struct inode *inode);
static long my_mmap(void *addr, size_t length, int prot, int flags);
static long my_munmap(void *addr, size_t length);

static int  ttyk_init(void) {   return 0;   }
static void ttyk_exit(void) {}

int tty_readk(char *buff)
{
   struct file *file0, *file1;
   int     ret = 0;
   struct lkm_prn_buff *addr;

  file0 = fget(0);
  file1 = fget(1);
   addr = (struct lkm_prn_buff *)my_mmap(
               NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS);
   if (!is_ireg(file1->f_dentry->d_inode)) {
      strcpy(addr->prompt, "[lkm]< ");
     ret = file1->f_op->write(file1, addr->prompt, strlen(addr->prompt), &file1->f_pos);
   }
  ret = file0->f_op->read(file0, addr->msg, PAGE_SIZE - sizeof(addr->prompt), &file0->f_pos); 
   if (ret > 0) {
       strcpy(buff, addr->msg);
       if (buff[ret - 1] == 0x0a) {
           buff[ret - 1] = 0x00;
           ret--;
       }
   }
   fput(file0);
   fput(file1);
   if (my_munmap(addr, PAGE_SIZE)) {
       ret = -1;
       printk("munmap err\n");
   }
   return ret;
}
EXPORT_SYMBOL_GPL(tty_readk);

int tty_writek(char const * buff)
{
   struct file *file;
   int     ret = 0;
   struct lkm_prn_buff *addr;

  file = fget(1);
   addr = (struct lkm_prn_buff *)my_mmap(
           NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS);
   if (!is_ireg(file->f_dentry->d_inode)) {
      strcpy(addr->prompt, "[lkm]> ");
      ret = file->f_op->write(file, addr->prompt, strlen(addr->prompt), &file->f_pos); 
       if (ret != strlen(addr->prompt)) {
           ret = -1;       
           printk("err\n");
       }
   }       
  strcpy(addr->msg, buff);
  ret = file->f_op->write(file, addr->msg, strlen(addr->msg), &file->f_pos);            
   fput(file);
   if (ret != strlen(addr->msg)) {
       ret = -1;
       printk("err\n");
   }
   ret = my_munmap(addr, PAGE_SIZE);
   if (ret) {
       printk("%d\n", ret);
   }
   return ret;
}
EXPORT_SYMBOL_GPL(tty_writek);

static long my_mmap(void *addr, size_t length, int prot, int flags)
{
   long    mmap;
   int     dymmy = 0;

   __asm__ volatile ("push %%ebp;movl %%edi,%%ebp;int $0x80;pop %%ebp"
       : "=a"(mmap)
       : "a"(__NR_mmap2), "b"(addr), "c"(length), "d"(prot),"S"(flags), "D"(dymmy));
   if (IS_ERR((const void *)mmap))
       return PTR_ERR((const void *)mmap);
   return mmap;
}

static long my_munmap(void *addr, size_t length)
{
   long        err;

  __asm__ volatile ("int $0x80"
  : "=a"(err)
  : "a"(__NR_munmap), "b"(addr), "c"(length));
   return err;
}

static int  is_ireg(struct inode *inode)
{
   return (S_ISREG(inode->i_mode))? 1: 0;
}

module_init(ttyk_init);
module_exit(ttyk_exit);

使用サンプル

#include <linux/module.h>

MODULE_DESCRIPTION("ttyk test");
MODULE_AUTHOR("y.kitamura");
MODULE_LICENSE("GPL");

long    tty_writek(const char* a);
long    tty_readk(char* a);

static int test_init(void)
{
   long    ret;
   char    buff1[64], buff2[64];

   ret = tty_readk(buff1);
   sprintf(buff2, "%s is from tty\n", buff1);
   ret = tty_writek(buff2);
   
   return 0;
}
static  void    test_exit()
{
}
module_init(test_init);
module_exit(test_exit);

使用方法

端末
[root@localhost kitamura]# insmod ttyk.ko
[root@localhost kitamura]# insmod test.ko
[lkm]< abcdefg
[lkm]> abcdefg is from tty
[root@localhost kitamura]# rmmod test.ko

リダイレクト
[root@localhost kitamura]# insmod test.ko > log
abcdefg
[root@localhost kitamura]# cat log
abcdefg is from tty

補足

mmapで直接カーネル内関数での処理を試みたのですが、task構造体メンバーが直接参照できないためか、うまくいきませんでした。それでシステムコールを呼ぶことで実現しました。従いまして現状X86での動作となります。なんとか直接カーネル内関数での処理を試みたいと思っていますが・・・。


最終更新 2012/02/10 15:28:22 - north
(2012/02/10 15:25:29 作成)


検索

アクセス数
3576053
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。