[インデックス 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
ファイル内のファイルパーミッション設定の変更に集約されます。
具体的には、以下の関数呼び出しにおけるファイルパーミッションの引数が変更されています。
-
b.cover
関数:- この関数は、Goのカバレッジツールが使用するカバレッジファイルを生成する際に呼び出されます。
- 変更前:
0666
(rw-rw-rw-) - 変更後:
0644
(rw-r--r--) - これにより、生成されるカバレッジファイルは、所有者のみが書き込み可能となり、他のユーザーは読み込みのみ可能になります。
-
b.copyFile
関数:- この関数は、ビルドプロセス中にファイルをコピーする際に呼び出されます。特に、OSやアーキテクチャ固有のサフィックスを持つファイル(例:
_goos_goarch
)のコピー時に使用されます。 - 変更前:
0666
(rw-rw-rw-) - 変更後:
0644
(rw-r--r--) - これにより、コピーされるファイルも、所有者のみが書き込み可能となり、他のユーザーは読み込みのみ可能になります。
- この関数は、ビルドプロセス中にファイルをコピーする際に呼び出されます。特に、OSやアーキテクチャ固有のサフィックスを持つファイル(例:
-
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
コアとなるコードの解説
変更はすべて、ファイル作成またはコピー時に指定されるパーミッションモードの定数値を変更するものです。
-
b.cover
関数の呼び出し:b.cover(a, coverFile, sourceFile, 0666, cover.Var)
がb.cover(a, coverFile, sourceFile, 0644, cover.Var)
に変更されました。- これは、カバレッジファイルのパーミッションを
0666
(所有者、グループ、その他すべてに読み書き権限) から0644
(所有者に読み書き権限、グループとその他に読み取り権限のみ) に変更しています。これにより、カバレッジファイルが意図せず他のユーザーによって変更されることを防ぎます。
-
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
に変更しています。これにより、ビルドプロセス中に生成される中間ファイルやコピーされるソースファイルが、より安全なパーミッションで作成されるようになります。
-
b.install
関数内のperm
変数の初期化:perm := os.FileMode(0666)
がperm := os.FileMode(0644)
に変更されました。- これは、インストールされるファイルのデフォルトパーミッションを
0666
から0644
に変更しています。
-
b.install
関数内のperm
変数の条件付き変更:if a1.link { perm = 0777 }
がif a1.link { perm = 0755 }
に変更されました。- これは、インストールされるファイルがシンボリックリンクである場合(または実行可能ファイルとして扱われる場合)のパーミッションを
0777
(所有者、グループ、その他すべてに読み書き実行権限) から0755
(所有者に読み書き実行権限、グループとその他に読み取りと実行権限のみ) に変更しています。これにより、インストールされる実行ファイルやライブラリが、不必要に世界書き込み可能になることを防ぎ、セキュリティを向上させています。
これらの変更はすべて、cmd/go
が生成するファイルのデフォルトパーミッションを、よりセキュアな 0644
(ファイルの場合) または 0755
(実行ファイル/リンクの場合) に設定することを目的としています。これにより、Goのビルドおよびインストールプロセスによって作成されるファイルが、意図しないアクセスや改ざんから保護されます。
関連リンク
- Go Issue #7240: https://github.com/golang/go/issues/7240
- Go CL 60480045: https://golang.org/cl/60480045
参考にした情報源リンク
- Unix file permissions: https://en.wikipedia.org/wiki/File-system_permissions#Traditional_Unix_permissions
- Go
os
package documentation: https://pkg.go.dev/os - Go
filepath
package documentation: https://pkg.go.dev/path/filepath - Go
strings
package documentation: https://pkg.go.dev/strings - Go
cmd/go
source code (specificallysrc/cmd/go/build.go
): https://github.com/golang/go/blob/master/src/cmd/go/build.go - Go
cover
package documentation: https://pkg.go.dev/cmd/go/internal/cover (これは内部パッケージですが、cover.Var
の文脈で参照されます)