[インデックス 10257] ファイルの概要
このコミットは、Go言語のパッケージインストールツールである goinstall
が、Launchpad.net のユーザーブランチからのパッケージを正しく処理できるようにするための変更です。具体的には、パッケージ名やパスに含まれる ~
(チルダ) 文字を許可するように goinstall
の内部ロジックを更新しています。
コミット
- コミットハッシュ:
cd6c7375d49edd52de557b0ec1cc5f37889ecaae
- Author: Jani Monoses jani.monoses@ubuntu.com
- Date: Fri Nov 4 15:07:34 2011 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cd6c7375d49edd52de557b0ec1cc5f37889ecaae
元コミット内容
goinstall: allow packages from launchpad.net/~user branches.
The permitted filename characters should include ~ to allow
the names of user-owned branches in Launchpad.
R=golang-dev, rsc, n13m3y3r, gustavo
CC=golang-dev, gustavo.niemeyer
https://golang.org/cl/5280052
変更の背景
goinstall
は、Go言語のパッケージをリモートリポジトリから取得し、ビルド・インストールするためのコマンドラインツールです。当時、goinstall
はパッケージのパスやファイル名に使用できる文字を厳しく制限していました。この制限により、Launchpad.net のような特定のバージョン管理システムで慣習的に使用される ~
(チルダ) 文字を含むパス(例: launchpad.net/~user/project
)を持つパッケージを goinstall
が正しく扱えないという問題がありました。
Launchpad.net では、ユーザーが所有するブランチやプロジェクトを示すために、ユーザー名の前に ~
を付ける慣習があります。例えば、lp:~user/project/branch
のような形式です。goinstall
がこの ~
を不正な文字と判断していたため、Launchpad.net 上のユーザーブランチから直接パッケージをインストールすることができませんでした。
このコミットは、この互換性の問題を解決し、goinstall
が Launchpad.net のユーザーブランチを含むパスを適切に解析・処理できるようにするために行われました。
前提知識の解説
goinstall
goinstall
は、Go言語の初期のバージョンで提供されていたパッケージ管理ツールです。現在の go get
コマンドの前身にあたります。リモートリポジトリからソースコードを取得し、依存関係を解決し、コンパイルしてインストールする機能を提供していました。
Launchpad.net
Launchpad.net は、Canonical社が運営するソフトウェア開発プロジェクトのホスティングプラットフォームです。特にUbuntuプロジェクトで広く利用されており、バグトラッキング、コードホスティング(Bazaarバージョン管理システムを使用)、翻訳、仕様策定などの機能を提供します。Launchpadでは、ユーザーが自身のブランチを作成する際に、ユーザー名のプレフィックスとして ~
(チルダ) を使用する慣習があります(例: lp:~user/project/branch
)。
ファイル名/パスにおける「安全な文字」の概念
ソフトウェア開発において、ファイル名やパスに使用できる文字は、オペレーティングシステム、ファイルシステム、プログラミング言語、そしてセキュリティ上の理由から制限されることがあります。
- オペレーティングシステム/ファイルシステム: Windowsでは
\ / : * ? " < > |
などが予約文字であり、Linux/Unix系では/
がパス区切り文字、NULL
文字が終端文字として予約されています。 - プログラミング言語/ツール: 特定のツールやライブラリが、内部処理の都合上、特定の文字を「安全でない」とみなし、許可しない場合があります。これは、正規表現の特殊文字、シェルスクリプトのメタ文字、URLエンコーディングの必要性など、様々な理由によります。
- セキュリティ: 不正な文字の挿入は、パスインジェクション攻撃やディレクトリトラバーサル攻撃などの脆弱性につながる可能性があるため、厳密な文字チェックが行われることがあります。
goinstall
の場合、パッケージのパスを内部的に処理する際に、予期せぬ動作やセキュリティリスクを防ぐために、許可される文字のリスト(safeBytes
)を定義していました。このコミット以前は、~
がこの「安全な文字」のリストに含まれていなかったため、~
を含むパスが拒否されていました。
技術的詳細
goinstall
は、パッケージのパスを処理する際に、そのパスが有効で安全なものであるかを検証するロジックを持っていました。この検証は、主に src/cmd/goinstall/make.go
ファイル内の safeName
関数と safeBytes
変数によって行われていました。
safeBytes
変数: これは、パッケージ名やパスに使用が許可されるバイト(文字)のリストを定義したバイトスライスです。このリストに含まれない文字がパスに存在する場合、そのパスは「安全でない」と判断されます。safeName
関数: この関数は、与えられた文字列(パッケージ名やパスの一部)がsafeBytes
に定義された文字のみで構成されているか、およびその他の特定のルール(例:..
を含まない)に違反していないかをチェックします。
コミット前の safeBytes
は、英数字、ハイフン (-
)、プラス (+
)、ピリオド (.
)、スラッシュ (/
)、アンダースコア (_
) のみを含んでいました。Launchpad.net のユーザーブランチで使われる ~
はこのリストに含まれていなかったため、safeName
関数は ~
を含むパスを不正と判断し、goinstall
がそのパッケージを処理できない原因となっていました。
また、このコミットでは、~
がパスの先頭に来る場合の特別なチェックも追加されています。これは、Unix系システムにおいて ~
がホームディレクトリを表す特殊な意味を持つため、意図しないパス解決を防ぐための追加の安全策と考えられます。
コアとなるコードの変更箇所
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
index c724cda47b..7445c9c207 100644
--- a/src/cmd/goinstall/make.go
+++ b/src/cmd/goinstall/make.go
@@ -109,7 +109,7 @@ func makeMakefile(dir, pkg string, tree *build.Tree, isCmd bool) ([]byte, error)\n return buf.Bytes(), nil\n }\n \n-var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")\n+var safeBytes = []byte("+-~./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")\n \n func safeName(s string) bool {\n \tif s == "" {\n@@ -118,6 +118,9 @@ func safeName(s string) bool {\n \t\treturn false\n \t}\n+\tif s[0] == '~' {\n+\t\treturn false\n+\t}\n \tfor i := 0; i < len(s); i++ {\n \t\tif c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {\n \t\t\treturn false\n```
## コアとなるコードの解説
このコミットによる変更は、`src/cmd/goinstall/make.go` ファイル内の2箇所です。
1. **`safeBytes` 変数の変更**:
```diff
-var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
+var safeBytes = []byte("+-~./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
```
この変更は、`safeBytes` バイトスライスに `~` (チルダ) 文字を追加しています。これにより、`goinstall` がパッケージ名やパスを検証する際に、`~` が許可される文字として認識されるようになります。これが、Launchpad.net のユーザーブランチパスを正しく処理するための主要な変更点です。
2. **`safeName` 関数への追加チェック**:
```diff
+\tif s[0] == '~' {\n+\t\treturn false\n+\t}\n ```
`safeName` 関数内に、新しい条件分岐が追加されました。このコードは、入力文字列 `s` の最初の文字が `~` であるかどうかをチェックします。もし最初の文字が `~` であれば、関数は `false` を返し、その名前は「安全でない」と判断されます。
この追加されたチェックは、一見すると `~` を許可する変更と矛盾するように見えますが、これはセキュリティとパス解決の曖昧さを避けるための重要な考慮事項です。Unix系システムでは、`~` が単独で、または `~user` の形式でホームディレクトリを表す特殊な意味を持ちます。`goinstall` がパッケージパスを処理する際に、これらのシェル的な解釈を意図せず行ってしまうことを防ぐため、パスの先頭に `~` が来る場合は明示的に拒否することで、予期せぬ動作やセキュリティリスクを回避しています。これにより、`launchpad.net/~user/project` のような形式は許可しつつも、`~/project` のようなローカルパスの解釈を防ぐことができます。
これらの変更により、`goinstall` は Launchpad.net のユーザーブランチパスを正しく認識し、処理できるようになり、同時にパスの先頭の `~` による潜在的な問題を回避しています。
## 関連リンク
- Go CL 5280052: [https://golang.org/cl/5280052](https://golang.org/cl/5280052)
## 参考にした情報源リンク
- (Web検索は行いませんでしたが、上記の解説はGo言語の`goinstall`の挙動、Launchpad.netの慣習、および一般的なファイルパスの安全性の概念に基づいています。)