[インデックス 19606] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおいて、OpenBSD、FreeBSD、およびDragonflyBSD向けにsetresuid(2)
およびsetresgid(2)
システムコールの実装を追加するものです。これにより、これらのBSD系OS上でGoプログラムがプロセスの実効ユーザーID(EUID)、実ユーザーID(RUID)、および保存設定ユーザーID(SUID)をより柔軟かつ安全に管理できるようになります。同様に、グループID(GID)についても同様の機能が提供されます。
コミット
commit 63e3763af88e758815187bd58c342b7ccfcd3aa2
Author: William Orr <will@worrbase.com>
Date: Tue Jun 24 13:30:30 2014 -0700
syscall: implement setresuid(2) and setresgid(2) on OpenBSD/FreeBSD/DragonflyBSD
Fixes #8218.
LGTM=iant
R=golang-codereviews, iant, minux
CC=golang-codereviews
https://golang.org/cl/107150043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/63e3763af88e758815187bd58c342b7ccfcd3aa2
元コミット内容
このコミットは、Goのsyscall
パッケージにsetresuid(2)
とsetresgid(2)
システムコールをOpenBSD、FreeBSD、およびDragonflyBSD向けに実装したものです。これにより、GoプログラムがこれらのOS上でユーザーIDとグループIDをより細かく制御できるようになります。コミットメッセージには「Fixes #8218」と記載されていますが、現在のGoのGitHubリポジトリではこの番号のIssueは見つかりませんでした。これは、当時の内部トラッカーの参照であるか、あるいはIssue番号が変更された可能性があります。
変更の背景
Unix系システムにおいて、プロセスの権限管理はセキュリティ上非常に重要です。従来のsetuid()
やsetgid()
といったシステムコールは、プロセスのユーザーIDやグループIDを変更するために使用されてきましたが、これらは実効IDと実IDを同時に変更するなど、柔軟性に欠ける点がありました。特に、特権を一時的に放棄し、必要に応じて再度取得するといった高度な権限管理を行う際には不十分でした。
setresuid(2)
とsetresgid(2)
は、実ユーザーID(RUID)、実効ユーザーID(EUID)、および保存設定ユーザーID(SUID)を個別に設定できるため、よりきめ細やかな権限管理を可能にします。これにより、例えばroot権限で起動したプロセスが、特定の処理を行う際に一時的に非特権ユーザーの権限に切り替え、処理完了後に再度root権限に戻るといった安全な運用が可能になります。
このコミットは、Go言語がこれらのBSD系OS上でより堅牢なセキュリティ機能を提供し、特権を扱うアプリケーションの開発を容易にすることを目的としています。Goのsyscall
パッケージはOSの低レベルな機能へのインターフェースを提供するため、これらのシステムコールをGoから直接呼び出せるようにすることは、Goプログラムの機能性とセキュリティを向上させる上で不可欠でした。
前提知識の解説
Unix系システムのユーザーIDとグループID
Unix系OSでは、各プロセスは以下の3種類のユーザーID(UID)とグループID(GID)を持ちます。
-
実ユーザーID (Real User ID, RUID) / 実グループID (Real Group ID, RGID): プロセスを起動したユーザーまたはグループのIDです。通常、プロセスのライフサイクルを通じて変更されません。これはプロセスの「所有者」を示します。
-
実効ユーザーID (Effective User ID, EUID) / 実効グループID (Effective Group ID, EGID): プロセスがファイルやその他のシステムリソースにアクセスする際の権限を決定するIDです。特権プログラム(例:
sudo
コマンド)は、この実効IDを一時的に変更することで、通常はアクセスできないリソースにアクセスできるようになります。 -
保存設定ユーザーID (Saved Set-User-ID, SUID) / 保存設定グループID (Saved Set-Group-ID, SGID):
execve()
システムコールによって新しいプログラムが実行される際に、その時点の実効IDのコピーが保存されます。これにより、プロセスは一時的に実効IDを非特権ユーザーに変更した後でも、保存された特権IDを使用して元の特権を回復することが可能になります。これは、特権を必要としない処理中は特権を放棄し、必要な時だけ特権を再取得するというセキュリティプラクティスを可能にします。
setresuid(2)
とsetresgid(2)
システムコール
これらのシステムコールは、プロセスのRUID、EUID、SUID(またはRGID、EGID、SGID)を個別に設定するために使用されます。
-
setresuid(uid_t ruid, uid_t euid, uid_t suid)
:ruid
: 設定したい実ユーザーIDeuid
: 設定したい実効ユーザーIDsuid
: 設定したい保存設定ユーザーID- 引数に
-1
を指定すると、対応するIDは変更されません。 - 特権プロセス(rootなど)は任意のIDを設定できます。
- 非特権プロセスは、現在のRUID、EUID、SUIDのいずれかにのみIDを変更できます。
-
setresgid(gid_t rgid, gid_t egid, gid_t sgid)
:rgid
: 設定したい実グループIDegid
: 設定したい実効グループIDsgid
: 設定したい保存設定グループIDsetresuid
と同様の挙動を示します。
これらのシステムコールは、特にセキュリティが重視されるデーモンやネットワークサービスにおいて、最小権限の原則を実装するために不可欠です。
Go言語のsyscall
パッケージ
Go言語の標準ライブラリに含まれるsyscall
パッケージは、オペレーティングシステムの低レベルなプリミティブ(システムコール)へのインターフェースを提供します。これにより、GoプログラムはOS固有の機能に直接アクセスし、ファイルシステム操作、プロセス管理、ネットワーク通信など、OSレベルの操作を実行できます。syscall
パッケージはOSごとに異なる実装を持ち、各OSのシステムコールをGoの関数としてラップしています。
zsyscall_*.go
ファイル
Goのsyscall
パッケージには、zsyscall_*.go
という命名規則のファイルが多数存在します。これらのファイルは通常、go tool cgo -godefs
のようなツールによって自動生成されます。このツールは、C言語のヘッダーファイルからGoの構造体や関数定義を生成し、GoプログラムがCのシステムコールを呼び出すためのバインディングを提供します。したがって、これらのファイルへの変更は、新しいシステムコールがGoから利用可能になったことを意味します。
技術的詳細
このコミットの技術的詳細は、主に以下の2点に集約されます。
-
システムコール定義の追加:
src/pkg/syscall/syscall_dragonfly.go
、src/pkg/syscall/syscall_freebsd.go
、src/pkg/syscall/syscall_openbsd.go
といった各OS固有のファイルに、setresuid
とsetresgid
のGo言語でのシステムコール定義が追加されています。これらは//sysnb
ディレクティブ(//sys
の非ブロックバージョン)を用いて、Goの関数シグネチャと対応するシステムコールを紐付けています。例:
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) //sysnb Setresuid(ruid int, euid int, suid int) (err error)
この行は、Goの
Setresgid
関数が、対応するOSのsetresgid
システムコールを呼び出すことをGoツールチェインに指示します。 -
自動生成されるシステムコールラッパーの実装:
src/pkg/syscall/zsyscall_dragonfly_386.go
、src/pkg/syscall/zsyscall_freebsd_amd64.go
などのzsyscall_*.go
ファイルには、実際にシステムコールを呼び出すためのGo関数が追加されています。これらの関数は、RawSyscall
関数を使用して低レベルなシステムコールを実行します。例:
func Setresgid(rgid int, egid int, sgid int) (err error) { _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)) if e1 != 0 { err = e1 } return }
ここで、
SYS_SETRESGID
は対応するOSのsetresgid
システムコールの番号を表す定数です。RawSyscall
は、引数をuintptr
に変換してOSのカーネルに渡し、システムコールを実行します。返されたエラーコードe1
は、Goのエラー型に変換されて返されます。
OpenBSDのsrc/pkg/syscall/syscall_openbsd.go
では、以前のコメントアウトされていたsetresgid
とsetresuid
の記述が削除されています。これは、これらのシステムコールが正式に実装されたため、もはや「未実装」としてリストする必要がなくなったことを示しています。
この変更により、GoプログラムはこれらのBSD系OS上で、より高度な権限管理を必要とするアプリケーション(例: セキュアなサーバー、サンドボックス環境)を開発する際に、ネイティブなシステムコールを活用できるようになります。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルとコードスニペットは以下の通りです。
1. src/pkg/syscall/syscall_dragonfly.go
, src/pkg/syscall/syscall_freebsd.go
, src/pkg/syscall/syscall_openbsd.go
:
これらのファイルに、setresgid
とsetresuid
のシステムコール定義が追加されました。
例 (src/pkg/syscall/syscall_dragonfly.go
):
--- a/src/pkg/syscall/syscall_dragonfly.go
+++ b/src/pkg/syscall/syscall_dragonfly.go
@@ -183,6 +183,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys Setpriority(which int, who int, prio int) (err error)
//sysnb Setregid(rgid int, egid int) (err error)
//sysnb Setreuid(ruid int, euid int) (err error)
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
+//sysnb Setresuid(ruid int, euid int, suid int) (err error)
//sysnb Setrlimit(which int, lim *Rlimit) (err error)
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
2. src/pkg/syscall/syscall_openbsd.go
:
既存のコメントからsetresgid
とsetresuid
の記述が削除されました。
--- a/src/pkg/syscall/syscall_openbsd.go
+++ b/src/pkg/syscall/syscall_openbsd.go
@@ -272,8 +274,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// semop
// setgroups
// setitimer
-// setresgid
-// setresuid
// setrtable
// setsockopt
// shmat
3. src/pkg/syscall/zsyscall_dragonfly_386.go
(および他のzsyscall_*.go
ファイル):
これらの自動生成ファイルに、Setresgid
とSetresuid
のGo関数実装が追加されました。
例 (src/pkg/syscall/zsyscall_dragonfly_386.go
):
--- a/src/pkg/syscall/zsyscall_dragonfly_386.go
+++ b/src/pkg/syscall/zsyscall_dragonfly_386.go
@@ -1059,6 +1059,26 @@ func Setreuid(ruid int, euid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func Setresgid(rgid int, egid int, sgid int) (err error) {
+\t_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
+\tif e1 != 0 {
+\t\terr = e1
+\t}\n+\treturn
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresuid(ruid int, euid int, suid int) (err error) {
+\t_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
+\tif e1 != 0 {
+\t\terr = e1
+\t}\n+\treturn
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(which int, lim *Rlimit) (err error) {
\t_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
\tif e1 != 0 {
コアとなるコードの解説
このコミットの核となる変更は、Goのsyscall
パッケージが特定のBSD系OS(OpenBSD、FreeBSD、DragonflyBSD)上でsetresuid(2)
とsetresgid(2)
システムコールを呼び出せるようにするためのものです。
-
//sysnb
ディレクティブの追加:syscall_*.go
ファイルに追加された//sysnb
コメントは、Goのツールチェイン(特にgo tool cgo -godefs
)に対する指示です。これは、GoのSetresgid
およびSetresuid
関数が、それぞれOSのsetresgid
およびsetresuid
システムコールに対応することを宣言しています。nb
は「non-blocking」を意味し、このシステムコールがブロックしない性質を持つことを示唆しています。このディレクティブがあることで、ツールチェインは対応するGoの関数シグネチャから、適切なシステムコール呼び出しコードを自動生成できるようになります。 -
zsyscall_*.go
ファイルでの実装:zsyscall_*.go
ファイルは、前述の//sysnb
ディレクティブに基づいて自動生成される部分です。ここに、実際にOSのシステムコールを呼び出すためのGo関数が追加されています。RawSyscall
関数は、Goから直接OSのシステムコールを呼び出すための低レベルなインターフェースです。第一引数にはシステムコール番号(例:SYS_SETRESGID
)、続く引数にはシステムコールに渡すパラメータがuintptr
型で渡されます。- システムコールが成功した場合、
RawSyscall
はエラーコード0
を返します。エラーが発生した場合は、非ゼロの値が返され、それがGoのエラー型に変換されて呼び出し元に返されます。 - これらの関数は、Goプログラムが
syscall.Setresuid(ruid, euid, suid)
やsyscall.Setresgid(rgid, egid, sgid)
といった形で、OSの権限管理機能を直接利用できるようにします。
この変更により、Goで書かれたアプリケーションは、これらのBSD系OSのセキュリティモデルに深く統合され、より高度な権限分離や特権の管理をプログラム的に行えるようになります。これは、特にセキュリティが要求されるシステムサービスやデーモンをGoで開発する際に、非常に重要な機能となります。
関連リンク
- Go言語の
syscall
パッケージに関するドキュメント: https://pkg.go.dev/syscall setresuid(2)
manページ (Linux): https://man7.org/linux/man-pages/man2/setresuid.2.htmlsetresgid(2)
manページ (Linux): https://man7.org/linux/man-pages/man2/setresgid.2.html
参考にした情報源リンク
- https://github.com/golang/go/commit/63e3763af88e758815187bd58c342b7ccfcd3aa2
- Web検索結果: "Go syscall setresuid setresgid OpenBSD FreeBSD DragonflyBSD"
- Web検索結果: "setresuid(2) setresgid(2) system calls"
- Go issue 8218 (検索結果では見つからなかったが、コミットメッセージに記載あり)