[インデックス 10557] ファイルの概要
このコミットは、Go言語の syscall
パッケージにおけるOpenBSD固有のバグ修正に関するものです。具体的には、OpenBSD 5.0以前のバージョンで sysctl
システムコールが kern.hostname
および kern.domainname
の長さを正しく返さない問題に対するワークアラウンドの適用条件を修正しています。
コミット
- コミットハッシュ:
595efd0d205b2a1fe143440088f8f394b09c3b8c
- Author: Joel Sing jsing@google.com
- Date: Thu Dec 1 10:17:33 2011 +1100
- コミットメッセージ:
syscall: fix openbsd sysctl hostname/domainname workaround Fixes #2509. R=golang-dev, adg CC=golang-dev https://golang.org/cl/5451055
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/595efd0d205b2a1fe143440088f8f394b09c3b8c
元コミット内容
syscall: fix openbsd sysctl hostname/domainname workaround
Fixes #2509.
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5451055
変更の背景
このコミットは、Go言語の syscall
パッケージがOpenBSD上で sysctl
システムコールを使用してホスト名 (kern.hostname
) やドメイン名 (kern.domainname
) を取得する際に発生していた問題を修正するために行われました。
OpenBSD 5.0より前のバージョンには、sysctl
システムコールに関する特定のバグが存在しました。このバグは、sysctl
を呼び出す際に、取得するデータのバッファサイズを問い合わせるために oldp
引数に nil
を渡した場合に、kern.hostname
や kern.domainname
といった特定のカーネルパラメータの長さが常に 0
として返されるというものでした。これにより、Goの syscall
パッケージは、これらの情報を取得するために必要なバッファのサイズを正しく判断できず、結果としてホスト名やドメイン名の取得に失敗する可能性がありました。
Goの syscall
パッケージには、このOpenBSDのバグに対するワークアラウンドが既に実装されていましたが、そのワークアラウンドが適用される条件に誤りがありました。具体的には、Sysctl
関数の引数として渡された name
(問い合わせるカーネルパラメータの名前) ではなく、Sysctl
関数が内部で処理した結果として得られる value
(取得された値、またはエラー発生時のダミー値) を参照してワークアラウンドを適用しようとしていました。この誤った条件判定により、ワークアラウンドが意図した通りに機能せず、問題が解決されないままでした。
この問題はGoのIssue #2509として報告されており、今回のコミットはその問題を解決するためのものです。
前提知識の解説
sysctl
sysctl
は、Unix系オペレーティングシステム(特にBSD系OS)でカーネルの実行時パラメータを検査および変更するためのメカニズムです。これにより、システム管理者はカーネルの動作を動的に調整したり、システム情報を取得したりすることができます。sysctl
は通常、階層的な名前空間(例: kern.hostname
, net.inet.ip.forwarding
)を通じてパラメータにアクセスします。プログラムからは sysctl
システムコールを介してこれらのパラメータにアクセスします。
sysctl
システムコールは通常、以下の引数を取ります。
name
: 問い合わせるカーネルパラメータのOID (Object Identifier) 配列。namelen
:name
配列の長さ。oldp
: 取得したデータを格納するバッファへのポインタ。oldlenp
:oldp
が指すバッファのサイズへのポインタ。関数呼び出し後には、実際に書き込まれたデータのサイズが格納される。newp
: 設定する新しいデータへのポインタ(パラメータを変更する場合)。newlen
:newp
が指すデータのサイズ(パラメータを変更する場合)。
データを取得する際、oldp
に NULL
を渡し、oldlenp
にバッファサイズを格納する変数のアドレスを渡すことで、必要なバッファサイズを事前に問い合わせることができます。これは、可変長のデータを扱う際によく用いられるパターンです。
OpenBSD
OpenBSDは、セキュリティを最優先事項として開発されているUnix系オペレーティングシステムです。その設計哲学は、コードの品質、堅牢性、そしてセキュリティの厳格な監査に重点を置いています。このため、他のOSと比較して、システムコールの扱いがより厳格であったり、特定のAPIの動作が異なる場合があります。今回の sysctl
のバグも、OpenBSDの特定のバージョンにおける実装の詳細に起因するものです。
Go syscall
パッケージ
Go言語の標準ライブラリには syscall
パッケージが含まれています。このパッケージは、Goプログラムから直接オペレーティングシステムのシステムコールを呼び出すための低レベルなインターフェースを提供します。これにより、GoプログラムはOSの機能(ファイル操作、ネットワーク通信、プロセス管理、システム情報の取得など)に直接アクセスできます。syscall
パッケージはOSごとに異なる実装を持ち、各OSのシステムコールAPIに合わせたラッパーを提供します。
kern.hostname
と kern.domainname
これらはOpenBSDを含む多くのBSD系OSで利用される sysctl
変数です。
kern.hostname
: システムのホスト名(コンピュータの名前)を保持します。kern.domainname
: システムのドメイン名(ネットワークドメインの名前)を保持します。
これらの情報は、ネットワーク上の識別やログ記録など、様々な場面で利用されます。
oldp
パラメータとバッファサイズ問い合わせ
sysctl
システムコールにおいて、oldp
引数に nil
(またはC言語の NULL
) を渡し、oldlenp
に有効なポインタを渡すことで、カーネルは指定されたパラメータのデータを格納するために必要なバッファのサイズを oldlenp
が指す変数に書き込みます。これは、呼び出し側が適切なサイズのバッファを動的に確保するために非常に重要な機能です。OpenBSD 5.0以前の特定のバージョンでは、kern.hostname
や kern.domainname
に対してこの方法で問い合わせた際に、必要なサイズが 0
と誤って報告されるバグがありました。
技術的詳細
Goの syscall
パッケージ内の Sysctl
関数は、OpenBSD上で kern.hostname
や kern.domainname
のような特定の sysctl
変数を扱う際に、OpenBSD 5.0以前のバージョンに存在するバグを回避するためのワークアラウンドを含んでいました。
このバグは、sysctl
システムコールが、kern.hostname
や kern.domainname
のような文字列型のカーネルパラメータに対して、必要なバッファサイズを問い合わせるために oldp
引数に nil
を渡した場合に、常に 0
を返してしまうというものでした。本来であれば、文字列の実際の長さ(終端のNULL文字を含む)が返されるべきです。このため、Goの Sysctl
関数は、この 0
という誤った長さが返された場合に、固定の最大ホスト名長 (MAXHOSTNAMELEN
、通常256バイト) を使用してバッファを確保するというロジックを持っていました。
しかし、このワークアラウンドの適用条件に問題がありました。元のコードでは、if OS == "openbsd" && (value == "kern.hostname" || value == "kern.domainname")
という条件でワークアラウンドを適用しようとしていました。ここで value
は Sysctl
関数が最終的に返す文字列であり、これは sysctl
システムコールから実際に取得されたデータ、またはエラーが発生した場合のダミー値です。
問題は、sysctl
システムコールがバグによって 0
の長さを返した場合、Sysctl
関数はまだ正しいホスト名やドメイン名を取得できていないため、value
が kern.hostname
や kern.domainname
と一致することはありえません。ワークアラウンドは、Sysctl
関数に渡された 入力パラメータ である name
(つまり、どの sysctl
変数を問い合わせようとしているのか) に基づいて適用されるべきでした。
このコミットは、この論理的な誤りを修正し、ワークアラウンドの適用条件を name == "kern.hostname" || name == "kern.domainname"
に変更することで、OpenBSDの特定のバージョンにおける sysctl
のバグに正しく対処できるようにしました。これにより、GoプログラムがOpenBSD上でホスト名やドメイン名を安定して取得できるようになります。
コアとなるコードの変更箇所
src/pkg/syscall/syscall_bsd.go
ファイルの以下の行が変更されました。
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -563,7 +563,7 @@ func Sysctl(name string) (value string, err error) {
// Work around a bug that was fixed after OpenBSD 5.0.
// The length for kern.hostname and kern.domainname is always
// returned as 0 when a nil value is passed for oldp.
- if OS == "openbsd" && (value == "kern.hostname" || value == "kern.domainname") {
+ if OS == "openbsd" && (name == "kern.hostname" || name == "kern.domainname") {
// MAXHOSTNAMELEN
n = 256
} else {
コアとなるコードの解説
変更された行は、Sysctl
関数内のOpenBSD固有のワークアラウンドの条件式です。
元のコード:
if OS == "openbsd" && (value == "kern.hostname" || value == "kern.domainname") {
この条件式では、オペレーティングシステムがOpenBSDであることに加えて、Sysctl
関数が返す value
変数が "kern.hostname"
または "kern.domainname"
と一致するかどうかをチェックしていました。しかし、前述の通り、value
は sysctl
システムコールから実際に取得されたデータであり、バグによって長さが 0
と返された場合、この value
は期待するホスト名やドメイン名にはなりません。したがって、この条件は常に false
となり、ワークアラウンドが適用されませんでした。
修正後のコード:
if OS == "openbsd" && (name == "kern.hostname" || name == "kern.domainname") {
修正後は、value
の代わりに name
変数を使用しています。name
は Sysctl
関数に引数として渡される文字列であり、ユーザーがどの sysctl
変数(例: "kern.hostname"
)の情報を取得しようとしているのかを正確に示します。これにより、OpenBSDの特定のバージョンで kern.hostname
や kern.domainname
を問い合わせる場合にのみ、このワークアラウンドが正しく適用されるようになります。ワークアラウンドが適用されると、必要なバッファサイズ n
が MAXHOSTNAMELEN
(256バイト) に設定され、ホスト名やドメイン名の取得が正常に行われるようになります。
この変更は、Goの syscall
パッケージがOpenBSD上でより堅牢に動作するために不可欠な修正でした。
関連リンク
- Go Issue #2509: https://golang.org/issue/2509 (コミットメッセージに記載されているIssue番号)
- Go CL 5451055: https://golang.org/cl/5451055 (Goのコードレビューシステムにおける変更リスト)