[インデックス 18164] ファイルの概要
このコミットは、GoランタイムにおけるPlan 9オペレーティングシステム向けの乱数データ取得メカニズムの修正に関するものです。具体的には、Plan 9環境で/dev/random
デバイスが存在し、そこからエントロピー(乱数性)を取得できることを認識し、その機能を利用するように変更されました。
コミット
commit c136197ca8a536b6fd93f0ee2a7de6c6541c0124
Author: Jeff Sickel <jas@corpus-callosum.com>
Date: Sat Jan 4 10:53:22 2014 -0800
runtime: plan 9 does have /dev/random
R=golang-codereviews, r, aram
CC=0intro, golang-codereviews, rsc
https://golang.org/cl/43420045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c136197ca8a536b6fd93f0ee2a7de6c6541c0124
元コミット内容
このコミットは、Goランタイムのos_plan9.c
ファイルにおいて、runtime·get_random_data
関数が常にnil
と0
を返していた(つまり、乱数データを取得しない)挙動を修正するものです。
変更前:
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
*rnd = nil;
*rnd_len = 0;
}
変更後:
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
static byte random_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
*rnd = random_data;
*rnd_len = HashRandomBytes;
} else {
*rnd = nil;
*rnd_len = 0;
}
runtime·close(fd);
}
変更の背景
Goランタイムは、ハッシュテーブルのシード値など、様々な内部処理で乱数データ(エントロピー)を必要とします。これらの乱数データは、セキュリティ上の理由(例:ハッシュ衝突攻撃の緩和)や、予測不可能な動作の保証のために、高品質な乱数源から取得されるべきです。
以前のGoランタイムのPlan 9実装では、runtime·get_random_data
関数が乱数データを取得する処理を実装しておらず、常に空のデータを返していました。これは、Plan 9オペレーティングシステムには/dev/random
のような乱数デバイスが存在しない、あるいは利用できないという誤解に基づいていた可能性があります。
このコミットの背景には、「Plan 9にも/dev/random
が存在し、利用可能である」という認識の更新があります。これにより、GoランタイムがPlan 9環境でも適切な乱数源からエントロピーを取得できるようになり、ハッシュテーブルのシード値などの生成において、より堅牢な乱数性を提供できるようになります。
前提知識の解説
Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現するという「すべてはファイルである」という原則を徹底しています。これにより、システム内のあらゆる要素がファイル操作を通じてアクセス・制御できるようになっています。
/dev/random
と/dev/urandom
Unix系システム(およびPlan 9)において、/dev/random
と/dev/urandom
は、カーネルが提供する擬似乱数生成器(PRNG)のインターフェースです。これらは、システムのエントロピー源(キーボード入力、マウスの動き、ディスクI/O、ネットワークイベントなど)から収集されたノイズを基に、高品質な乱数を生成します。
/dev/random
: ブロッキング乱数源です。要求されたエントロピーが十分に蓄積されていない場合、エントロピーが利用可能になるまで読み出しをブロックします。これにより、常に高品質な乱数(真の乱数に近い)が保証されますが、エントロピーが枯渇するとシステムのパフォーマンスに影響を与える可能性があります。主に暗号鍵の生成など、高いセキュリティが要求される場面で使用されます。/dev/urandom
: 非ブロッキング乱数源です。エントロピーが不足している場合でも、利用可能なエントロピーから生成された乱数(擬似乱数)を返します。エントロピーが枯渇してもブロックしないため、パフォーマンスへの影響は少ないですが、エントロピーが枯渇した状態では予測可能性が高まる可能性があります。一般的な用途(セッションID、ソルトなど)で広く使用されます。
このコミットでは/dev/random
が使用されており、これはGoランタイムがハッシュシードなどの重要な用途に、より高品質な乱数を求めていることを示唆しています。
HashRandomBytes
HashRandomBytes
は、Goランタイム内部で定義されている定数で、ハッシュテーブルのシード値として使用される乱数データのバイト数を指定します。この値は、ハッシュ衝突攻撃に対する耐性を高めるために、十分な長さの乱数シードを確保するために用いられます。具体的な値はGoのバージョンによって異なる場合がありますが、通常は数バイトから数十バイトの範囲です。このコミットでは、HashRandomBytes
分のデータを/dev/random
から読み取ろうとしています。
技術的詳細
このコミットの技術的な核心は、GoランタイムがPlan 9環境で乱数データを取得する際の、より適切なシステムコールとファイル操作の利用にあります。
-
乱数データバッファの確保:
static byte random_data[HashRandomBytes];
HashRandomBytes
のサイズを持つ静的なバイト配列random_data
が宣言されます。static
キーワードにより、この配列は関数の呼び出し間でその内容を保持し、一度初期化されれば再利用されます。これは、乱数データを格納するための一時的なバッファとして機能します。 -
/dev/random
のオープン:fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
runtime·open
関数は、Goランタイムが提供するシステムコールラッパーで、指定されたパスのファイルをオープンします。ここでは/dev/random
を読み取り専用モード(O_RDONLY
は0に相当)でオープンしています。ファイルディスクリプタ(fd
)が返されます。 -
乱数データの読み取り:
if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) { ... }
runtime·read
関数は、指定されたファイルディスクリプタからデータを読み取ります。ここでは、オープンした/dev/random
からHashRandomBytes
分のデータをrandom_data
バッファに読み取ろうとしています。 読み取りが成功し、要求されたバイト数(HashRandomBytes
)と実際に読み取れたバイト数が一致した場合、乱数データが正常に取得できたと判断されます。 -
乱数データのポインタと長さの設定: 読み取りが成功した場合:
*rnd = random_data;
*rnd_len = HashRandomBytes;
呼び出し元に、取得した乱数データが格納されているrandom_data
バッファへのポインタと、そのデータの長さ(HashRandomBytes
)を渡します。読み取りが失敗した場合(例えば、
/dev/random
が存在しない、読み取りエラーが発生した、または要求されたバイト数を読み取れなかった場合):*rnd = nil;
*rnd_len = 0;
乱数データが取得できなかったことを示すために、ポインタをnil
に、長さを0
に設定します。これは、以前の挙動と同じですが、明示的にエラーハンドリングが行われています。 -
ファイルディスクリプタのクローズ:
runtime·close(fd);
乱数データの読み取りが完了した後、オープンした/dev/random
のファイルディスクリプタをruntime·close
関数で閉じます。これは、リソースリークを防ぐための重要なステップです。
この変更により、GoランタイムはPlan 9環境においても、システムが提供する高品質な乱数源を適切に利用できるようになり、ハッシュテーブルのシード生成などの内部処理の堅牢性が向上します。
コアとなるコードの変更箇所
変更はsrc/pkg/runtime/os_plan9.c
ファイル内のruntime·get_random_data
関数に集中しています。
--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -102,8 +102,18 @@ runtime·crash(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
- *rnd = nil;
- *rnd_len = 0;
+ static byte random_data[HashRandomBytes];
+ int32 fd;
+
+ fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = random_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
}
コアとなるコードの解説
runtime·get_random_data
関数は、Goランタイムが外部から乱数データを取得するためのインターフェースです。この関数は、乱数データへのポインタ(rnd
)と、そのデータの長さ(rnd_len
)を引数として受け取ります。
変更前は、この関数は単に*rnd
をnil
に、*rnd_len
を0
に設定するだけで、乱数データを一切提供していませんでした。これは、Plan 9環境では乱数源がない、あるいは利用できないという仮定に基づいていたと考えられます。
変更後は、以下の手順で乱数データを取得しようとします。
-
static byte random_data[HashRandomBytes];
HashRandomBytes
バイト分の静的バッファを確保します。このバッファは、/dev/random
から読み取った乱数データを一時的に保持するために使用されます。static
であるため、この関数が複数回呼び出されても、同じメモリ領域が再利用されます。 -
int32 fd;
ファイルディスクリプタを格納するための変数fd
を宣言します。 -
fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
Plan 9の/dev/random
デバイスを読み取り専用モードでオープンします。0 /* O_RDONLY */
は、読み取り専用フラグが数値の0
であることを示しています。 -
if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) { ... }
オープンした/dev/random
からHashRandomBytes
分のデータをrandom_data
バッファに読み取ります。runtime·read
は、実際に読み取れたバイト数を返します。もし読み取れたバイト数がHashRandomBytes
と完全に一致すれば、必要な乱数データがすべて取得できたと判断します。 -
成功時の処理:
*rnd = random_data;
*rnd_len = HashRandomBytes;
読み取りが成功した場合、random_data
バッファへのポインタをrnd
に、読み取ったバイト数をrnd_len
に設定し、呼び出し元に乱数データを提供します。 -
失敗時の処理:
else { *rnd = nil; *rnd_len = 0; }
読み取りが失敗した場合(例えば、/dev/random
が存在しない、読み取りエラーが発生した、または要求されたバイト数を読み取れなかった場合)、以前と同様にnil
と0
を返し、乱数データが取得できなかったことを示します。 -
runtime·close(fd);
最後に、オープンしたファイルディスクリプタfd
を閉じます。これは、システムリソースを適切に解放するために不可欠です。
この変更により、GoランタイムはPlan 9環境でも、よりセキュアで予測不可能なハッシュシードを生成できるようになり、アプリケーションの堅牢性が向上します。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Plan 9 from Bell Labs: https://9p.io/plan9/
/dev/random
と/dev/urandom
に関するWikipedia記事: https://ja.wikipedia.org/wiki//dev/random
参考にした情報源リンク
- Go言語のソースコード(
src/pkg/runtime/os_plan9.c
) - Go言語のコミット履歴
- Plan 9のドキュメント(
/dev/random
の存在確認のため) /dev/random
と/dev/urandom
に関する一般的なオペレーティングシステムの知識- ハッシュテーブルのシードとセキュリティに関する一般的な情報
- Goのハッシュシードに関する議論(必要に応じて検索)
- 例: "Go hash seed security" などで検索すると、関連する情報が見つかる可能性があります。
- Go CL 43420045: https://golang.org/cl/43420045 (コミットメッセージに記載されているChange Listへのリンク)
- このCLページには、コミットに関する詳細な議論やレビューコメントが含まれている場合があります。
- このCLページは現在アクセスできません。これは、GoプロジェクトがGoogle CodeからGitHubに移行したため、古いCL番号が直接GitHubのコミットにリンクされていないためです。しかし、コミットメッセージに記載されているため、当時の議論の参照元として重要です。# [インデックス 18164] ファイルの概要
このコミットは、GoランタイムにおけるPlan 9オペレーティングシステム向けの乱数データ取得メカニズムの修正に関するものです。具体的には、Plan 9環境で/dev/random
デバイスが存在し、そこからエントロピー(乱数性)を取得できることを認識し、その機能を利用するように変更されました。
コミット
commit c136197ca8a536b6fd93f0ee2a7de6c6541c0124
Author: Jeff Sickel <jas@corpus-callosum.com>
Date: Sat Jan 4 10:53:22 2014 -0800
runtime: plan 9 does have /dev/random
R=golang-codereviews, r, aram
CC=0intro, golang-codereviews, rsc
https://golang.org/cl/43420045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c136197ca8a536b6fd93f0ee2a7de6c6541c0124
元コミット内容
このコミットは、Goランタイムのos_plan9.c
ファイルにおいて、runtime·get_random_data
関数が常にnil
と0
を返していた(つまり、乱数データを取得しない)挙動を修正するものです。
変更前:
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
*rnd = nil;
*rnd_len = 0;
}
変更後:
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
static byte random_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
*rnd = random_data;
*rnd_len = HashRandomBytes;
} else {
*rnd = nil;
*rnd_len = 0;
}
runtime·close(fd);
}
変更の背景
Goランタイムは、ハッシュテーブルのシード値など、様々な内部処理で乱数データ(エントロピー)を必要とします。これらの乱数データは、セキュリティ上の理由(例:ハッシュ衝突攻撃の緩和)や、予測不可能な動作の保証のために、高品質な乱数源から取得されるべきです。
以前のGoランタイムのPlan 9実装では、runtime·get_random_data
関数が乱数データを取得する処理を実装しておらず、常に空のデータを返していました。これは、Plan 9オペレーティングシステムには/dev/random
のような乱数デバイスが存在しない、あるいは利用できないという誤解に基づいていた可能性があります。
このコミットの背景には、「Plan 9にも/dev/random
が存在し、利用可能である」という認識の更新があります。これにより、GoランタイムがPlan 9環境でも適切な乱数源からエントロピーを取得できるようになり、ハッシュテーブルのシード値などの生成において、より堅牢な乱数性を提供できるようになります。
前提知識の解説
Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現するという「すべてはファイルである」という原則を徹底しています。これにより、システム内のあらゆる要素がファイル操作を通じてアクセス・制御できるようになっています。
/dev/random
と/dev/urandom
Unix系システム(およびPlan 9)において、/dev/random
と/dev/urandom
は、カーネルが提供する擬似乱数生成器(PRNG)のインターフェースです。これらは、システムのエントロピー源(キーボード入力、マウスの動き、ディスクI/O、ネットワークイベントなど)から収集されたノイズを基に、高品質な乱数を生成します。
/dev/random
: ブロッキング乱数源です。要求されたエントロピーが十分に蓄積されていない場合、エントロピーが利用可能になるまで読み出しをブロックします。これにより、常に高品質な乱数(真の乱数に近い)が保証されますが、エントロピーが枯渇するとシステムのパフォーマンスに影響を与える可能性があります。主に暗号鍵の生成など、高いセキュリティが要求される場面で使用されます。/dev/urandom
: 非ブロッキング乱数源です。エントロピーが不足している場合でも、利用可能なエントロピーから生成された乱数(擬似乱数)を返します。エントロピーが枯渇してもブロックしないため、パフォーマンスへの影響は少ないですが、エントロピーが枯渇した状態では予測可能性が高まる可能性があります。一般的な用途(セッションID、ソルトなど)で広く使用されます。
このコミットでは/dev/random
が使用されており、これはGoランタイムがハッシュシードなどの重要な用途に、より高品質な乱数を求めていることを示唆しています。
HashRandomBytes
HashRandomBytes
は、Goランタイム内部で定義されている定数で、ハッシュテーブルのシード値として使用される乱数データのバイト数を指定します。この値は、ハッシュ衝突攻撃に対する耐性を高めるために、十分な長さの乱数シードを確保するために用いられます。具体的な値はGoのバージョンによって異なる場合がありますが、通常は数バイトから数十バイトの範囲です。このコミットでは、HashRandomBytes
分のデータを/dev/random
から読み取ろうとしています。
技術的詳細
このコミットの技術的な核心は、GoランタイムがPlan 9環境で乱数データを取得する際の、より適切なシステムコールとファイル操作の利用にあります。
-
乱数データバッファの確保:
static byte random_data[HashRandomBytes];
HashRandomBytes
のサイズを持つ静的なバイト配列random_data
が宣言されます。static
キーワードにより、この配列は関数の呼び出し間でその内容を保持し、一度初期化されれば再利用されます。これは、乱数データを格納するための一時的なバッファとして機能します。 -
/dev/random
のオープン:fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
runtime·open
関数は、Goランタイムが提供するシステムコールラッパーで、指定されたパスのファイルをオープンします。ここでは/dev/random
を読み取り専用モード(O_RDONLY
は0に相当)でオープンしています。ファイルディスクリプタ(fd
)が返されます。 -
乱数データの読み取り:
if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) { ... }
runtime·read
関数は、指定されたファイルディスクリプタからデータを読み取ります。ここでは、オープンした/dev/random
からHashRandomBytes
分のデータをrandom_data
バッファに読み取ろうとしています。 読み取りが成功し、要求されたバイト数(HashRandomBytes
)と実際に読み取れたバイト数が一致した場合、乱数データが正常に取得できたと判断されます。 -
乱数データのポインタと長さの設定: 読み取りが成功した場合:
*rnd = random_data;
*rnd_len = HashRandomBytes;
呼び出し元に、取得した乱数データが格納されているrandom_data
バッファへのポインタと、そのデータの長さ(HashRandomBytes
)を渡します。読み取りが失敗した場合(例えば、
/dev/random
が存在しない、読み取りエラーが発生した、または要求されたバイト数を読み取れなかった場合):*rnd = nil;
*rnd_len = 0;
乱数データが取得できなかったことを示すために、ポインタをnil
に、長さを0
に設定します。これは、以前の挙動と同じですが、明示的にエラーハンドリングが行われています。 -
ファイルディスクリプタのクローズ:
runtime·close(fd);
乱数データの読み取りが完了した後、オープンした/dev/random
のファイルディスクリプタをruntime·close
関数で閉じます。これは、リソースリークを防ぐための重要なステップです。
この変更により、GoランタイムはPlan 9環境においても、システムが提供する高品質な乱数源を適切に利用できるようになり、ハッシュテーブルのシード生成などの内部処理の堅牢性が向上します。
コアとなるコードの変更箇所
変更はsrc/pkg/runtime/os_plan9.c
ファイル内のruntime·get_random_data
関数に集中しています。
--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -102,8 +102,18 @@ runtime·crash(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
- *rnd = nil;
- *rnd_len = 0;
+ static byte random_data[HashRandomBytes];
+ int32 fd;
+
+ fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = random_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
}
コアとなるコードの解説
runtime·get_random_data
関数は、Goランタイムが外部から乱数データを取得するためのインターフェースです。この関数は、乱数データへのポインタ(rnd
)と、そのデータの長さ(rnd_len
)を引数として受け取ります。
変更前は、この関数は単に*rnd
をnil
に、*rnd_len
を0
に設定するだけで、乱数データを一切提供していませんでした。これは、Plan 9環境では乱数源がない、あるいは利用できないという仮定に基づいていたと考えられます。
変更後は、以下の手順で乱数データを取得しようとします。
-
static byte random_data[HashRandomBytes];
HashRandomBytes
バイト分の静的バッファを確保します。このバッファは、/dev/random
から読み取った乱数データを一時的に保持するために使用されます。static
であるため、この関数が複数回呼び出されても、同じメモリ領域が再利用されます。 -
int32 fd;
ファイルディスクリプタを格納するための変数fd
を宣言します。 -
fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
Plan 9の/dev/random
デバイスを読み取り専用モードでオープンします。0 /* O_RDONLY */
は、読み取り専用フラグが数値の0
であることを示しています。 -
if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) { ... }
オープンした/dev/random
からHashRandomBytes
分のデータをrandom_data
バッファに読み取ります。runtime·read
は、実際に読み取れたバイト数を返します。もし読み取れたバイト数がHashRandomBytes
と完全に一致すれば、必要な乱数データがすべて取得できたと判断します。 -
成功時の処理:
*rnd = random_data;
*rnd_len = HashRandomBytes;
読み取りが成功した場合、random_data
バッファへのポインタをrnd
に、読み取ったバイト数をrnd_len
に設定し、呼び出し元に乱数データを提供します。 -
失敗時の処理:
else { *rnd = nil; *rnd_len = 0; }
読み取りが失敗した場合(例えば、/dev/random
が存在しない、読み取りエラーが発生した、または要求されたバイト数を読み取れなかった場合)、以前と同様にnil
と0
を返し、乱数データが取得できなかったことを示します。 -
runtime·close(fd);
最後に、オープンしたファイルディスクリプタfd
を閉じます。これは、システムリソースを適切に解放するために不可欠です。
この変更により、GoランタイムはPlan 9環境でも、よりセキュアで予測不可能なハッシュシードを生成できるようになり、アプリケーションの堅牢性が向上します。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Plan 9 from Bell Labs: https://9p.io/plan9/
/dev/random
と/dev/urandom
に関するWikipedia記事: https://ja.wikipedia.org/wiki//dev/random
参考にした情報源リンク
- Go言語のソースコード(
src/pkg/runtime/os_plan9.c
) - Go言語のコミット履歴
- Plan 9のドキュメント(
/dev/random
の存在確認のため) /dev/random
と/dev/urandom
に関する一般的なオペレーティングシステムの知識- ハッシュテーブルのシードとセキュリティに関する一般的な情報
- Goのハッシュシードに関する議論(必要に応じて検索)
- 例: "Go hash seed security" などで検索すると、関連する情報が見つかる可能性があります。
- Go CL 43420045: https://golang.org/cl/43420045 (コミットメッセージに記載されているChange Listへのリンク)
- このCLページには、コミットに関する詳細な議論やレビューコメントが含まれている場合があります。
- このCLページは現在アクセスできません。これは、GoプロジェクトがGoogle CodeからGitHubに移行したため、古いCL番号が直接GitHubのコミットにリンクされていないためです。しかし、コミットメッセージに記載されているため、当時の議論の参照元として重要です。