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

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

このコミットは、Go 1.4 リリースノートのドキュメントファイル doc/go1.4.txt に変更を加えるものです。具体的には、syscall.Setuid および syscall.Setgid の Linux プラットフォームにおける挙動に関する重要な注意書きを追加しています。このファイルは、Go の新しいバージョンで導入された変更点や新機能、非互換性などをユーザーに伝えるための公式ドキュメントの一部です。

コミット

commit 88b663b246db802809afaeac0f1b86b2bd260723
Author: Dave Cheney <dave@cheney.net>
Date:   Tue Jun 24 09:50:10 2014 +1000

    doc/go1.4: add note about Set{uid,gid} change
    
    LGTM=iant
    R=ruiu, iant
    CC=golang-codereviews
    https://golang.org/cl/107320044

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

https://github.com/golang/go/commit/88b663b246db802809afaeac0f1b86b2bd260723

元コミット内容

doc/go1.4: add note about Set{uid,gid} change
    
LGTM=iant
R=ruiu, iant
CC=golang-codereviews
https://golang.org/cl/107320044

変更の背景

この変更の背景には、Go プログラムが Linux 上で syscall.Setuid および syscall.Setgid を呼び出した際の予期せぬ挙動がありました。これらのシステムコールは、通常、プロセスの実効ユーザーID (UID) や実効グループID (GID) を変更するために使用されます。しかし、Linux においては、これらのシステムコールは呼び出し元のスレッドにのみ作用し、プロセス全体には影響を与えません。

Go ランタイムは複数のゴルーチンを OS スレッドに多重化して実行するため、あるゴルーチンが Setuid/Setgid を呼び出して権限を降下させても、他のゴルーチンが異なる OS スレッドで実行されている場合、それらのゴルーチンは元の(場合によっては昇格された)権限を保持してしまう可能性がありました。これはセキュリティ上の懸念を引き起こすだけでなく、開発者が期待する「プロセス全体の権限降下」というセマンティクスと一致しませんでした。

この問題は Go の issue 1435 で議論されており、このコミットは、その問題が解決されるまでの間、ユーザーにこの挙動を明確に伝えるために、これらのシステムコールを Linux プラットフォームで無効化し、その旨をリリースノートに記載することを目的としています。

前提知識の解説

ユーザーID (UID) とグループID (GID)

Unix系OSでは、各プロセスは特定のユーザーID (UID) とグループID (GID) に関連付けられています。これらはプロセスの権限を決定します。

  • 実効UID (EUID): プロセスがファイルや他のリソースにアクセスする際に使用されるIDです。
  • 実効GID (EGID): プロセスがグループ関連のリソースにアクセスする際に使用されるIDです。

setuidsetgid システムコール

setuid() および setgid() は、プロセスの実効UIDおよび実効GIDを変更するためのシステムコールです。これらは通常、特権を一時的に昇格させたり(例: sudo コマンド)、逆に特権を降下させたり(例: ネットワークサービスが特定のポートにバインドした後、非特権ユーザーとして実行を継続する)するために使用されます。

プロセスとスレッド

  • プロセス: 実行中のプログラムのインスタンスです。それぞれが独立したメモリ空間を持ち、リソースを共有しません。
  • スレッド: プロセス内の実行単位です。同じプロセスのスレッドはメモリ空間やリソースを共有します。

Linuxにおける setuid/setgid の挙動

Linux の setuid/setgid システムコールは、POSIX 標準とは異なり、呼び出し元のスレッドにのみ作用します。これは、Linux のスレッド実装が「軽量プロセス」として扱われるためです。つまり、Linux カーネルの視点からは、各スレッドは独立したプロセスのようなものであり、setuid/setgid はその「軽量プロセス」の権限を変更するに過ぎません。

Goランタイムとゴルーチン

Go は、軽量な並行処理の単位である「ゴルーチン」を提供します。Go ランタイムは、これらのゴルーチンを少数の OS スレッドに多重化して実行します。これにより、開発者は OS スレッドの管理を意識することなく、多数の並行処理を記述できます。しかし、この抽象化が、Linux の setuid/setgid の挙動と組み合わさると問題を引き起こします。

技術的詳細

Go の syscall.Setuid および syscall.Setgid は、内部的に Linux の setuid() および setgid() システムコールを呼び出します。前述の通り、Linux ではこれらのシステムコールは呼び出し元の OS スレッドの権限のみを変更します。

Go プログラムでは、複数のゴルーチンが同時に実行され、Go ランタイムはこれらのゴルーチンを動的に利用可能な OS スレッドに割り当てます。もしあるゴルーチンが syscall.Setuid(non_root_uid) を呼び出して権限を降下させたとしても、そのゴルーチンが実行されている OS スレッドの権限のみが変更されます。同じ Go プロセス内の他のゴルーチンは、異なる OS スレッドで実行されている場合、元の(root などの)権限を保持したままになる可能性があります。

これは、開発者が Setuid/Setgid を呼び出す際に期待する「プロセス全体の権限降下」というセマンティクスと大きく乖離します。この不一致は、意図しない特権の保持や、セキュリティ上の脆弱性につながる可能性があります。例えば、プログラムが起動時に root 権限で動作し、その後 Setuid で非特権ユーザーに降下しようとした場合、一部の OS スレッドが依然として root 権限を保持し続けることで、予期せぬ動作やセキュリティホールが発生するリスクがありました。

この問題を根本的に解決するには、Go ランタイムが Setuid/Setgid の呼び出しを検知した際に、プロセス内のすべての OS スレッドの権限を適切に変更するか、あるいは Go の並行モデルと Linux のスレッドモデルの間のセマンティクスのギャップを埋めるようなより複雑なメカニズムを導入する必要がありました。

このコミットの時点では、その根本的な解決策がまだ見つかっていなかったため、一時的な措置として、Linux プラットフォームでの syscall.Setuid および syscall.Setgid の使用を無効化し、その旨をリリースノートに明記することで、ユーザーがこの問題に遭遇しないように、また、誤解を招かないようにしました。これは、問題が解決されるまでの間、安全性を確保するための現実的な対応でした。

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

--- a/doc/go1.4.txt
+++ b/doc/go1.4.txt
@@ -6,4 +6,5 @@ package or cmd/xxx directory name, and ending in a CL number.
 Please keep the list sorted (as in sort.Strings of the lines).
 
 runtime/race: freebsd is supported (CL 107270043)
+syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043)
 time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046)

コアとなるコードの解説

このコミットは、doc/go1.4.txt ファイルに以下の1行を追加しています。

syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043)

この行は、Go 1.4 のリリースノートに記載される重要な変更点です。

  • syscall: Setuid, Setgid are disabled on linux platforms.: Linux 環境において syscall.Setuid および syscall.Setgid が無効化されたことを明確に述べています。これは、これらの関数を呼び出しても期待通りの動作をしない、あるいはエラーを返すようになったことを意味します。
  • On linux those syscalls operate on the calling thread, not the whole process.: 無効化の理由を説明しています。Linux ではこれらのシステムコールがプロセス全体ではなく、呼び出し元のスレッドにのみ作用するという、他のプラットフォームとは異なる挙動を指摘しています。
  • This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved: この挙動が他のプラットフォームのセマンティクスや、開発者の期待と一致しないため、Go の issue 1435 が解決されるまでこれらの操作が無効化されたことを示しています。

この追加により、Go 1.4 を使用する開発者は、Linux 上での Setuid/Setgid の制限について事前に認識し、適切な代替手段を検討できるようになります。

関連リンク

参考にした情報源リンク