GNU/Linux >> Linux の 問題 >  >> Linux

セキュリティのためにヒープがゼロで初期化されている場合、スタックが単に初期化されていないのはなぜですか?

malloc() によって返されるストレージはそうではありません ゼロ初期化。そうだと思い込まないでください。

あなたのテスト プログラムでは、それはただのまぐれです:malloc() mmap() から新しいブロックを取得しました 、しかしそれに頼らないでください。

たとえば、あなたのプログラムを私のマシンでこのように実行すると:

$ echo 'void __attribute__((constructor)) p(void){
    void *b = malloc(4444); memset(b, 4, 4444); free(b);
}' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036

2 番目の例は、単純に malloc のアーティファクトを公開することです glibc での実装。 malloc を繰り返すと /free 8 バイトを超えるバッファを使用すると、次のサンプル コードのように、最初の 8 バイトだけがゼロになっていることが明確にわかります。

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()
{
    for (size_t i = n; i; --i) {
        int *const p = malloc(m*sizeof(int));
        printf("%p ", p);
        for (size_t j = 0; j < m; ++j) {
            printf("%d:", p[j]);
            ++p[j];
            printf("%d ", p[j]);
        }
        free(p);
        printf("\n");
    }
    return 0;
}

出力:

0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4

スタックがどのように初期化されても、C ライブラリは main を呼び出す前に多くの処理を行うため、元のスタックは表示されません。 、そしてそれらはスタックに触れます。

GNU C ライブラリを使用すると、x86-64 では、_start エントリ ポイントで実行が開始され、__libc_start_main が呼び出されます。 物事をセットアップするために、後者は main を呼び出すことになります . main を呼び出す前に 、他の多くの関数を呼び出し、さまざまなデータがスタックに書き込まれます。スタックの内容は関数呼び出し間でクリアされないため、main に入ると 、スタックには以前の関数呼び出しの残り物が含まれています。

これは、スタックから取得した結果のみを説明しています。一般的なアプローチと仮定に関する他の回答を参照してください。


どちらの場合も、初期化されていません その内容について推測することはできません。

OS がプロセスに新しいページを割り当てる必要がある場合 (それがスタック用か、malloc() によって使用されるアリーナ用か) )、他のプロセスからのデータを公開しないことを保証します。それを確実にする通常の方法は、それをゼロで埋めることです(ただし、 /dev/urandom のページを含む、他のもので上書きすることも同様に有効です - 実際、いくつかのデバッグ malloc() 実装は、ゼロ以外のパターンを記述して、あなたのような誤った仮定をキャッチします)。

malloc() の場合 すでに使用され、このプロセスによって解放されたメモリからの要求を満たすことができる場合、その内容はクリアされません (実際、クリアは malloc() とは関係ありません) それはできません-メモリがアドレス空間にマップされる前に発生する必要があります)。プロセス/プログラムによって以前に書き込まれたメモリを取得する場合があります (例:main() より前) ).

サンプル プログラムでは、malloc() が表示されています。 このプロセスによってまだ書き込まれていない領域 (つまり、新しいページからの直接の領域) と、(main() より前に) 書き込まれたスタック プログラムのコード)。スタックをさらに調べると、(成長の方向で) さらに下にゼロが埋め込まれていることがわかります。

OS レベルで何が起こっているかを本当に理解したい場合は、C ライブラリ レイヤーをバイパスし、brk() などのシステム コールを使用して対話することをお勧めします。 と mmap()


Linux
  1. サーバーが私のIPをブロックしたのはなぜですか?

  2. ファイル内の複数の文字列のGrepを実行し、サイズ順にファイルを一覧表示しますか?

  3. ヒアドキュメントの親シェルがダッシュのサブコマンドでは機能しないのに、Bashは機能するのはなぜですか?

  1. cPanelがウェブサイトデザイナーにとって最良のソリューションである理由

  2. .bss セグメントが必要なのはなぜですか?

  3. free コマンドと dmidecode で表示される RAM の値が異なるのはなぜですか?

  1. BCRYPT - Linux ディストリビューションがデフォルトで使用しないのはなぜですか?

  2. OOM-Killer が要求しすぎるプロセスを強制終了できないのはなぜですか?

  3. 最近の Linux では、デフォルトのスタック サイズが 8 MB (一部のディストリビューションでは 10 MB) と非常に大きいのはなぜですか?