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

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

このコミットは、Go言語のコマンドラインツール cmd/go におけるファイル作成時のパーミッション設定に関する変更です。具体的には、生成されるファイルが意図せず世界書き込み可能(world-writable)になるのを防ぐための修正が行われています。

コミット

commit c66956cdb1f3e0c0e692f7d7ea6034b41c85af47
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Thu Feb 6 17:54:33 2014 -0500

    cmd/go: do not create world-writable files.
    Fixes #7240.
    
    LGTM=tommi.virtanen, bradfitz
    R=golang-codereviews, tommi.virtanen, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/60480045

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

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

元コミット内容

cmd/go: do not create world-writable files. Fixes #7240.

このコミットメッセージは簡潔ですが、その意図は明確です。cmd/go ツールが生成するファイルが、すべてのユーザーから書き込み可能(world-writable)なパーミッションで作成されないように修正するというものです。これは、GoのIssue #7240を解決するための変更です。

変更の背景

Go言語のビルドツールである cmd/go は、ソースコードのコンパイル、テスト、インストールなど、様々な操作を行います。これらの操作の過程で、中間ファイルや最終的なバイナリファイルなどが生成されます。

このコミットが行われた背景には、セキュリティ上の懸念がありました。以前の cmd/go の実装では、一部のファイルが 0666(rw-rw-rw-)や 0777(rwxrwxrwx)といったパーミッションで作成される可能性がありました。これは、ファイルが作成されたシステム上のすべてのユーザーが、そのファイルを読み書きまたは実行できることを意味します。

このようなパーミッションは、特に共有環境やマルチユーザーシステムにおいて、セキュリティリスクとなります。悪意のあるユーザーが、世界書き込み可能なファイルを改ざんしたり、不正なコードを挿入したりする可能性があります。例えば、ビルドプロセス中に生成される一時ファイルや、インストールされるバイナリが世界書き込み可能である場合、システム全体のセキュリティが脅かされる可能性があります。

Goチームは、この問題をIssue #7240として認識し、ファイルパーミッションをより安全なデフォルト値に設定することで、この脆弱性を修正する必要があると判断しました。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

1. Unix/Linuxファイルパーミッション

Unix系OS(Linux、macOSなど)では、ファイルやディレクトリにはパーミッション(アクセス権)が設定されています。これは、誰がそのファイルにアクセスできるか、どのような操作(読み込み、書き込み、実行)ができるかを制御します。

パーミッションは通常、3桁の8進数で表現されます。各桁はそれぞれ「所有者(owner)」「グループ(group)」「その他(others/world)」に対する権限を表します。各桁の数値は、以下の権限の合計です。

  • 4: 読み込み(read, r
  • 2: 書き込み(write, w
  • 1: 実行(execute, x

例えば:

  • 0666: rw-rw-rw-
    • 所有者: 読み書き可能 (4+2=6)
    • グループ: 読み書き可能 (4+2=6)
    • その他: 読み書き可能 (4+2=6)
    • これは「世界書き込み可能(world-writable)」なファイルパーミッションであり、セキュリティ上のリスクが高いとされます。
  • 0644: rw-r--r--
    • 所有者: 読み書き可能 (4+2=6)
    • グループ: 読み込みのみ (4)
    • その他: 読み込みのみ (4)
    • これは一般的なファイルパーミッションで、所有者のみが書き込みでき、他のユーザーは読み込みのみ可能です。
  • 0777: rwxrwxrwx
    • 所有者: 読み書き実行可能 (4+2+1=7)
    • グループ: 読み書き実行可能 (4+2+1=7)
    • その他: 読み書き実行可能 (4+2+1=7)
    • これは「世界書き込み実行可能(world-writable and executable)」なディレクトリや実行ファイルパーミッションであり、非常に危険です。
  • 0755: rwxr-xr-x
    • 所有者: 読み書き実行可能 (4+2+1=7)
    • グループ: 読み込み実行可能 (4+1=5)
    • その他: 読み込み実行可能 (4+1=5)
    • これは一般的な実行ファイルやディレクトリのパーミッションで、所有者のみが書き込みでき、他のユーザーは読み込みと実行のみ可能です。

2. os.FileMode (Go言語)

Go言語の os パッケージには、ファイルパーミッションを扱うための FileMode 型があります。これは、Unix系OSのファイルパーミッションを抽象化したものです。os.FileMode(0644) のように、8進数リテラルを使用してパーミッションを指定します。

3. cmd/go のビルドプロセス

cmd/go は、Goのソースコードをビルドする際に、様々な内部処理を行います。これには、ソースファイルのコピー、カバレッジファイルの生成、最終的なバイナリのインストールなどが含まれます。これらの操作中に、新しいファイルが作成されることがあります。

技術的詳細

このコミットの技術的な詳細は、src/cmd/go/build.go ファイル内のファイルパーミッション設定の変更に集約されます。

具体的には、以下の関数呼び出しにおけるファイルパーミッションの引数が変更されています。

  1. b.cover 関数:

    • この関数は、Goのカバレッジツールが使用するカバレッジファイルを生成する際に呼び出されます。
    • 変更前: 0666 (rw-rw-rw-)
    • 変更後: 0644 (rw-r--r--)
    • これにより、生成されるカバレッジファイルは、所有者のみが書き込み可能となり、他のユーザーは読み込みのみ可能になります。
  2. b.copyFile 関数:

    • この関数は、ビルドプロセス中にファイルをコピーする際に呼び出されます。特に、OSやアーキテクチャ固有のサフィックスを持つファイル(例: _goos_goarch)のコピー時に使用されます。
    • 変更前: 0666 (rw-rw-rw-)
    • 変更後: 0644 (rw-r--r--)
    • これにより、コピーされるファイルも、所有者のみが書き込み可能となり、他のユーザーは読み込みのみ可能になります。
  3. b.install 関数:

    • この関数は、ビルドされたパッケージやバイナリをインストールする際に呼び出されます。
    • 変更前: perm := os.FileMode(0666) および perm = 0777 (リンクの場合)
    • 変更後: perm := os.FileMode(0644) および perm = 0755 (リンクの場合)
    • これにより、インストールされるファイル(ライブラリやバイナリ)は、所有者のみが書き込み可能となり、他のユーザーは読み込みのみ可能になります。また、実行ファイルやディレクトリとしてリンクされる場合は、所有者のみが書き込み可能で、他のユーザーは読み込みと実行のみ可能になります。

これらの変更は、cmd/go が生成するすべてのファイルに対して、より制限された、しかし一般的なファイルパーミッションを適用することを目的としています。これにより、意図しないファイル改ざんのリスクが低減されます。

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

src/cmd/go/build.go ファイルにおいて、以下の行が変更されています。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -816,7 +816,7 @@ func (b *builder) build(a *action) (err error) {
 			continue
 		}
 		coverFile := filepath.Join(obj, file)
-		if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
+		if err := b.cover(a, coverFile, sourceFile, 0644, cover.Var); err != nil {
 			return err
 		}
 		gofiles = append(gofiles, coverFile)
@@ -911,17 +911,17 @@ func (b *builder) build(a *action) (err error) {
 		switch {
 		case strings.HasSuffix(name, _goos_goarch):
 			targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
 				return err
 			}
 		case strings.HasSuffix(name, _goarch):
 			targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
 				return err
 			}
 		case strings.HasSuffix(name, _goos):
 			targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
 				return err
 			}
 		}
@@ -993,9 +993,9 @@ func (b *builder) install(a *action) (err error) {
 		}
 	}()
 	a1 := a.deps[0]
-	perm := os.FileMode(0666)
+	perm := os.FileMode(0644)
 	if a1.link {
-		perm = 0777
+		perm = 0755
 	}
 
 	// make target directory

コアとなるコードの解説

変更はすべて、ファイル作成またはコピー時に指定されるパーミッションモードの定数値を変更するものです。

  1. b.cover 関数の呼び出し:

    • b.cover(a, coverFile, sourceFile, 0666, cover.Var)b.cover(a, coverFile, sourceFile, 0644, cover.Var) に変更されました。
    • これは、カバレッジファイルのパーミッションを 0666 (所有者、グループ、その他すべてに読み書き権限) から 0644 (所有者に読み書き権限、グループとその他に読み取り権限のみ) に変更しています。これにより、カバレッジファイルが意図せず他のユーザーによって変更されることを防ぎます。
  2. b.copyFile 関数の呼び出し:

    • b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666)b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644) に変更されました。
    • この変更は3箇所にわたって行われており、_goos_goarch_goarch_goos サフィックスを持つファイルをコピーする際のパーミッションを 0666 から 0644 に変更しています。これにより、ビルドプロセス中に生成される中間ファイルやコピーされるソースファイルが、より安全なパーミッションで作成されるようになります。
  3. b.install 関数内の perm 変数の初期化:

    • perm := os.FileMode(0666)perm := os.FileMode(0644) に変更されました。
    • これは、インストールされるファイルのデフォルトパーミッションを 0666 から 0644 に変更しています。
  4. b.install 関数内の perm 変数の条件付き変更:

    • if a1.link { perm = 0777 }if a1.link { perm = 0755 } に変更されました。
    • これは、インストールされるファイルがシンボリックリンクである場合(または実行可能ファイルとして扱われる場合)のパーミッションを 0777 (所有者、グループ、その他すべてに読み書き実行権限) から 0755 (所有者に読み書き実行権限、グループとその他に読み取りと実行権限のみ) に変更しています。これにより、インストールされる実行ファイルやライブラリが、不必要に世界書き込み可能になることを防ぎ、セキュリティを向上させています。

これらの変更はすべて、cmd/go が生成するファイルのデフォルトパーミッションを、よりセキュアな 0644 (ファイルの場合) または 0755 (実行ファイル/リンクの場合) に設定することを目的としています。これにより、Goのビルドおよびインストールプロセスによって作成されるファイルが、意図しないアクセスや改ざんから保護されます。

関連リンク

参考にした情報源リンク