[インデックス 15773] ファイルの概要
このコミットは、Go言語のランタイムにおけるFreeBSD ARMアーキテクチャ向けの修正であり、特にハッシュ変更に関連する問題に対処しています。具体的には、open
、read
、close
といった基本的なシステムコールがFreeBSD ARM環境で正しく定義されていなかった点を修正しています。
コミット
commit a98bec4554fe1dc1b002acfca75aeb6a0dc6c6e9
Author: Russ Cox <rsc@golang.org>
Date: Thu Mar 14 17:45:44 2013 -0400
runtime: fix freebsd arm for hash change
Was missing definitions of open, read, close.
R=golang-dev
CC=golang-dev
https://golang.org/cl/7828043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a98bec4554fe1dc1b002acfca75aeb6a0dc6c6e9
元コミット内容
このコミットの元々の内容は、GoランタイムがFreeBSD ARM環境で、open
、read
、close
といったファイル操作に関するシステムコールの定義を欠いていたため、これを追加するというものです。コミットメッセージには「hash change」という記述がありますが、これは直接的な変更内容ではなく、この修正が必要になった背景にある、Goランタイム全体のハッシュ機構の変更を示唆しています。
変更の背景
このコミットが行われた2013年頃、Go言語のランタイムでは、マップ(ハッシュテーブル)の実装におけるハッシュ衝突攻撃(Hash Flood Attack)への対策として、ハッシュ機構に大きな変更が加えられました。ハッシュ衝突攻撃は、悪意のある入力によってハッシュテーブルのパフォーマンスを意図的に低下させ、サービス拒否(DoS)を引き起こす可能性のある脆弱性です。これを防ぐため、Goは各マップにランダムなハッシュシードを使用するようになり、攻撃者がハッシュ値を予測して衝突を引き起こすことを困難にしました。
このようなランタイムの基盤部分の変更は、特定のアーキテクチャやOSにおけるシステムコールとの連携に影響を与えることがあります。FreeBSD ARM環境では、このハッシュ変更に関連して、Goランタイムが依存するopen
、read
、close
といった基本的なファイルI/Oシステムコールの定義が不足していることが判明しました。これらのシステムコールは、ファイルを開く、読み込む、閉じるというOSレベルの操作を行うために不可欠であり、Goランタイムが内部でファイル操作を行う際に必要となります。定義が欠けていると、GoプログラムがFreeBSD ARM上で正しく動作しない、あるいはクラッシュする原因となります。
したがって、このコミットは、Goランタイムのセキュリティ強化(ハッシュ変更)という大きな流れの中で、特定のプラットフォーム(FreeBSD ARM)における互換性の問題を解決するために行われた、重要な修正であると言えます。
前提知識の解説
Goランタイムとシステムコール
Go言語のプログラムは、Goランタイムと呼ばれる実行環境上で動作します。Goランタイムは、ガベージコレクション、スケジューリング、ネットワークI/O、ファイルI/Oなど、プログラムの実行に必要な低レベルな処理の多くを担っています。これらの処理の多くは、OSが提供するシステムコールを介して行われます。システムコールは、ユーザー空間のプログラムがカーネル空間の機能(ファイルシステム、ネットワーク、メモリ管理など)にアクセスするためのインターフェースです。
ARMアーキテクチャとシステムコール規約
ARM(Advanced RISC Machine)は、モバイルデバイスや組み込みシステムで広く使用されているRISC(Reduced Instruction Set Computer)ベースのプロセッサアーキテクチャです。ARMプロセッサ上で動作するOS(FreeBSD ARMなど)では、システムコールを呼び出すための特定の規約(Calling Convention)が存在します。これには、システムコール番号をどのレジスタに格納するか、引数をどのレジスタに渡すか、システムコールをトリガーするための命令(通常はSWI
またはSVC
)などが含まれます。
FreeBSD ARMにおける一般的なシステムコール規約では、システムコール番号は特定のレジスタ(例: R7
またはR0
、文脈による)に格納され、引数はR0
、R1
、R2
などのレジスタに渡されます。システムコールはSWI
(Software Interrupt)命令によってトリガーされます。
FreeBSDのシステムコール番号
FreeBSDでは、各システムコールに一意の番号が割り当てられています。この番号は、ユーザー空間のプログラムが特定のカーネル機能にアクセスする際に使用されます。
open
: ファイルを開く、または作成するシステムコール。FreeBSD ARMでは通常、システムコール番号 5 が割り当てられています。read
: ファイルディスクリプタからデータを読み込むシステムコール。FreeBSD ARMでは通常、システムコール番号 3 が割り当てられています。close
: ファイルディスクリプタを閉じるシステムコール。FreeBSD ARMでは通常、システムコール番号 6 が割り当てられています。
これらのシステムコールは、C言語の標準ライブラリ関数(open()
, read()
, close()
)の背後で実際に呼び出されるカーネル関数です。Goランタイムは、これらの低レベルなシステムコールを直接呼び出すことで、OSとの連携を実現しています。
技術的詳細
このコミットは、src/pkg/runtime/sys_freebsd_arm.s
というアセンブリ言語ファイルに、runtime·open
、runtime·read
、runtime·close
というGoランタイムが使用する関数(実際にはシステムコールへのラッパー)の定義を追加しています。
アセンブリ言語でシステムコールを呼び出す際の一般的な手順は以下の通りです。
- 引数の設定: システムコールに渡す引数をARMレジスタ(
R0
,R1
,R2
など)に格納します。Goの関数呼び出し規約に従い、スタックフレーム(FP
)から引数を読み込みます。 - システムコール番号の設定: 呼び出すシステムコールの番号を特定のレジスタ(この場合は
R7
またはR0
、Goのランタイム規約による)に格納します。 - システムコール呼び出し:
SWI
(Software Interrupt)命令を実行して、カーネルにシステムコールを要求します。SWI
命令のオペランドは、FreeBSD ARMではシステムコール番号そのものを示します。
このコミットで追加されたコードは、まさにこの手順を踏んでいます。
runtime·open(SB)
:MOVW 0(FP), R0
:第一引数(ファイル名)をR0
に移動。MOVW 4(FP), R1
:第二引数(モード)をR1
に移動。MOVW 8(FP), R2
:第三引数(パーミッション)をR2
に移動。SWI $5
:システムコール番号5(open
)を呼び出し。
runtime·read(SB)
:MOVW 0(FP), R0
:第一引数(ファイルディスクリプタ)をR0
に移動。MOVW 4(FP), R1
:第二引数(バッファ)をR1
に移動。MOVW 8(FP), R2
:第三引数(読み込むバイト数)をR2
に移動。SWI $3
:システムコール番号3(read
)を呼び出し。
runtime·close(SB)
:MOVW 0(FP), R0
:第一引数(ファイルディスクリプタ)をR0
に移動。SWI $6
:システムコール番号6(close
)を呼び出し。
これらの定義が追加されることで、GoランタイムはFreeBSD ARM環境でファイルI/Oを正しく実行できるようになります。
コアとなるコードの変更箇所
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -54,6 +54,20 @@ TEXT runtime·exit1(SB),7,$-8
MOVW.CS R9, (R9)
RET
+TEXT runtime·open(SB),7,$-8
+\tMOVW 0(FP), R0\t// arg 1 name
+\tMOVW 4(FP), R1\t// arg 2 mode
+\tMOVW 8(FP), R2\t// arg 3 perm
+\tSWI $5
+\tRET
+\n+TEXT runtime·read(SB),7,$-8
+\tMOVW 0(FP), R0\t// arg 1 fd
+\tMOVW 4(FP), R1\t// arg 2 buf
+\tMOVW 8(FP), R2\t// arg 3 count
+\tSWI $3
+\tRET
+\n TEXT runtime·write(SB),7,$-8
MOVW 0(FP), R0\t// arg 1 fd
MOVW 4(FP), R1\t// arg 2 buf
@@ -61,6 +75,11 @@ TEXT runtime·write(SB),7,$-8
SWI $4
RET
+TEXT runtime·close(SB),7,$-8
+\tMOVW 0(FP), R0\t// arg 1 fd
+\tSWI $6
+\tRET
+\n TEXT runtime·getrlimit(SB),7,$-8
MOVW 0(FP), R0
MOVW 4(FP), R1
コアとなるコードの解説
変更の中心は、src/pkg/runtime/sys_freebsd_arm.s
ファイルへの以下の3つのアセンブリ関数の追加です。
-
TEXT runtime·open(SB),7,$-8
:- これはGoランタイムが内部的に使用する
open
システムコールへのラッパー関数です。 MOVW 0(FP), R0
、MOVW 4(FP), R1
、MOVW 8(FP), R2
は、Goの関数呼び出し規約に従って、スタックフレーム(FP
)からopen
関数の引数(ファイル名、モード、パーミッション)をARMレジスタR0
、R1
、R2
にそれぞれロードしています。SWI $5
は、FreeBSD ARMにおけるopen
システムコール(システムコール番号5)を呼び出す命令です。RET
は関数からのリターンです。
- これはGoランタイムが内部的に使用する
-
TEXT runtime·read(SB),7,$-8
:read
システムコールへのラッパー関数です。MOVW 0(FP), R0
、MOVW 4(FP), R1
、MOVW 8(FP), R2
は、引数(ファイルディスクリプタ、バッファ、読み込むバイト数)をR0
、R1
、R2
にロードします。SWI $3
は、FreeBSD ARMにおけるread
システムコール(システムコール番号3)を呼び出します。
-
TEXT runtime·close(SB),7,$-8
:close
システムコールへのラッパー関数です。MOVW 0(FP), R0
は、引数(ファイルディスクリプタ)をR0
にロードします。SWI $6
は、FreeBSD ARMにおけるclose
システムコール(システムコール番号6)を呼び出します。
これらのアセンブリコードの追加により、GoランタイムはFreeBSD ARM環境で、ファイルI/O操作をOSカーネルに正しく要求できるようになり、Goプログラムの安定性と互換性が向上しました。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/
- FreeBSDプロジェクト: https://www.freebsd.org/
- ARMアーキテクチャに関する情報: https://developer.arm.com/
参考にした情報源リンク
- Go runtime: consider caching previous map hash value (GitHub Issue): https://github.com/golang/go/issues/5090
- Go maps in action: https://blog.golang.org/go-maps-in-action (ハッシュマップの動作に関する一般的な情報)
- FreeBSD System Calls (man pages):
- ARM System Call Convention (Stack Overflowなど): https://stackoverflow.com/questions/tagged/arm-assembly+system-call (一般的なARMシステムコール規約に関する情報)
- FreeBSD
syscalls.master
(例): https://github.com/freebsd/freebsd-src/blob/main/sys/kern/syscalls.master (FreeBSDのシステムコール定義に関する情報) - Go言語のハッシュ衝突対策に関する記事 (例): https://www.golangbridge.org/ や https://cheney.net/ など、Goコミュニティのブログや記事。