Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15773] ファイルの概要

このコミットは、Go言語のランタイムにおけるFreeBSD ARMアーキテクチャ向けの修正であり、特にハッシュ変更に関連する問題に対処しています。具体的には、openreadcloseといった基本的なシステムコールが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環境で、openreadcloseといったファイル操作に関するシステムコールの定義を欠いていたため、これを追加するというものです。コミットメッセージには「hash change」という記述がありますが、これは直接的な変更内容ではなく、この修正が必要になった背景にある、Goランタイム全体のハッシュ機構の変更を示唆しています。

変更の背景

このコミットが行われた2013年頃、Go言語のランタイムでは、マップ(ハッシュテーブル)の実装におけるハッシュ衝突攻撃(Hash Flood Attack)への対策として、ハッシュ機構に大きな変更が加えられました。ハッシュ衝突攻撃は、悪意のある入力によってハッシュテーブルのパフォーマンスを意図的に低下させ、サービス拒否(DoS)を引き起こす可能性のある脆弱性です。これを防ぐため、Goは各マップにランダムなハッシュシードを使用するようになり、攻撃者がハッシュ値を予測して衝突を引き起こすことを困難にしました。

このようなランタイムの基盤部分の変更は、特定のアーキテクチャやOSにおけるシステムコールとの連携に影響を与えることがあります。FreeBSD ARM環境では、このハッシュ変更に関連して、Goランタイムが依存するopenreadcloseといった基本的なファイル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、文脈による)に格納され、引数はR0R1R2などのレジスタに渡されます。システムコールは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·openruntime·readruntime·closeというGoランタイムが使用する関数(実際にはシステムコールへのラッパー)の定義を追加しています。

アセンブリ言語でシステムコールを呼び出す際の一般的な手順は以下の通りです。

  1. 引数の設定: システムコールに渡す引数をARMレジスタ(R0, R1, R2など)に格納します。Goの関数呼び出し規約に従い、スタックフレーム(FP)から引数を読み込みます。
  2. システムコール番号の設定: 呼び出すシステムコールの番号を特定のレジスタ(この場合はR7またはR0、Goのランタイム規約による)に格納します。
  3. システムコール呼び出し: 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つのアセンブリ関数の追加です。

  1. TEXT runtime·open(SB),7,$-8:

    • これはGoランタイムが内部的に使用するopenシステムコールへのラッパー関数です。
    • MOVW 0(FP), R0MOVW 4(FP), R1MOVW 8(FP), R2は、Goの関数呼び出し規約に従って、スタックフレーム(FP)からopen関数の引数(ファイル名、モード、パーミッション)をARMレジスタR0R1R2にそれぞれロードしています。
    • SWI $5は、FreeBSD ARMにおけるopenシステムコール(システムコール番号5)を呼び出す命令です。
    • RETは関数からのリターンです。
  2. TEXT runtime·read(SB),7,$-8:

    • readシステムコールへのラッパー関数です。
    • MOVW 0(FP), R0MOVW 4(FP), R1MOVW 8(FP), R2は、引数(ファイルディスクリプタ、バッファ、読み込むバイト数)をR0R1R2にロードします。
    • SWI $3は、FreeBSD ARMにおけるreadシステムコール(システムコール番号3)を呼び出します。
  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プログラムの安定性と互換性が向上しました。

関連リンク

参考にした情報源リンク