[インデックス 13566] ファイルの概要
コミット
commit 3f34248a7712e451b4217aa135e9236e93ece964
Author: Russ Cox <rsc@golang.org>
Date: Fri Aug 3 15:27:35 2012 -0400
cmd/ld: add PT_PAX_FLAGS ELF header
PAX systems are Linux systems that are more paranoid about memory permissions.
These flags tell them to relax when running Go binaries.
Fixes #47.
R=iant
CC=golang-dev
https://golang.org/cl/6326054
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3f34248a7712e451b4217aa135e9236e93ece964
元コミット内容
cmd/ld: add PT_PAX_FLAGS ELF header
PAXシステムは、メモリパーミッションに関してより厳格なLinuxシステムです。 これらのフラグは、Goバイナリを実行する際にPAXシステムに緩和を指示します。
Fixes #47.
変更の背景
このコミットは、Go言語のリンカ (cmd/ld
) に PT_PAX_FLAGS
というELFヘッダを追加するものです。背景には、PaX (Patch for eXecutable) と呼ばれるLinuxカーネルのセキュリティ機能との互換性の問題がありました。
PaXは、メモリの実行権限を厳しく制限することで、バッファオーバーフローなどのメモリ関連の脆弱性を悪用した攻撃を防ぐことを目的としたセキュリティパッチです。具体的には、データ領域からのコード実行を禁止したり、アドレス空間配置のランダム化 (ASLR) を強化したりします。
しかし、Go言語のランタイムは、ガベージコレクションやコルーチン (goroutine) のスタック管理などの内部的な動作のために、実行時にメモリ領域のパーミッションを変更する (mprotect
システムコールを使用する) ことがあります。PaXが有効なシステムでは、このような動的なメモリパーミッションの変更がセキュリティポリシーに違反すると見なされ、Goバイナリがクラッシュしたり、正しく動作しなかったりする問題が発生していました。
この問題は、GoプロジェクトのIssue #47として報告されていました。このコミットは、GoバイナリがPaXシステム上で適切に動作するように、リンカが出力するELFファイルにPT_PAX_FLAGS
ヘッダを追加することで、PaXシステムに対してGoバイナリの特定の動作を「緩和」させることを目的としています。これにより、Goのランタイムが必要とするメモリ操作がPaXによってブロックされるのを防ぎます。
前提知識の解説
ELF (Executable and Linkable Format)
ELFは、Unix系システムで実行可能ファイル、オブジェクトファイル、共有ライブラリなどを表現するための標準的なファイルフォーマットです。ELFファイルは、ヘッダ、プログラムヘッダテーブル、セクションヘッダテーブル、そして実際のデータ(コードやデータ)で構成されます。
- ELFヘッダ: ファイルの基本的な情報(マジックナンバー、アーキテクチャ、OS ABIなど)を含みます。
- プログラムヘッダテーブル (Program Header Table): 実行時にメモリにロードされるセグメントのレイアウトを記述します。各エントリは「プログラムヘッダ (Program Header)」と呼ばれ、セグメントのタイプ(例:
PT_LOAD
、PT_GNU_STACK
)、メモリ上の位置、サイズ、パーミッションなどを定義します。 - セクションヘッダテーブル (Section Header Table): リンク時に使用されるファイルの論理的な構造(コードセクション、データセクションなど)を記述します。
PaX (Patch for eXecutable)
PaXは、Linuxカーネルのセキュリティ拡張機能であり、メモリ保護を強化することで、エクスプロイト(脆弱性攻撃)を困難にします。主な機能は以下の通りです。
- W^X (Write XOR Execute): メモリページが書き込み可能であると同時に実行可能である状態を禁止します。これにより、データ領域に注入された悪意のあるコードが実行されるのを防ぎます。
- ASLR (Address Space Layout Randomization): プロセスのアドレス空間のレイアウトをランダム化し、攻撃者が特定のコードやデータのメモリ上の位置を予測することを困難にします。
- mprotect制限:
mprotect()
システムコールによるメモリパーミッションの変更を制限します。これは、攻撃者が非実行可能メモリを実行可能に変更するのを防ぐためです。
PT_PAX_FLAGS
PT_PAX_FLAGS
は、PaXシステムがELFバイナリに対して適用するセキュリティポリシーを細かく制御するためのプログラムヘッダのタイプです。このヘッダが存在する場合、PaXはバイナリに埋め込まれたフラグを読み取り、それに応じてセキュリティ機能を調整します。これにより、特定のアプリケーションがPaXの厳格なポリシーと衝突する場合でも、セキュリティを完全に無効にすることなく、必要な緩和措置を講じることが可能になります。PT_PAX_FLAGS
のタイプ値は 0x65041580
です。
mprotect, randexec, emutramp
これらはPaXが提供するセキュリティ機能の一部です。
- mprotect: 前述の通り、
mprotect()
システムコールによるメモリパーミッション変更の制限を指します。Goバイナリが動的にメモリパーミッションを変更する必要がある場合、この制限が問題となります。 - randexec (RANDEXEC): 非PIE (Position Independent Executable) バイナリのベースアドレスをランダム化するPaXの機能です。ASLRの一種ですが、特定のバイナリタイプに特化しています。
- emutramp (EMUTRAMP): 「エミュレート・トランポリン」の略で、JITコンパイラやネストされた関数など、実行時に動的にコードを生成するプログラムがPaXのW^X保護と衝突するのを避けるための機能です。
EMUTRAMP
を有効にすることで、PaXはこれらの動的に生成されたコードの実行を許可します。
このコミットでは、0x2a00
というフラグ値が設定されています。これは、mprotect
, randexec
, emutramp
の各機能を無効化(または緩和)することをPaXに指示するものです。具体的には、PaXのドキュメントによると、0x2a00
は以下のフラグの組み合わせに相当します。
PAX_MPROTECT
:mprotect
の制限を無効化PAX_RANDEXEC
:randexec
を無効化PAX_EMUTRAMP
:emutramp
を無効化
これらのフラグを無効にすることで、Goランタイムが実行時に必要とするメモリ操作がPaXによって妨げられなくなり、GoバイナリがPaXシステム上で正常に動作するようになります。
技術的詳細
このコミットは、Go言語のリンカ (cmd/ld
) がELF実行可能ファイルを生成する際に、PT_PAX_FLAGS
プログラムヘッダを追加するように変更します。
具体的には、以下のファイルが変更されています。
src/cmd/6l/asm.c
:6l
はamd64アーキテクチャ用のリンカです。src/cmd/8l/asm.c
:8l
はx86アーキテクチャ用のリンカです。src/cmd/ld/elf.h
: ELF関連の定数を定義するヘッダファイルです。
変更の核心は、asmb()
関数(アセンブリコードを生成し、ELFヘッダやプログラムヘッダを設定する関数)内で、既存のPT_GNU_STACK
ヘッダの後に新しいPT_PAX_FLAGS
ヘッダを追加する点です。
新しいPT_PAX_FLAGS
プログラムヘッダは、以下のプロパティで初期化されます。
ph->type = PT_PAX_FLAGS;
: ヘッダのタイプをPT_PAX_FLAGS
に設定します。この定数はsrc/cmd/ld/elf.h
で0x65041580
として新しく定義されています。ph->flags = 0x2a00;
: PaXシステムに渡すフラグ値を0x2a00
に設定します。この値は、mprotect
,randexec
,emutramp
の各機能を無効化(または緩和)することを意味します。ph->align = 8;
(6lの場合) またはph->align = 4;
(8lの場合): メモリのアライメントを設定します。これは、プログラムヘッダがメモリにロードされる際の配置要件です。
この変更により、Goリンカによって生成された実行可能ファイルは、PaXが有効なLinuxシステム上で実行される際に、PaXの厳格なメモリ保護ポリシーの一部を緩和するようPaXカーネルに明示的に要求するようになります。これにより、Goランタイムが動的にメモリパーミッションを変更する操作が許可され、Goバイナリの互換性と安定性が向上します。
コアとなるコードの変更箇所
src/cmd/6l/asm.c
および src/cmd/8l/asm.c
これらのファイルは、Goリンカのアーキテクチャ固有の部分であり、ELF実行可能ファイルのプログラムヘッダを構築するロジックを含んでいます。
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -1082,6 +1082,11 @@ asmb(void)\n \tph->type = PT_GNU_STACK;\n \tph->flags = PF_W+PF_R;\n \tph->align = 8;\n+\t\t\n+\t\tph = newElfPhdr();\n+\t\tph->type = PT_PAX_FLAGS;\n+\t\tph->flags = 0x2a00; // mprotect, randexec, emutramp disabled\n+\t\tph->align = 8;\
\n \tsh = newElfShstrtab(elfstr[ElfStrShstrtab]);\n \tsh->type = SHT_STRTAB;\
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -1127,6 +1127,11 @@ asmb(void)\n \tph->flags = PF_W+PF_R;\n \tph->align = 4;\n \n+\t\tph = newElfPhdr();\n+\t\tph->type = PT_PAX_FLAGS;\n+\t\tph->flags = 0x2a00; // mprotect, randexec, emutramp disabled\n+\t\tph->align = 4;\
+\n \tsh = newElfShstrtab(elfstr[ElfStrShstrtab]);\n \tsh->type = SHT_STRTAB;\
\tsh->addralign = 1;\
src/cmd/ld/elf.h
このヘッダファイルには、ELFフォーマットに関連する定数が定義されています。
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -251,6 +251,7 @@ typedef struct {\n #define PT_LOPROC 0x70000000 /* First processor-specific type. */\n #define PT_HIPROC 0x7fffffff /* Last processor-specific type. */\n #define PT_GNU_STACK 0x6474e551\n+#define PT_PAX_FLAGS 0x65041580\
\n /* Values for p_flags. */\n #define PF_X 0x1 /* Executable. */
コアとなるコードの解説
上記の変更は、GoリンカがELF実行可能ファイルを生成する際のプログラムヘッダテーブルに、新しいエントリを追加するものです。
-
src/cmd/ld/elf.h
の変更:#define PT_PAX_FLAGS 0x65041580
という行が追加されています。これは、PT_PAX_FLAGS
という新しいプログラムヘッダタイプに、PaXが認識する特定の数値(0x65041580
)を割り当てています。この数値は、ELF仕様で定義されているプロセッサ固有のタイプ範囲(PT_LOPROC
からPT_HIPROC
)内にあり、PaXがこのヘッダを識別するために使用します。
-
src/cmd/6l/asm.c
およびsrc/cmd/8l/asm.c
の変更:newElfPhdr()
関数を呼び出して、新しいELFプログラムヘッダ構造体を作成しています。- 作成したプログラムヘッダの
type
フィールドを、新しく定義したPT_PAX_FLAGS
に設定しています。 flags
フィールドには0x2a00
という値を設定しています。この値は、PaXシステムに対して、Goバイナリの実行時にmprotect
、randexec
、emutramp
といった特定のセキュリティ機能を無効化(または緩和)するよう指示するものです。コメントにも「mprotect, randexec, emutramp disabled
」と明記されており、このフラグの意図が明確に示されています。align
フィールドは、メモリのアライメント要件を設定します。6l
(amd64)では8バイト、8l
(x86)では4バイトに設定されています。
これらの変更により、Goリンカは、GoバイナリがPaXが有効なシステム上で実行される際に、PaXの厳格なメモリ保護ポリシーの一部を緩和するよう明示的に要求するELFヘッダを埋め込むようになります。これにより、Goランタイムが動的にメモリパーミッションを変更する操作が許可され、Goバイナリの互換性と安定性が向上します。
関連リンク
- Go Issue #47: https://github.com/golang/go/issues/47
- Go CL 6326054: https://golang.org/cl/6326054
参考にした情報源リンク
- PaX Documentation: https://pax.grsecurity.net/
- ELF (Executable and Linkable Format) - Wikipedia: https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format
- PaX - Wikipedia: https://ja.wikipedia.org/wiki/PaX
- mprotect(2) - Linux man page: https://man7.org/linux/man-pages/man2/mprotect.2.html
- PT_PAX_FLAGS - Go source code: https://go.dev/src/cmd/ld/elf.h (このコミットで追加された行を含む)
- PaX flags values (検索結果から得られた情報に基づく)