web-dev-qa-db-ja.com

Java nullポインタが逆参照されるコードに悪用のリスクが実際にあるか

私は一般的によく書かれて解析されたいくつかのJava=コードで遊んでいますが、コードスキャンツールによっていくつかの奇妙な点が投げ出されています。

Nullポインターの逆参照がプログラムをクラッシュさせる可能性があることは知っていますが、すべての例外をキャッチして管理するようにコードが記述されているとすれば、この問題を使用する可能性のある実際の攻撃を知っている人はいますか?

感謝して受け取ったコードスニペット:-)

9
Rory Alsop

Nullのポインタを使用しようとすると、Javaは NullPointerException をスローします。これはRuntimeExceptionなので、キャッチする必要はありませんが、 。たとえば、

String iAmNull = null;
iAmNull.trim();

nullPointExceptionをスローし、プログラムを終了します。しかしそれを捕まえれば

try {
    String iAmNull = null;<br>
    iAmNull.trim();<br>
} catch (NullPointerException e) {
    log.warn("Null pointer in method x")
}

それは実行を続け、エラーを記録するだけです(もちろん、ロガーをセットアップしている場合)。または、Exception eをキャッチすることもできます。

Javaのnullポインタに基づく攻撃は、Java仮想マシンがすべてのポインタを処理するため、理論的には不可能です。したがって、コード内のNullPointer。

13
Andreas Arnold

理論的には、Javaでのあらゆる種類のnullポインターの逆参照によりNullPointerExceptionがトリガーされ、他の例外と同様にJava内で処理できます。これは、これがgoodであることを意味するものではありません。実際には、障害のある部分を削除する(つまり、呼び出しスレッドを終了させる、またはキャッチに戻る)ことを除いて、このような例外からの回復は非常に困難です。すべての句)。 nullポインタをたどることは、バッファのオーバーランに似ています。それはまだバグです。ここでのJavaと保護されていない言語(Cなど)の違いは、Javaがそのバグの影響についてより優雅であることです。特に、例外は呼び出しに伝播されますスタック、モニターの解放(synchronizedキーワード)、およびfinally句の実行、そして障害のあるスレッドのみが影響を受けます。

ただし、実際には、いくつかの問題が発生する可能性があります。 JVMがnullポインター逆参照をトラップする方法は、JVM実装次第です。しかし、実装が通常行うことは次のとおりです。それらはポインタに従うだけです。ポインタがnullの場合、メモリの最初のページでメモリアクセスが発生しますが、これはOSによってアクセスが禁止されています。 OSは発生を(MMUを介して)キャッチし、比較的残酷な方法でアプリケーションに通知します(Unixのようなシステムでは、これはSIGSEGVシグナルです)。 JVMは情報を受け取り、それをNullPointerExceptionに変換します。

シグナルから例外への変換は、JVMがバイトコードインタープリターまたはJITで生成されたバイナリコードのどこかにある問題のあるオペコードアドレスのみを受け取るため、複雑です。 JVMはメソッドとスレッドスタックを見つける必要があります。これは、OSが最初にメモリに物を置く方法といくつかの細かい相互作用があります。このようなコードは、今日、主流のプラットフォームで非常に安定しています。ただし、あまり一般的でない組み合わせ(SunのJDKがFreeBSDに移植された)では、JVMが呼び出し側スタックを見つけられないnullポインター逆参照が発生することがありました(JVMコードがFreeBSD用ではなくLinux用に調整されていたため、スタックがどこにあるべきかという仮定、FreeBSDで常に満たされるとは限らない仮定)。その結果、JVMがすぐに終了しました。

もう1つの問題は、アクセスが「禁止された」ページのどこかにあるため、nullポインターの逆参照がキャッチされることです。つまり、アドレス空間の最初のページです。ただし、インスタンスフィールドにアクセスする場合、JVMは通常、適切なデータ要素に直接アクセスします。参照がネイティブコードレベルで、アドレスへのポインターである場合xであり、フィールドがオフセットにある場合nオブジェクト構造の場合、コードはアドレスでバイトを読み取りますx + n(これは、JVMがオブジェクトを内部的にどのように表すかに依存しますが、Cのような構造が一般的です)。クラスに多くのフィールドがある場合、nはページのサイズよりも大きくなる可能性があります。その場合、読み取りアクセスは最初のページではなく2番目のページになります。その状況で何が起こるかは、オペレーティングシステムによって異なります。

配列アクセスでは長さがチェックされ、「長さ」は通常、オブジェクトヘッダーに近い一種のフィールドであるため、「高オフセットのフィールド」の状況は配列では発生しません。また、Javaクラスのフィールド数には制限があります(クラスファイル形式では65535までの絶対的な制限があります。実際には、各フィールドに名前とタイプが必要であるため、これよりも低くなります。これもクラスファイル形式であり、それよりも早く他の制限に達します)。したがって、問題は「一般的な」システムでは発生しません。 Sun/Oracle VMを実行するLinux。これは主にVMの実装者が知っておくべきことです。

したがって、私のアドバイスは、バッファオーバーフロー(JavaではNullPointerException)と同様に、IndexOutOfBoundsExceptionを深刻なバグと見なすことです。 VM安全性は、コードのデバッグに役立ち(スタックトレースは非常に便利です)、展開前に十分にデバッグしなかった場合は、おそらくスキンが節約されます。しかし、バグはバグです。

20
Thomas Pornin

CWE-476:NULLポインター逆参照 -コード実行は非常にまれな状況で可能であり、環境は可能であると述べています。ただし、これはJavaに固有のものではありません。 Javaに対するエクスプロイトがnullポインタの違いに基づいており、どれも見つけることができなかったかどうかを確認するために、考えられるすべてのエクスプロイトWebサイトをチェックしました。

しかし、周りを見回していると、Certサイトでこのページを見つけました- EXC15-J。NullPointerExceptionをキャッチしないでください 。彼らは、NullPointerExceptionをキャッチすることはせいぜい最適ではなく、例外を回避するためにチェックを追加する代わりに大幅に遅くなると述べています。したがって、アプリケーションによっては、検討する必要がある可能性があります。

6
Mark Davidson

Javaコード内のnullを逆参照すると、NPEが発生します。Cとは異なり、マップされたメモリにランドするオフセットを追加する方法はありません。NPEは、キャッチするか、スレッドのキャッチされない例外ハンドラーに渡します。

Javaの実際の脆弱性の原因は、本来あるべきではない場所でnullsを受け入れています。null変数のコードをスキップすることは、実際に実行してNPEするよりも危険です。たとえば、 ClassLoader参照は機能ですが、最も重要なクラスローダー(ブートクラスローダー)は通常、nullで示されます(一部のJava APIは、提供されるクラスローダー参照はnull)です。