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

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

このコミットは、Go言語のディストリビューションツール misc/dist において、tarball(tarアーカイブ)内のファイルのパーミッション(モード)を強制的に 0755 (実行可能ファイルの場合) または 0644 (それ以外の場合) に設定する変更を導入しています。これにより、異なる環境やファイルシステム間でGoのバイナリディストリビューションを展開した際に、一貫したファイルパーミッションが保証され、セキュリティと互換性の問題が軽減されます。

コミット

commit b3ca3e95642f23c682a04d51ed60cc90825b08a5
Author: Andrew Gerrand <adg@golang.org>
Date:   Wed Mar 14 17:09:15 2012 +1100

    misc/dist: force modes to 0755 or 0644 in tarballs
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/5823045

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

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

元コミット内容

    misc/dist: force modes to 0755 or 0644 in tarballs
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/5823045

変更の背景

Go言語のディストリビューションは、様々なオペレーティングシステムやファイルシステム上で利用されます。tarball形式で配布される際、元のファイルシステムでのパーミッション情報がそのままアーカイブに含まれることがあります。しかし、これにより以下のような問題が発生する可能性がありました。

  1. 不適切なパーミッション: 例えば、開発環境で作成されたファイルが、意図せず実行可能パーミッション(0777など)を持ったまま配布されてしまうと、セキュリティ上のリスクとなる可能性があります。逆に、本来実行可能であるべきファイル(例: Goのコンパイラやツールチェインのバイナリ)が、展開後に実行パーミッションを失ってしまうと、ユーザーが手動でパーミッションを変更する必要が生じ、利便性が損なわれます。
  2. 環境依存性: 異なるOSやファイルシステムでは、パーミッションの扱いに微妙な違いがある場合があります。これにより、tarballの展開結果が環境によって異なり、予期せぬ動作を引き起こす可能性がありました。
  3. 一貫性の欠如: Goの公式ディストリビューションとして、常に予測可能で一貫したファイルパーミッションを提供することが求められます。

このコミットは、これらの問題を解決し、Goのディストリビューションがより堅牢で、安全で、使いやすくなるように、tarball内のファイルパーミッションを標準化することを目的としています。具体的には、実行可能ファイルには 0755 (所有者には読み書き実行、グループとその他には読み書き実行)、それ以外のファイルには 0644 (所有者には読み書き、グループとその他には読み取りのみ) を強制的に適用します。

前提知識の解説

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

Unix系OS(Linux, macOSなど)では、ファイルやディレクトリに対してアクセス権限が設定されています。これは「パーミッション」と呼ばれ、通常は3桁または4桁の八進数(例: 755, 644)で表現されます。

各桁は、以下の順序でアクセス権限を示します。

  • 1桁目 (所有者): ファイルの所有者に対する権限
  • 2桁目 (グループ): ファイルが属するグループのメンバーに対する権限
  • 3桁目 (その他): 上記以外のすべてのユーザーに対する権限

各桁は、以下の権限の組み合わせで構成されます。

  • r (read: 読み取り) = 4
  • w (write: 書き込み) = 2
  • x (execute: 実行) = 1

これらの値を合計して、各桁の八進数を決定します。

  • 0755:
    • 所有者: rwx (4+2+1=7) - 読み取り、書き込み、実行
    • グループ: r-x (4+0+1=5) - 読み取り、実行
    • その他: r-x (4+0+1=5) - 読み取り、実行 これは、実行可能ファイルやスクリプトによく使われるパーミッションです。
  • 0644:
    • 所有者: rw- (4+2+0=6) - 読み取り、書き込み
    • グループ: r-- (4+0+0=4) - 読み取り
    • その他: r-- (4+0+0=4) - 読み取り これは、通常のデータファイルや設定ファイルによく使われるパーミッションです。

2. tarball (Tape Archive)

tarballは、複数のファイルやディレクトリを一つのアーカイブファイルにまとめるための形式です。通常、.tar 拡張子を持ち、さらに gzipbzip2 などで圧縮されて .tar.gz.tar.bz2 といった形式で配布されます。Go言語のバイナリディストリビューションも、この形式で提供されることが一般的です。tarアーカイブは、ファイルの内容だけでなく、パーミッション、タイムスタンプ、所有者情報などのメタデータも保存します。

3. Go言語の misc/dist パッケージ

misc/dist は、Go言語のソースツリー内にある内部パッケージで、Goの公式ディストリビューション(バイナリ配布物)を構築するためのツール群を含んでいます。これには、クロスコンパイルされたバイナリをまとめたり、tarballを作成したりする機能が含まれます。このパッケージは、Goのリリースプロセスにおいて重要な役割を担っています。

4. hdr.Mode とビット演算子 &

Go言語の archive/tar パッケージなど、ファイルシステム操作に関連するライブラリでは、ファイルのパーミッションは数値として表現されます。hdr.Mode は、tarヘッダー内のファイルのパーミッション情報を保持するフィールドです。

ビット演算子 & (AND) は、2つの数値の対応するビットを比較し、両方のビットが1の場合にのみ結果のビットを1にする演算です。

  • 0111 (八進数) は、二進数で 001001001 となります。これは、ユーザー、グループ、その他の「実行」ビットがすべて立っている状態を表します。
  • hdr.Mode & 0111 という式は、hdr.Mode の実行可能ビットが立っているかどうかをチェックするために使用されます。もし hdr.Mode のいずれかの実行ビットが1であれば、結果は0以外の値になります。これは、ファイルが実行可能であると判断するための一般的な方法です。

技術的詳細

このコミットは、misc/dist/bindist.go ファイル内の makeTar 関数に修正を加えています。makeTar 関数は、Goのバイナリディストリビューション用のtarballを作成する役割を担っています。

変更の核心は、tarヘッダー (hdr) を書き込む直前に、ファイルのパーミッション (hdr.Mode) を明示的に上書きするロジックを追加した点です。

具体的には、以下の条件分岐が追加されました。

  1. if hdr.Mode&0111 != 0:
    • この条件は、現在のファイルのパーミッション (hdr.Mode) に、実行可能ビット(0111 は八進数で、ユーザー、グループ、その他の実行ビットがすべて1であることを意味します)が一つでも設定されているかどうかをチェックします。
    • もし、ファイルが実行可能であると判断された場合(つまり、hdr.Mode のいずれかの実行ビットが立っている場合)、hdr.Mode0755 に設定されます。これは、所有者には読み書き実行、グループとその他には読み取り実行の権限を与えます。
  2. else:
    • 上記の条件に合致しない場合、つまりファイルが実行可能ではないと判断された場合、hdr.Mode0644 に設定されます。これは、所有者には読み書き、グループとその他には読み取りのみの権限を与えます。

この変更により、tarballに含められるすべてのファイルは、その性質(実行可能か否か)に応じて、標準化されたパーミッションを持つことになります。これにより、tarballが展開される環境によらず、Goのディストリビューションのファイルパーミッションが一貫して保証されるようになります。

また、このコミットでは、tarヘッダーの Uid (ユーザーID) と Gid (グループID) を 0 に設定する既存のロジックも確認できます。これは、tarball内のファイルの所有者情報をルートユーザーに設定することで、展開時の所有者に関する問題を回避し、よりポータブルなアーカイブを作成するための一般的なプラクティスです。

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

変更は misc/dist/bindist.go ファイルの makeTar 関数内で行われています。

--- a/misc/dist/bindist.go
+++ b/misc/dist/bindist.go
@@ -536,6 +536,13 @@ func makeTar(targ, workdir string) error {
 		hdr.Uid = 0
 		hdr.Gid = 0
 
+		// Force mode to 0755 for executables, 0644 for everything else.
+		if hdr.Mode&0111 != 0 {
+			hdr.Mode = 0755
+		} else {
+			hdr.Mode = 0644
+		}
+
 		err = tw.WriteHeader(hdr)
 		if err != nil {
 			return fmt.Errorf("Error writing file %q: %v", name, err)

コアとなるコードの解説

追加されたコードブロックは以下の通りです。

		// Force mode to 0755 for executables, 0644 for everything else.
		if hdr.Mode&0111 != 0 {
			hdr.Mode = 0755
		} else {
			hdr.Mode = 0644
		}
  • // Force mode to 0755 for executables, 0644 for everything else.
    • これはコードの意図を説明するコメントです。実行可能ファイルには 0755 を、それ以外のファイルには 0644 を強制的に適用することを示しています。
  • if hdr.Mode&0111 != 0 { ... }
    • hdr.Mode は現在のファイルのパーミッションを表す数値です。
    • 0111 は八進数で、二進数では 001001001 となります。これは、ユーザー、グループ、その他の実行ビット(x)がすべて1であることを意味します。
    • & はビットAND演算子です。hdr.Mode0111 のビットANDを取ることで、hdr.Mode の実行ビットのいずれかが立っているかどうかを効率的にチェックしています。
    • != 0 は、ビットANDの結果が0でなければ(つまり、いずれかの実行ビットが立っていれば)、条件が真となることを意味します。これにより、ファイルが実行可能であると判断されます。
  • hdr.Mode = 0755
    • ファイルが実行可能であると判断された場合、そのパーミッションを 0755 に設定します。
  • else { hdr.Mode = 0644 }
    • ファイルが実行可能ではないと判断された場合、そのパーミッションを 0644 に設定します。

このロジックは、tarアーカイブにファイルが追加される直前に適用され、アーカイブ内のすべてのファイルが意図したパーミッションを持つことを保証します。これにより、Goのディストリビューションの展開時に、パーミッションに関する問題が発生するリスクが大幅に低減されます。

関連リンク

参考にした情報源リンク