web-dev-qa-db-ja.com

LinuxでASLRランダム性はどのくらいの頻度で更新されますか?

現在、ほとんどのLinuxディストリビューションは、多くのプログラムでASLRを使用して、メモリのレイアウトをランダム化しています。

これに使用されるランダム性はどのくらいの頻度で変更されますか?同じプログラムを複数回再実行すると、毎回同じレイアウトが表示されますか、それとも毎回異なりますか?プログラムを実行するたびに新鮮なランダム性が生成されますか?マシンが再起動されるたびに?ランダムな値はいつ新しい値に更新/リセットされますか?これはLinuxディストリビューションに依存しますか?それは、私たちが話しているメモリの領域(たとえば、実行可能ファイル、動的ライブラリ、スタック、ヒープなど)に依存しますか、またはそれらすべての答えは同じですか?

7
D.W.

Wikipedia page は、答えが「依存する」ことを示しています。複数の実装とパッチがあります。

考慮すべき重要な点は次のとおりです。

  • Linux実行可能ファイルは、mainバイナリ、およびDLL(shared objets)動的にロードされます。従来のLinuxでは、メインバイナリはリンク時に選択された固定アドレスにありますが、DLLは位置に依存しないコードです。

  • LinuxのDLLは安価に「移動」できます。確かに、DLLがアドレス空間にマップされると、そのDLL(DLLそれ自体、および他のDLLとメインバイナリも同様)は、そのDLLを指すように調整する必要があります。これは、メインバイナリと一部のDLLの一部のバイトを変更する必要があることを意味します。特定の実行可能インスタンスのアドレス空間の構成に応じて異なります。ただし、修正されたpage(アーキテクチャに応じて4または8 kB)は同時に実行される他の実行可能ファイルの他のインスタンスと(物理RAMで)共有できなくなりました。これにより、RAM DLLの使用上の利点がなくなりましたtheDLLを使用する理由ですが、今日では、ソフトウェアのアップグレードの容易さが間違いなく強力な理由です)。

    Linux(およびその他のOS、特に [〜#〜] elf [〜#〜] )を使用するすべてのOSでは、この問題を回避する方法はDLLをコンパイルすることです。 = "特別に" 位置に依存しないコード :実際には、バイナリコードは、間接テーブル( "GOT "、別名"グローバルオフセットテーブル ")は、呼び出しコードに対してその位置relativeによって動的に配置されます。これは、ほとんどのDLL DLLが読み込まれると、ページは変更されないままになるため、別の実行可能ファイルのアドレス空間にある同じDLLの他のインスタンスと共有されます。

    これは、OSがそれを使用するすべてのプロセスの同じアドレスに同じDLLをロードしようとするため、参照が「適切に」変更されるように、Windowsで行われる方法とは対照的です"そして、すべてのプロセスが同じアドレスで同じDLLを参照するため、共有されます。(20年以上前、" libc4 "の時点で、DLLは「移動可​​能」ではなく、すべてのプロセスで常に固定された場所にロードされていました。)

  • メインバイナリは固定アドレスでリンクされることになっています。ただし、PIC DLLと同様のメカニズムがメインバイナリにも実装されています。これは [〜#〜] pie [〜#〜] と呼ばれています。長さ there 。PIEは一部のC以外のアプリケーションを破壊する可能性があるため、それを使用するLinuxディストリビューションは、someと見なされるアプリケーションに予約する傾向があります「脆弱」(つまり、ネットワークアクティビティのあるアプリケーション)。

  • Linuxには [〜#〜] vdso [〜#〜] も備わっています。これは、DLLから提供されるのではなく、カーネルによって提供されるASLRに対するカーネルのサポートは、プロセスごとにVDSOアドレスをランダム化します。

  • ランダム化にはスペースが必要であるため、スペースの断片化の問題に対処している可能性があります(空きスペースがいくつかの小さな穴に分割されているため、大きなブロックの割り当てが失敗する可能性があります)。これは、32ビットのLinuxバリアントに特に当てはまります。 64ビットアーキテクチャでは、問題を回避するために、アドレススペースはまだ十分に大きい(物理RAMサイズと比較して)。したがって、ASLRは、写真/ビデオ編集などの一部のアプリケーションでは無効にする必要がある場合がある。これは、プロセスごとに setarch を使用して実行できます。

これらから、以下を取得します:

  • ASLRがLinuxに適用される場合、通常はプロセスごとに適用されます。同じプロセスを2回開始すると、DLLが異なるアドレスにロードされます(PIE用にコンパイルされている場合は、メインバイナリもロードされます)。これは、 gdb、そして実際、バグを追跡する場合、最初に行うことは ASLRを無効にする です。

  • Prelink が適用されている場合、ASLRを防止します(少なくともDLLおよびバイナリの場合。ヒープとスタックの位置はランダム化される可能性があります)。Prelinkは、ランダム化を行うことによってこれを相殺し、しかし、構築により、これは実行可能ファイルごとに修正されます。事前にリンクされた実行可能ファイルは、バイナリとDLLが常に同じ場所にありますが、同じ上にある他の事前にリンクされた実行可能ファイルはマシンは同じDLLを異なるアドレスで参照します。これはマシン固有であるため、他のマシンは異なるレイアウトのアドレススペースを取得します。また、新しいプレリンクを定期的に実行することをお勧めします(例:毎週)、再ランダム化します(evey DLL upgradeの場合も同様)。

  • スタックとヒープもランダム化されます。初期スタック位置とヒープの開始点(brk()システムコール用)は、プロセスの開始時にカーネルによって選択され、実行ごとに新しい場所に配置されます(ASLRが有効になっている場合) )。また、メモリアロケータはランダム化されたmmap()(通常は大きなブロックに対してそうします)に依存する場合があり、これは動的に割り当てられるスレッドスタックにまで及びます。デフォルトでは、 glibc は、128 kBを超えるブロックに対してmmap()呼び出しを使用し、新しいスレッドのスタックはデフォルトで1 MBになります。

  • プロセスが forked の場合、子は必然的に親と同じレイアウトを取得します。ただし、DLLフォークの後に読み込まれると、異なるアドレスに到達する可能性があります。

これらのすべてはカーネルのバージョンとパッチ、および構成可能なオプションに依存するためしたがって、質問への回答は必然的にディストリビューションに依存します。たとえば、Ubuntuでの状況を見ることができます there (基本的に、ASLRはどこでも、PIEは特定のパッケージリストのみ、プレリンクはありません)。唯一の共通点は、LinuxのASLRがブートに依存しないことです。各プロセスインスタンスにランダム化が適用されていない場合、これは再リンク後も永続的なプリリンクが原因です(ただし、定期的に再適用する必要があります)。

8
Thomas Pornin

スタックとmmap割り当てを調整するためのASLRランダム性は、新しいプロセスごとにカーネルの内部get_random_int関数によって生成されます。

get_random_intは、CPUでサポートされている場合、RDRAND命令を使用してランダムな値を生成します。他のCPUでは、ブート時にカーネルの非ブロッキング(/dev/urandom)プールから一度初期化されるPRNGを使用します。 (このPRNGは、暗号化による安全ではなく、高速になるように最適化されています。)

動的リンカー/ローダー( ld.so 、glibcの一部)はmmapを使用して実行可能ファイルと共有ライブラリーをロードします。

つまり、一番下の行:スタックの場所とmmap割り当て(ヒープと実行可能ファイルを含む)はランダムであり、新しいプロセスごとに異なります。

2
CL.