vsyscallセグメントとvDSOセグメントは、Linuxで特定のシステムコールを高速化するために使用される2つのメカニズムです。たとえば、gettimeoftheday
通常、このメカニズムを介して呼び出されます。導入された最初のメカニズムはvsyscallでした。これは、システムコールのオーバーヘッドを削減するために、実行するために実際のレベルの特権を必要としない特定のシステムコールを実行する方法として追加されました。前の例gettimeofday
に従う必要があるのは、カーネルの現在の時刻を読み取ることだけです。gettimeofday
少しでもオーバーヘッドを気にするほど頻繁に呼び出す(タイムスタンプを生成するなど)アプリケーションがあります。この懸念に対処するために、カーネルは現在の時刻と高速を含むページをユーザースペースにマップしますgettimeofday
実装(つまり、vsyscallに節約された時間を読み取る関数)。この仮想システムコールを使用すると、Cライブラリは、従来のシステムコールモデルまたはgettimeofday
によって通常導入されるカーネルスペースとユーザースペースの間のコンテキストスイッチによって導入されるオーバーヘッドのない高速を提供できます。INT 0x80
SYSCALL
ただし、このvsyscallメカニズムにはいくつかの制限があります。割り当てられるメモリは小さく、4つのシステムコールしか許可されません。さらに重要で深刻なのは、vsyscallページの場所が次のようになっているため、 vsyscallページが各プロセスの同じアドレスに静的に割り当てられることです。カーネルABIに釘付け。このvsyscallの静的割り当ては、Linuxで一般的に使用されるメモリ空間のランダム化によってもたらされる利点を損ないます。攻撃者は、スタックオーバーフローを悪用してアプリケーションを侵害した後、 vsyscallからシステムコールを呼び出すことができます。任意のパラメータを持つページ。彼に必要なのはシステムコールのアドレスだけです。これは静的に割り当てられているため、簡単に予測できます(異なるアプリケーションでもコマンドを再実行しようとすると、vsyscallのアドレスが変更されないことがわかります)。このタイプの攻撃を阻止するには、vsyscallページの場所を削除するか、少なくともランダム化するとよいでしょう。残念ながら、アプリケーションはそのページの存在と正確なアドレスに依存しているため、何もできません。
このセキュリティの問題は、すべてのシステムコール命令を特別なトラップ命令によって修正されたアドレスに置き換えることで解決されました。vsyscallページを呼び出そうとするアプリケーションは、カーネルにトラップされ、カーネル空間で目的の仮想システムコールをエミュレートします。結果は、最初にカーネルシステムコールを回避するためにそこに配置された仮想システムコールをエミュレートするカーネルシステムコールです。その結果、実行に時間がかかるvsyscallが生成されますが、重要なことに、既存のABIが破損することはありません。いずれの場合も、アプリケーションがvDSOではなくvsyscallページを使用しようとしている場合にのみ速度低下が見られます。vDSO _制限を克服しながら、vsyscallと同じ機能を提供します。vDSO(仮想動的リンク共有オブジェクト)は、ユーザースペースに割り当てられたメモリ領域であり、ユーザースペースの一部のカーネル機能を安全な方法で公開します。これは、によって引き起こされるセキュリティの脅威を解決するために導入されましたvsyscall
。vDSOは動的に割り当てられるため、セキュリティ上の懸念が解決され、4つを超えるシステムコールを実行できます。vDSOリンクは、glibcライブラリを介して提供されます。リンカは、そのようなルーチンに.などのvDSOバージョンが付随している場合、 glibcvDSO機能にリンクします。プログラムの実行時に、カーネルがvDSOをサポートしていない場合は、従来のシステムコールが実行されます。gettimeofday
クレジットと便利なリンク: