16

似たような話題があったとしても、2年も前の話だと気づいたので、新たに立てた方がいいのかな…

乱数ジェネレーター (/drivers/char/random.c) の動作を監視するために、Linux カーネル (3.3.4) から UDP パケットを送信する方法を見つけようとしています。これまでのところ、sock_create および sock_sendmsg 関数のおかげで、いくつかのことを監視できました。このメッセージの最後に、私が使用する典型的なコードを示します。(完全に変更された random.c ファイルをここからダウンロードすることもできます。)

このコードを適切な random.c 関数内に挿入することで、/dev/random および /dev/urandom へのアクセスごとに UDP パケットを送信し、乱数ジェネレーターがエントロピーを収集するために使用するキーボード/マウス イベントごとに送信できます。 . しかし、ディスク イベントを監視しようとすると、まったく機能しません。ブート中にカーネル パニックが発生します。

したがって、私の主な質問は次のとおりです。私のコードがディスク イベント関数に挿入されると、なぜこれほどまでに多くの問題が発生するのか、わかりますか? (add_disk_randomness)

あるいは、この種の UDP-in-kernel の問題を処理することになっている netpoll API について読んだことがあります。残念ながら、2005 年の非常に興味深いが時代遅れの Red Hat のプレゼンテーション以外に、関連するドキュメントは見つかりませんでしたはいの場合、例はありますか?

どんな助けでも大歓迎です。前もって感謝します。

PS: これは私の最初の質問です。何か間違ったことをしている場合は遠慮なく教えてください。今後のために心に留めておきます :)


#include <linux/net.h>
#include <linux/in.h>
#include <linux/netpoll.h>
#define MESSAGE_SIZE 1024
#define INADDR_SEND ((unsigned long int)0x0a00020f) //10.0.2.15
static bool sock_init;
static struct socket *sock;
static struct sockaddr_in sin;
static struct msghdr msg;
static struct iovec iov;

[...]

int error, len;
mm_segment_t old_fs;
char message[MESSAGE_SIZE];

if (sock_init == false)
{
  /* Creating socket */
  error = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
  if (error<0)
    printk(KERN_DEBUG "Can't create socket. Error %d\n",error);

  /* Connecting the socket */
  sin.sin_family = AF_INET;
  sin.sin_port = htons(1764);
  sin.sin_addr.s_addr = htonl(INADDR_SEND);
  error = sock->ops->connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr), 0);
  if (error<0)
    printk(KERN_DEBUG "Can't connect socket. Error %d\n",error);

  /* Preparing message header */
  msg.msg_flags = 0;
  msg.msg_name = &sin;
  msg.msg_namelen  = sizeof(struct sockaddr_in);
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_iov = &iov;
  msg.msg_control = NULL;
  sock_init = true;
}

/* Sending a message */
sprintf(message,"EXTRACT / Time: %llu / InputPool: %4d / BlockingPool: %4d / NonblockingPool: %4d / Request: %4d\n",
  get_cycles(),
  input_pool.entropy_count,
  blocking_pool.entropy_count,
  nonblocking_pool.entropy_count,
  nbytes*8);
iov.iov_base = message;
len = strlen(message);
iov.iov_len = len;
msg.msg_iovlen = len;
old_fs = get_fs();
set_fs(KERNEL_DS);
error = sock_sendmsg(sock,&msg,len);
set_fs(old_fs);
4

2 に答える 2

15

私は数ヶ月前に私の問題を解決しました。これが私が使用した解決策です。

標準のパケット送信 API (sock_create、connect など) は、いくつかのコンテキスト (中断) では使用できません。間違った場所で使用すると、KP につながります。

netpoll API はより「低レベル」であり、あらゆるコンテキストで機能します。ただし、いくつかの条件があります。

  • イーサネット デバイス
  • IP ネットワーク
  • UDP のみ (TCP なし)
  • パケットを送受信する別のコンピュータ (自分自身に送信することはできません)。

問題が発生してもエラー メッセージは表示されないため、それらを尊重してください。黙って失敗します:) ここに少しのコードがあります。

宣言

#include <linux/netpoll.h>
#define MESSAGE_SIZE 1024
#define INADDR_LOCAL ((unsigned long int)0xc0a80a54) //192.168.10.84
#define INADDR_SEND ((unsigned long int)0xc0a80a55) //192.168.10.85
static struct netpoll* np = NULL;
static struct netpoll np_t;

初期化

np_t.name = "LRNG";
strlcpy(np_t.dev_name, "eth0", IFNAMSIZ);
np_t.local_ip = htonl(INADDR_LOCAL);
np_t.remote_ip = htonl(INADDR_SEND);
np_t.local_port = 6665;
np_t.remote_port = 6666;
memset(np_t.remote_mac, 0xff, ETH_ALEN);
netpoll_print_options(&np_t);
netpoll_setup(&np_t);
np = &np_t;

使用する

char message[MESSAGE_SIZE];
sprintf(message,"%d\n",42);
int len = strlen(message);
netpoll_send_udp(np,message,len);

それが誰かを助けることを願っています。

于 2012-08-29T10:31:54.080 に答える
2

起動中のパニックは、まだ初期化されていないものを使用しようとしたことが原因である可能性があります。スタック トレースを調べると、実際に何が起こったのかを理解するのに役立つ場合があります。

あなたの問題については、単純なことをしようとしていると思うので、単純なツールに固執しないのはなぜですか? ;) printks は確かに悪い考えかもしれませんが、trace_printk を試してみてください。trace_printk は Ftrace インフラストラクチャの一部です。

次の記事の「Trace _printk() を使用する」セクションでは、知っておく必要があるすべてのことを説明しています: http://lwn.net/Articles/365835/

于 2012-05-14T20:23:39.497 に答える