web-dev-qa-db-ja.com

Objective Cは(本当に)バッファオーバーフローの影響を受けますか?

私はObjective-Cでバッファオーバーフローのサンプルコードを見つけようとしていますが、見つかったサンプルはCで書かれているだけです(「ブラケットスタイル」なし)。

私はObjective-CがCに基づいていることを理解していますが、only Objective-Cを使用してバッファオーバーフロー(または任意の種類のオーバーフロー)が発生する可能性はありますか?

それを示すサンプルコードはありますか?

前もって感謝します。

1
John Kravicz

編集:コードサンプルを追加

Objective-CはCのスーパーセットです。 Cで実行できることはすべてObjective-Cで実行できます。これには、(バッファオーバーフローのように)したくないことがたくさんあります。 .cソースファイルを取得し、拡張子を.mに変更し、それをObjective-Cコンパイラでコンパイルしても、バッファオーバーフローは防止されません。

さらに、Objective-C言語自体は境界チェックされていません。静的バッファー(Cで使用されているように、_int foo[16]_またはmalloc(100)から取得するもの)は、Objective-Cで本質的にサポートされている唯一のインデックスアクセス可能なデータ構造であり、あなたを妨げるものは何もありません。 1つの境界の外での読み取りまたは書き込み。

ただし、Objective-Cコードの大部分は、1つ以上の配列クラス(NSArrayなど)を含むクラスのライブラリを提供する「キット」または「フレームワーク」(CocoaやGNUstepなど)を使用して記述されています。 )、これらのクラスは境界チェックされる場合があります。 NSArrayのようなものは、チェックされていないメモリバッファをバッキングストアとして使用する必要がありますが(直接または他の配列クラスをラップすることにより)、そのバッファを直接公開する必要はありません。代わりに、バッファからの読み取りまたは書き込みの前に境界チェックを実行するメソッドを呼び出す _objectAtIndex:_ などのメッセージをサポートします。

これらのライブラリクラスのインターフェイスでさえ、Cスタイルのメモリバッファと相互作用する場合があります。その場合、通常、バッファのサイズが正しいことを確認するためにユーザーに依存しています。それを誤ると、バッファのオーバーリードまたはオーバーフローが発生する可能性があります。これは、誤ったサイズパラメータを渡した関数のすぐ内側、または後で指定したサイズの内側であるが、バッファの実際のサイズの外側にある場所にアクセスしようとしたときに発生します。いくつかの例については、NSArrayメソッド _arrayWithObjects:count:_ および _getObjects:range:_ を参照してください。これらは、プログラマーがCスタイルの配列を指定し、そのいずれかを指定する必要があります。サイズまたは少なくともそのサイズが十分であることを知っています。これらの関数は、それぞれオーバーリードまたはオーバーフローを引き起こす可能性があります。

Appleは最近(言語の35年の歴史と比較して)、NSArrayなどのコレクションへのCスタイルの配列アクセスのサポートを追加しましたが、これはコレクションと対話する既存の方法の単なる構文上のシュガーです。 _myNSArray[2]_を使用してCスタイルの配列の3番目の要素を取得するのと同じように、_array[2]_を使用してNSArrayの3番目の要素を取得できますが、内部の動作は完全に異なります。 Cスタイルの配列によるインデックス付けは、単なるポインタ演算です(_array[7]_は*(array+7)とまったく同じです。それ自体は等価です-少なくともx86/x64のようなバイトアドレス可能なプラットフォームでは、「配列」はpointer-to-int-to *((int*)(((uintptr_t)array)+(sizeof(int)*7)))または*((int*)(((char*)array)+(sizeof(int)*7)))になり、x86アセンブリの1行で完全に実装できることがよくあります。比較すると、_myNSArray[7]_は、 _[myNSArray objectAtIndex:7]_はメソッド呼び出しです。境界チェックが実装されているのはそのメソッド内であり、境界外である場合は例外が発生し、NSArrayをサポートするCスタイルのバッファへのインデックス付けが行われ、最後に取得したオブジェクトが返されます。

つまり、要約すると、

  • objective-Cで境界チェックされたコレクションのみを使用し、ライブラリにCスタイルのバッファーバッキングストアへのすべてのアクセスを処理させる
  • 関数/レシーバーが指示されたバッファーの境界を認識できない、または強制しない場合は、個人的にポインター演算を行ったり、関数を呼び出したりしないでください。
  • cスタイルの配列をとる関数を直接または間接的に呼び出したり、それらの境界やインデックスを提供することを期待したりしないでください。

そうすれば、Objective-Cがバッファオーバーフローの影響を受けないように安全に見せかけることができます。 (使用するライブラリにバグがあり、境界チェックが失敗したり、正しく実行されなかったりする可能性があるため、「ほぼ安全」と言います。)これらのルールに従わない場合、またはこれらのルールに従わないことによって汚染されたデータを処理する場合、あなたは危険にさらされています...たとえあなたがObjective-Cレシーバーに「ブラケットスタイル」メッセージを使っているとしても。


_// Code example for a buffer overflow in Objective-C.

// NSArray with 6 Objective-C elements
NSArray *myArray = @[ @"Buffer", @"overflows", @"can", @"happen", @"in", @"Objective-C" ];
// NSRange within the bounds of the array
NSRange myRange = NSMakeRange(1, 4);
// Buffer with room for 2 Objective-C objects
id buffer[2];
// Use an NSArray method with "bracket style" syntax to copy data to the buffer
[myArray getObjects:buffer range:myRange];
// Boom
_
5
CBHacking

C関数にフォールバックせずにバッファオーバーフローを引き起こすことができる、工夫されていない方法は考えられません。

SonarSourceにはObjective-Cソースコード監査に適したルールがいくつかあり、この領域での唯一のルールはC関数を探すことです: https://rules.sonarsource.com/objective-c/RSPEC-1081

さらに... Swift技術的には、「unsafe」という名前を適切に含むいくつかの関数が原因で、バッファオーバーフローが依然として可能です。私の理解では、これらはC-方法のように。

0
hiburn8