回答:
実際、ほとんどのプラットフォームでは、エラーで失敗するだけですが、それはハードウェアアーキテクチャによって異なります。非特権ユーザーとしてコマンドを実行しない限り、これが無害であるという保証はほとんどありません。権限のないユーザーの場合、コマンドを開くことができないため、コマンドは完全に無害です/dev/mem
。
rootとしてコマンドを実行すると、自分が何をしているかがわかるはずです。カーネルは時々危険なことをすることを防ぎますが、常にではありません。/dev/mem
自分が何をしているかを本当に知っているはずの、潜在的に危険なことの1つです。
/dev/mem
Linuxで書き込みがどのように機能するかを説明します。一般的な原理は他のUnicesでも同じですが、カーネルオプションなどはまったく異なります。
プロセスがデバイスファイルを読み書きするときに何が起こるかは、カーネル次第です。デバイスファイルへのアクセスは、このデバイスファイルを処理するドライバーでいくつかのコードを実行します。たとえば、への書き込みにより/dev/mem
の関数write_mem
がdrivers/char/mem.c
呼び出されます。この関数は4つの引数を取ります。開いているファイルを表すデータ構造、書き込むデータへのポインター、書き込むバイト数、およびファイル内の現在の位置です。
呼び出し元が最初にファイルを開く権限を持っている場合にのみ、これまでに取得することに注意してください。デバイスファイルは、通常、ファイルのアクセス許可に従います。の通常の権限は/dev/mem
がcrw-r-----
所有root:kmem
しているため、rootにならずに書き込み用に開こうとすると、「権限が拒否されました」(EACCESS)になります。しかし、あなたがrootである場合(またはrootがこのファイルのアクセス権を変更した場合)、オープニングは通過し、書き込みを試行できます。
write_mem
関数内のコードはいくつかの健全性チェックを行いますが、これらのチェックだけではすべての問題から保護するのに十分ではありません。まず、現在のファイル位置*ppos
を物理アドレスに変換します。それが失敗した場合(実際には、32ビットの物理アドレスを持つプラットフォーム上に64ビットのファイルオフセットがあり、ファイルオフセットが2 ^ 32より大きいため)、書き込みはEFBIG(ファイルが大きすぎる)で失敗します。次のチェックは、書き込む特定の物理アドレスの範囲がこの特定のプロセッサアーキテクチャで有効であるかどうかであり、障害が発生するとEFAULT(不良アドレス)が発生します。
次に、Sparcとm68kでは、最初の物理ページでの書き込みのどの部分も黙ってスキップされます。
これで、1つのMMUページに収まるブロック内のデータを反復処理するメインループに到達しました。
は、仮想メモリではなく物理メモリにアクセスしますが、データをメモリにロードして格納するプロセッサ命令は仮想アドレスを使用するため、コードは物理アドレスを仮想アドレスにマップするように調整する必要があります。Linuxでは、プロセッサアーキテクチャとカーネル構成に応じて、このマッピングは永続的に存在するか、オンザフライで作成する必要があります。それが仕事です(そして何をしても元に戻します)。次に、関数は渡されたバッファから読み取ります/dev/mem
xlate_dev_mem_ptr
unxlate_dev_mem_ptr
xlate_dev_mem_ptr
copy_from_user
write
システムコールし、物理メモリが現在マップされている仮想アドレスに書き込むだけです。コードは通常のメモリストア命令を発行し、これが何を意味するかはハードウェア次第です。
物理アドレスへの書き込みについて説明する前に、この書き込みの前に行われるチェックについて説明します。ループ内ではpage_is_allowed
、カーネル構成オプションCONFIG_STRICT_DEVMEM
が有効になっている場合(デフォルトではこの場合)、関数は特定のアドレスへのアクセスをブロックします。許可されたアドレスにのみdevmem_is_allowed
到達できます。/dev/mem
その他の場合、EPERMで書き込みが失敗します(操作は許可されません)。このオプションの説明は次のとおりです。
このオプションがオンで、IO_STRICT_DEVMEM = nの場合、/ dev / memファイルは、PCIスペースとBIOSコードおよびデータ領域へのユーザースペースアクセスのみを許可します。これは、dosemuとX、および/ dev / memのすべての一般的なユーザーにとって十分です。
これは非常にx86中心の説明です。実際、より一般的には、CONFIG_STRICT_DEVMEM
RAMにマップする物理メモリアドレスへのアクセスをブロックしますが、RAMにマップしないアドレスへのアクセスを許可します。許可される物理アドレスの範囲の詳細は、プロセッサアーキテクチャによって異なりますが、カーネルとユーザーランドプロセスのデータが保存されているRAMはすべて除外されます。追加オプションCONFIG_IO_STRICT_DEVMEM
(Ubuntu 18.04では無効)は、ドライバーが要求する物理アドレスへのアクセスをブロックします。
RAMにマップする物理メモリアドレス。それでは、RAMにマップしない物理メモリアドレスはありますか?はい。これは、アドレスに書き込むことが何を意味するかについて上記で約束した議論です。
メモリストア命令は必ずしもRAMに書き込む必要はありません。プロセッサはアドレスを分解し、ストアをディスパッチするペリフェラルを決定します。(私が「プロセッサ」と言うとき、私は同じ製造元から来ていないかもしれない周辺機器コントローラを含みます。)RAMはそれらの周辺機器の1つにすぎません。ディスパッチがどのように行われるかは、プロセッサアーキテクチャに大きく依存しますが、基本はすべてのアーキテクチャでほぼ同じです。プロセッサは基本的にアドレスの上位ビットを分解し、ハードコードされた情報、一部のバスをプローブして得られた情報、およびソフトウェアによって構成された情報に基づいて入力されたいくつかのテーブルでそれらを検索します。多くのキャッシングとバッファリングが含まれる可能性がありますが、簡単に言えば、この分解の後、バスとそれを処理するのは周辺機器次第です。(または、テーブルルックアップの結果、このアドレスにペリフェラルが存在しない可能性があります。その場合、プロセッサはトラップ状態に入り、通常は呼び出しプロセスのSIGBUSとなるカーネル内のコードを実行します。)
RAMにマップするアドレスへのストアは、以前にこのアドレスに格納されていた値を上書きする以外は何も「実行」せず、同じアドレスで後でロードすると最後に格納された値が返されることが保証されます。ただし、RAMにも、このように動作しないアドレスがいくつかあります。リフレッシュレートや電圧などを制御できるレジスタがいくつかあります。
一般に、ハードウェアレジスタへの読み取りまたは書き込みは、ハードウェアが実行するようにプログラムされているものは何でも実行します。ハードウェアへのほとんどのアクセスはこのように機能します。ソフトウェア(通常はカーネルコード)は特定の物理アドレスにアクセスし、これがプロセッサをペリフェラルに接続するバスに到達し、ペリフェラルがその役割を果たします。一部のプロセッサ(特にx86)には、メモリのロードおよびストアとは異なるペリフェラルへの読み取り/書き込みを引き起こす個別のCPU命令もありますが、x86でも、ロード/ストアを介して多くのペリフェラルに到達します。
このコマンドdd if=/dev/urandom of=/dev/mem
は、アドレス0(および書き込みが成功する限り、後続のアドレス)にマップされているペリフェラルにランダムデータを書き込みます。実際には、多くのアーキテクチャでは、物理アドレス0にペリフェラルがマッピングされていないか、RAMが割り当てられているため、最初の書き込みは失敗します。ただし、アドレス0にマップされたペリフェラルがある場合、またはコマンドを変更して別のアドレスに書き込む場合、ペリフェラルで予測できない何かがトリガーされます。ランダムなデータが増加するアドレスにあると、興味深いことをする可能性はほとんどありませんが、原則として、コンピューターの電源をオフにし(実際にこれを実行するアドレスがある可能性があります)、ブートを不可能にするBIOS設定を上書きしたり、それを損傷する方法でバギー周辺機器。
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
CONFIG_STRICT_DEVMEM
有効になっている場合、実際にはカーネルを損傷することはできません。
マニュアルページごとのmem(4):
/ dev / memは、コンピューターのメインメモリのイメージであるキャラクターデバイスファイルです。これは、たとえば、システムを検査(およびパッチを適用)するために使用できます。
したがって、理論dd if=/dev/urandom of=/dev/mem
的には、インストールした物理メモリのアドレス空間全体を上書きする必要があります。カーネルやその他のプログラムはメモリから実行されるため、システムを効果的にクラッシュさせるはずです。実際には限界があります。同じmanページから:
Linux 2.6.26以降、アーキテクチャによっては、CONFIG_STRICT_DEVMEMカーネル構成オプションにより、このファイルを介してアクセスできる領域が制限されています。
これを仮想マシンUbuntu 18.04で試すと、rootの権限がdd: writing to '/dev/mem': Operation not permitted
あってもなくてもエラーが返されます。Ubuntu Wikiから:sudo
crw-r-----
/ dev / mem保護
一部のアプリケーション(Xorg)では、ユーザー空間から物理メモリに直接アクセスする必要があります。このアクセスを提供するために、特別なファイル/ dev / memが存在します。以前は、攻撃者がrootアクセス権を持っている場合、このファイルからカーネルメモリを表示および変更することが可能でした。CONFIG_STRICT_DEVMEMカーネルオプションは、非デバイスメモリアクセスをブロックするために導入されました(元の名前はCONFIG_NONPROMISC_DEVMEM)。
つまり、技術的には安全ではありません(システムをクラッシュさせるため)。カーネルオプションCONFIG_STRICT_DEVMEM
が無効になっているとセキュリティホールになりますが、これまでのところ、そのオプションが有効になっているとコマンドは実行されません。クロスサイト複製によると、再起動で問題が修正されますが、もちろん、その時点でのRAM内のデータは失われ、ディスクにフラッシュされません(必要な場合)。
以前にリンクを使用して複製された複製に推奨される方法があるbusybox devmem
ため、RAMをいじくり回すことが決まっている場合は、やっぱり方法があるかもしれません。
CONFIG_STRICT_DEVMEM
、ペリフェラルがマップされているメモリ領域にアクセスできます/dev/mem
。これがの重要なポイントです。周辺機器にランダムなものを書き込むと、何かが起こる可能性があります。マップされていないアドレスにアクセスしようとすると、「操作は許可されません」というメッセージが表示され、コマンドはアドレス0から始まります。アドレス0が何かにマップするかどうかは、ハードウェアアーキテクチャによって異なります。PCのどこにもマッピングされない可能性があることはすべて知っていますが、一般的に安全ではありません。
head -c 1024 </dev/mem | od -tx1
)が、プロセッサがリアルモード(8088モード)でないときにこれらが使用されるかどうかはわかりません。私はそれらが64ビットモードで使用できるとは思いません。結局のところ、8088割り込みベクトルはアドレスに32ビットしかありません。ちなみに、これはCONFIG_STRICT_DEVMEM
setでアクセスできるので、Linuxでは使用しないと思います。