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

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

コミット

このコミットは、GoランタイムにおけるFreeBSD環境でのSIGSYSシグナルの扱いを変更するものです。具体的には、SIGSYSシグナルが「通知可能 (notifiable)」になるように更新されています。

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/d9fc789df2a97137a56d305c61513cd33b1c910a

元コミット内容

commit d9fc789df2a97137a56d305c61513cd33b1c910a
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Mon Mar 3 07:08:44 2014 +0900

    runtime: make SIGSYS notifiable on FreeBSD
    
    Update #7186
    
    LGTM=iant
    R=iant
    CC=golang-codereviews
    https://golang.org/cl/70490043

変更の背景

この変更は、Go Issue #7186 に関連しています。SIGSYSシグナルは、プログラムが不正なシステムコールを試みた際にカーネルによって送信されるシグナルです。FreeBSD環境において、GoランタイムがこのSIGSYSシグナルを適切に処理できるよう、そのシグナルハンドリングの挙動を調整する必要がありました。

Goランタイムは、プログラムの安定性とデバッグ可能性を確保するために、様々なシグナルに対して独自のハンドリングロジックを持っています。特に、予期せぬシステムコールエラーが発生した場合に、プログラムが即座に終了するのではなく、より制御された方法でエラーを報告したり、デバッグ情報を提供したりすることが望ましい場合があります。このコミットは、FreeBSD上でのSIGSYSの扱いを、他のプラットフォームや他のシグナルと同様に、ランタイムがその発生を「通知」できるようにすることで、この制御を改善することを目的としています。

前提知識の解説

シグナル (Signals)

シグナルは、Unix系オペレーティングシステムにおいて、プロセスに対して非同期的にイベントを通知するソフトウェア割り込みの一種です。シグナルは、様々な状況で生成されます。例えば、ユーザーがCtrl+Cを押した場合(SIGINT)、不正なメモリアクセスが発生した場合(SIGSEGV)、子プロセスが終了した場合(SIGCHLD)などです。

各シグナルには、デフォルトの動作が定義されています。これには、プロセスの終了、コアダンプの生成、シグナルの無視、シグナルハンドラ関数の実行などがあります。プログラムは、signal()sigaction()といったシステムコールを使用して、特定のシグナルに対するデフォルトの動作を変更し、カスタムのシグナルハンドラを設定することができます。

SIGSYS シグナル

SIGSYS (Signal System Call) は、プロセスが不正なシステムコールを試みた際にカーネルによって送信されるシグナルです。これは通常、存在しないシステムコール番号を呼び出したり、システムコールに無効な引数を渡したりした場合に発生します。セキュリティメカニズム(例: seccomp)によって、特定のシステムコールの実行が禁止されている場合にも発生することがあります。

デフォルトでは、SIGSYSを受け取ったプロセスは終了します。しかし、デバッグや特定のセキュリティポリシーの実装のために、このシグナルを捕捉してカスタムの処理を行うことが望ましい場合があります。

Goランタイムとシグナルハンドリング

Goプログラムは、Goランタイムによって管理されます。Goランタイムは、ガベージコレクション、スケジューリング、ネットワークI/O、そしてシグナルハンドリングなど、多くの低レベルなタスクを処理します。Goランタイムは、オペレーティングシステムから受け取ったシグナルを捕捉し、Goのゴルーチンモデルと統合された方法で処理します。これにより、Goプログラムは、OSレベルのシグナルを直接扱うことなく、より高レベルなos/signalパッケージを通じてシグナルイベントを処理できます。

Goランタイム内部では、各シグナルに対して、そのシグナルが「終了 (Terminate)」、「無視 (Ignore)」、「コアダンプ (Core Dump)」、「停止 (Stop)」、「通知 (Notify)」のいずれのカテゴリに属するかを定義するテーブルを持っています。

  • T (Terminate): シグナルを受け取るとプロセスが終了する。
  • P (Core Dump): シグナルを受け取るとプロセスが終了し、コアダンプを生成する。
  • I (Ignore): シグナルを無視する。
  • S (Stop): シグナルを受け取るとプロセスが停止する。
  • N (Notify): シグナルを受け取ると、Goランタイムがそのシグナルを捕捉し、os/signalパッケージを通じてユーザーゴルーチンに通知する。

このコミットの文脈では、SIGSYST(終了)からN(通知)に変更されることが重要です。

技術的詳細

このコミットの核心は、FreeBSDにおけるSIGSYSシグナルのGoランタイム内での分類を変更することです。変更前は、SIGSYST(Terminate)として扱われていました。これは、GoプログラムがFreeBSD上で不正なシステムコールを試みた場合、ランタイムがそのシグナルを捕捉しても、最終的にはプロセスを終了させるという挙動を意味します。

変更後は、SIGSYSN(Notify)として扱われるようになります。これにより、GoランタイムはSIGSYSシグナルを捕捉し、そのシグナルイベントをos/signalパッケージを通じてGoプログラム内のユーザーゴルーチンに通知できるようになります。つまり、Go開発者はos/signalパッケージを使用してSIGSYSシグナルを捕捉し、プログラム内でカスタムのハンドリングロジックを実装できるようになります。これにより、不正なシステムコールが発生した場合でも、プログラムが即座にクラッシュするのではなく、より柔軟なエラー処理やデバッグが可能になります。

この変更は、特にサンドボックス環境や、特定のシステムコールが意図的にブロックされるような環境でGoプログラムを実行する際に重要になります。例えば、seccompのようなメカニズムを使用してシステムコールを制限している場合、許可されていないシステムコールを呼び出すとSIGSYSが発生します。この変更により、Goプログラムはそのようなイベントを捕捉し、適切に対応できるようになります。

コアとなるコードの変更箇所

変更は、src/pkg/runtime/signals_freebsd.hファイル内のSigTab配列の定義にあります。

--- a/src/pkg/runtime/signals_freebsd.h
+++ b/src/pkg/runtime/signals_freebsd.h
@@ -21,7 +21,7 @@ SigTab runtime·sigtab[] = {
 	/* 9 */	0, "SIGKILL: kill",
 	/* 10 */	P, "SIGBUS: bus error",
 	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad system call",
+	/* 12 */	N, "SIGSYS: bad system call",
 	/* 13 */	N, "SIGPIPE: write to broken pipe",
 	/* 14 */	N, "SIGALRM: alarm clock",
 	/* 15 */	N+K, "SIGTERM: termination",

コアとなるコードの解説

src/pkg/runtime/signals_freebsd.hファイルは、FreeBSDプラットフォームにおけるGoランタイムのシグナルハンドリング設定を定義しています。

SigTab runtime·sigtab[]は、Goランタイムが認識するシグナルとそのデフォルトの動作を定義するテーブルです。各エントリは、シグナル番号(コメントで示されている)、シグナルの種類を示すフラグ(T, P, Nなど)、およびシグナルの説明文字列で構成されています。

このコミットでは、SIGSYSに対応する行が以下のように変更されています。

  • 変更前: /* 12 */ T, "SIGSYS: bad system call",
    • これは、シグナル番号12(SIGSYS)がT(Terminate)として扱われることを意味していました。つまり、SIGSYSを受け取ると、Goプログラムはデフォルトで終了します。
  • 変更後: /* 12 */ N, "SIGSYS: bad system call",
    • これは、シグナル番号12(SIGSYS)がN(Notify)として扱われることを意味します。これにより、GoランタイムはSIGSYSを捕捉し、os/signalパッケージを通じてGoプログラムに通知できるようになります。

この小さな変更により、FreeBSD上でのGoプログラムのSIGSYSシグナルに対する挙動が根本的に変わり、より柔軟なシグナルハンドリングが可能になります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (シグナルハンドリングに関する一般的な情報)
  • Unix/Linuxシグナルに関する一般的なドキュメント (SIGSYSの定義など)
  • FreeBSDのシグナルに関するドキュメント (FreeBSD固有のシグナル挙動)
  • Goランタイムのソースコード (signals_freebsd.hのコンテキスト理解のため)
  • Go Issue #7186の議論 (変更の背景と目的の理解のため)