2017-02-01 12 views
0

catコマンドをカーネルモジュールとして実装しようとしています。私はファイルI/Oがカーネルモジュールで行われてはならないことを知っています。 insmod module.koを使用するたびに、出力はkilledとなります。どうすれば修正できますか?また、コードを改善するにはどうすればよいですか?
カーネルバージョン - 4.4
コード:insmodを使用してカーネルモジュールを無効にしました

#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/unistd.h> 
#include <linux/syscalls.h> 
#include <linux/fcntl.h> 
#include <asm/uaccess.h> 
#include <linux/init.h> 
#include <linux/fs.h> 
#include <linux/file.h> 

static char* argv[10]; 
static int argc = 1; 
module_param_array(argv, int, &argc , 0); 

static void cat(int f, char *s) 
{ 
    char buf[8192]; 
    struct file *file; 
    loff_t pos = 0; 
    long n; 
    mm_segment_t old_fs = get_fs(); 
    set_fs(KERNEL_DS); 

    while((n = vfs_read(f, buf, (long)sizeof buf, &pos)) > 0) 
    { 
     //write(1, buf, n); 
     file = fget(f); 
     if (file) { 
      vfs_write(file, buf, (long)sizeof buf, &pos); 
      fput(file); 
     } 


    } 
    set_fs(old_fs); 
} 

static void __init hello_init(void) 
{ 
    int f, i; 
    if(argc == 1) 
     cat(0, "<stdin>"); 
    else for(i=1; i<argc; i++) 
    { 
     f = filp_open(argv[i], O_RDONLY, 0); 
     if(f < 0) 
      printk("error"); 
     else{ 
      cat(f, argv[i]); 
      filp_close(f); 
     } 
    } 
} 

static void __exit hello_cleanup(void) 
{ 
    printk(KERN_INFO "Cleaning up module.\n"); 
} 

module_init(hello_init); 
module_exit(hello_cleanup); 

ここでは、単にファイルを読み込み、上記のコードの簡易版です。 vfs_readの部分をコメントアウトすると、私はそれをinsmodすることができますが、vfs_readでそれは殺されたことを示します。

#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/syscalls.h> 
#include <linux/fcntl.h> 
#include <asm/uaccess.h> 

static void read_file(char *filename) 
{ 
    int fd; 
    char buf[1]; 
    loff_t f_pos = 0; 

    mm_segment_t old_fs = get_fs(); 
    set_fs(KERNEL_DS); 

    fd = filp_open(filename, O_RDONLY, 0); 
    if (fd >= 0) { 
    printk(KERN_DEBUG); 
    while (vfs_read(fd, buf, 1, &f_pos) == 1) //if this 
     printk("%c", buf[0]); //and this is removed I'm able to insmod it 
    printk("\n"); 
    sys_close(fd); 
    } 
    set_fs(old_fs); 
} 

static int __init init(void) 
{ 
    read_file("/etc/shadow"); 
    return 0; 
} 

static void __exit exit(void) 
{ } 

module_init(init); 
module_exit(exit); 
+0

**あなたはコードをデバッグしようとしましたか?デバッグカーネルコードでは、あるポイントの後に 'printk()'を追加することができます。また、コードがクラッシュした場合、 'dmesg'はそれに関する追加情報を与えるかもしれません。 – Tsyvarev

+0

dmesgはRIP []を返します。vfs_read + 0x5/0x130とfbcon_switch:未処理のfb_set_parエラーを検出しました – user7498777

+0

'hello_init'関数のどの枝が実行されますか? ( 'cat(0)'、 'cat(f)')ですか?あなたのモジュールは**ポインタの配列**を受け入れますが、これはおそらくあなたが期待しているものではないことに注意してください。つまり、 'argv [i]'はガーベジへのポインタであり、 'filp_open()'呼び出しのような)逆参照は**間違いです**。 – Tsyvarev

答えて

1

あなたはモジュールのinitコールバックからすべてこれを行うにしようとしているいくつかのこと...

argc/argvには何も含まれていないため、問題が発生しています(つまり、セグメンテーションを取得する可能性があります)。

ハードワイヤーargc/argv有効な値ですが、再コンパイルして、別のファイルを使用してドライバーを再読み込みする必要があります。

しかし、モジュールのパラメータを受け入れてstrtokに分割して、argvに値を設定したほうがよい場合があります。これは、ドライバのために同等のargvに最も近いものです[アプリケーションではmainとまったく同じ方法で実際には存在しません]。

あなたはまだはそれをするたびにリロードする必要があります、モジュールを再コンパイルする必要がありますが、ではないでしょうしかし

、これを行うには、実際の/正しい方法(異なる引数を毎回insmodを与えます)モジュールinitでは、標準メカニズムを使ってキャラクタデバイスとしてドライバを登録します。同様に、モジュールクリーンアップルーチンで登録を解除します。

次に、/devのエントリ(例:/dev/mycat)を作成します。

アプリケーションからは、/dev/mycatを開いて、ファイル記述子に追加するファイルのリストを1行に1つ書きます。

ドライバのwriteコールバックルーチンを使用して、渡されたバッファ内のデータを解析して(つまり、ユーザー空間に独自のfgetsを実装しているかのように)、取得したリストを処理して、 。 YMMV

ドライバが任意であるために、ファイルリストを通信するための実際の機構 -

むしろ/devエントリを作成するよりも、/procエントリ(例えば/proc/mycat)を作成する方が簡単かもしれません。 AF_UNIXソケット、名前付きパイプ、SysVメッセージキューへのフックなどを使用できますが、/devまたは/proc解決策はおそらく簡単でしょう。


UPDATE:

vfs_readで別の問題があるようです。 dmesgのは、RIP [] vfs_read + 0x5/0x130とfbcon_switchを与える:とりわけ

未処理fb_set_parエラーを検出し、あなたはvfs_readへの最初の引数としてintを渡しています。最初の引数はstruct file * [vfs_write]のようにする必要があります。

注:標準メカニズムを使用してドライバを構築する場合、これは-Wallでコンパイルされ、コンパイル時にフラグが立てられます。

O_RDONLY(つまり、ユーザースペースcat foobar > foobarに相当)で開いていても、読んでいるファイルに[cat出力]を書き込もうとしています。これは、vfs_writeの場合はfile = fget(f)でした。あなたが本当にやりたかったのはfile = fget(1)

vfs_readvfs_writeの場合は、fget/fputペアリングが必要です。そして、彼らは別々する必要があります。

file_in = fget(f); 
file_out = fget(1); 

// read/write loop ... 
while (1) { 
    ... 
} 

fput(file_in); 
fput(file_out); 

あなたはスタックにbufを置きたくないありません。競合状態が発生します。 vfs_read [AFAIK]でI/Oが依然として保留されている間に[カーネル]スレッドが別のプロセッサに移行する可能性があります。類似のものを行う他のドライバは、バッファを取得するためにkmallocを使用します[そしてそれを解放するにはkfree]。

+0

ありがとう。 vfs_readには別の問題があるようです。 dmesgはRIP [] vfs_read + 0x5/0x130を返し、fbcon_switch:未処理のfb_set_parエラーを検出しました – user7498777

関連する問題