プログラムスタックサイズ

プログラムスタックサイズ

各プロセスのデフォルトのスタック サイズは 8MB に制限されており、mmap_base は rlimit のスタック サイズとランダム値に基づいて計算されることを知りました。以下のコードは、x86(linux/include/uapi/asm-generic/resource.h) で mmap_base アドレスを計算する mmap_base 関数です。

static unsigned long mmap_base(unsigned long rnd)
{
    unsigned long gap = rlimit(RLIMIT_STACK);

    if (gap < MIN_GAP)
        gap = MIN_GAP;
    else if (gap > MAX_GAP)
        gap = MAX_GAP;

    return PAGE_ALIGN(TASK_SIZE - gap - rnd);
}

プログラム スタック サイズが 8MB+rnd 値より大きい場合はどうなるのでしょうか。つまり、スタック サイズが mmap_base を超えて大きくなったらどうなるのでしょうか。8MB を超えるスタック メモリを割り当てると、セグメンテーション違反で失敗するだけでしょうか。カーネルがスタック サイズを自動的に拡大する場合、mmap_base 内のコンテンツを他のスペースに移動することは可能ですか。

答え1

プロセスのメイン スレッド スタック サイズは、設定された制限より大きくすることはできません。この制限の既定値は 8 MB です。この制限を超えると、セグメンテーション違反が発生し、プロセスにシグナルが送信されSIGSEGV、既定ではプロセスが強制終了されます。スタックの最大サイズは、ulimit -sプログラムを起動する前に変更できます。カーネルは、プログラムが起動された後、メモリ領域 (mmap 領域など) を移動しません。また、移動後に間違ったアドレスを指すポインタがこの領域を指すため、移動できません。

ただし、スタック オーバーフローのチェックはスタック メモリがアクセスされるときに実行されるため、スタック上で大きな割り当てを実行したり、スタック ポインターの値を変更したりするだけでは、必ずしも障害が発生するわけではありません。

2017 年の夏には、この動作を悪用する可能性についての話がありました。攻撃者がプログラムを騙して大量のメモリを割り当てることができれば、スタック ポインターがガード領域をスキップし、代わりに有効だが別の領域を指すようになります。これにより、プロセスを制御できる巧妙なトリックが生まれます。このlwn.netの記事この問題に関する議論のため。

関連情報