[インデックス 15176] ファイルの概要
このコミットでは、Go言語の標準ライブラリos
およびsyscall
パッケージ内の環境変数設定に関する変更が行われています。具体的には、Unix系システムにおけるSetenv
関数の挙動が修正され、環境変数名(キー)や値に無効な文字が含まれていないかどうかのチェックが追加されました。
変更されたファイルは以下の2つです。
src/pkg/os/env_unix_test.go
: 新規追加されたテストファイルで、Setenv
関数が無効な環境変数名や値に対して正しくエラー(EINVAL
)を返すことを検証します。src/pkg/syscall/env_unix.go
:Setenv
関数の実装が含まれるファイルで、環境変数名に=
や\x00
(NULL文字)、環境変数値に\x00
が含まれていないかをチェックするロジックが追加されました。
コミット
commit d2252d9b0769867fa8a25ba8b274603ddf21c9e9
Author: Péter Surányi <speter.go1@gmail.com>
Date: Fri Feb 8 10:45:46 2013 -0800
syscall: check for invalid characters in Setenv on Unix
On POSIX, '=' in key is explicitly invalid, and '\x00' in key/value is implicitly invalid.
R=golang-dev, iant, bradfitz
CC=golang-dev
https://golang.org/cl/7311061
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d2252d9b0769867fa8a25ba8b274603ddf21c9e9
元コミット内容
syscall: check for invalid characters in Setenv on Unix
On POSIX, '=' in key is explicitly invalid, and '\x00' in key/value is implicitly invalid.
R=golang-dev, iant, bradfitz
CC=golang-dev
https://golang.org/cl/7311061
変更の背景
この変更の背景には、POSIX標準における環境変数の命名規則と、Go言語のSetenv
関数がこれらの規則に準拠していなかったという問題があります。
POSIX(Portable Operating System Interface)は、UNIX系オペレーティングシステム間の互換性を高めるための標準規格です。環境変数に関しては、いくつかの重要な制約があります。
- 環境変数名(キー)に
=
を含めることの禁止: POSIXでは、環境変数はNAME=VALUE
という形式で表現されます。このため、環境変数名自体に=
が含まれていると、パーサーが名前と値の区切りを正しく識別できなくなり、予期せぬ動作を引き起こす可能性があります。 - 環境変数名および値にNULL文字(
\x00
)を含めることの禁止: C言語の文字列はNULL終端であるため、環境変数名や値にNULL文字が含まれていると、文字列が途中で切れてしまい、情報が正しく伝達されなくなります。これは、多くのシステムコールがNULL終端文字列を期待しているため、暗黙的に無効な文字とされています。
Go言語のSetenv
関数は、これらのPOSIX標準の制約を明示的にチェックしていませんでした。その結果、無効な環境変数名や値が設定され、後続のプログラムやシステムコールで問題が発生する可能性がありました。このコミットは、このような潜在的な問題を未然に防ぐために、Setenv
関数にこれらの無効文字チェックを追加し、POSIX標準への準拠を強化することを目的としています。
前提知識の解説
環境変数 (Environment Variables)
環境変数とは、オペレーティングシステムが提供する動的な名前付きの値の集合です。これらは、実行中のプロセスに設定情報や構成データを提供するために使用されます。例えば、PATH
環境変数は実行可能ファイルの検索パスを定義し、HOME
環境変数はユーザーのホームディレクトリを示します。
プログラムは、これらの環境変数を読み取って、その動作を調整することができます。Setenv
関数(またはそれに相当するシステムコール)は、新しい環境変数を設定したり、既存の環境変数の値を変更したりするために使用されます。
Setenv
関数
Setenv
は、指定されたキー(環境変数名)と値で環境変数を設定する関数です。Go言語では、os.Setenv
がこの機能を提供し、内部的にはsyscall.Setenv
を呼び出します。
EINVAL
(Invalid Argument)
EINVAL
は、Unix系システムコールが返すエラーコードの一つで、「無効な引数」を意味します。これは、関数に渡された引数が、その関数の期待する形式や範囲に合致しない場合に返されます。このコミットでは、無効な文字を含む環境変数名や値がSetenv
に渡された際に、このEINVAL
エラーを返すように変更されています。
NULL文字 (\x00
)
NULL文字(ヌル文字)は、ASCIIコードで0x00(10進数で0)に相当する特殊な文字です。C言語では、文字列の終端を示すマーカーとして広く使用されています。そのため、文字列の途中にNULL文字が含まれていると、それ以降のデータが無視される可能性があります。環境変数においても、この特性が問題となるため、キーや値にNULL文字を含めることはできません。
イコール記号 (=
)
イコール記号は、環境変数のキーと値を区切るために使用されます(例: KEY=VALUE
)。このため、環境変数名自体にイコール記号が含まれていると、システムがキーと値の境界を正しく認識できなくなり、環境変数の解析に問題が生じます。
技術的詳細
このコミットの技術的な変更は、主にsyscall/env_unix.go
内のSetenv
関数に、環境変数名と値のバリデーションロジックを追加することにあります。
変更前は、Setenv
関数はキーが空文字列であるかどうかのチェックしか行っていませんでした。
if len(key) == 0 {
return EINVAL
}
変更後、以下の2つのループが追加されました。
-
キーのチェック:
for i := 0; i < len(key); i++ { if key[i] == '=' || key[i] == 0 { return EINVAL } }
このループは、環境変数名(
key
)の各文字を走査し、=
または\x00
(NULL文字)が含まれていないかをチェックします。これらの文字が検出された場合、即座にEINVAL
エラーを返します。 -
値のチェック:
for i := 0; i < len(value); i++ { if value[i] == 0 { return EINVAL } }
このループは、環境変数の値(
value
)の各文字を走査し、\x00
(NULL文字)が含まれていないかをチェックします。NULL文字が検出された場合、即座にEINVAL
エラーを返します。
これらのチェックにより、Setenv
関数はPOSIX標準に準拠し、無効な環境変数が設定されることを防ぐことができます。
また、src/pkg/os/env_unix_test.go
に新しいテストケースTestSetenvUnixEinval
が追加されました。このテストは、以下の無効なキーと値の組み合わせに対してSetenv
を呼び出し、期待通りEINVAL
エラーが返されることを確認します。
- 空のキー (
""
,""
) - キーに
=
が含まれる ("k=v"
,""
) - キーに
\x00
が含まれる ("\x00"
,""
) - 値に
\x00
が含まれる ("k"
,"\x00"
)
これらのテストは、追加されたバリデーションロジックが正しく機能することを保証します。
コアとなるコードの変更箇所
src/pkg/os/env_unix_test.go
(新規追加)
--- /dev/null
+++ b/src/pkg/os/env_unix_test.go
@@ -0,0 +1,30 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd
+
+package os_test
+
+import (
+ . "os"
+ "testing"
+)
+
+var setenvEinvalTests = []struct {
+ k, v string
+}{
+ {"", ""}, // empty key
+ {"k=v", ""}, // '=' in key
+ {"\x00", ""}, // '\x00' in key
+ {"k", "\x00"}, // '\x00' in value
+}
+
+func TestSetenvUnixEinval(t *testing.T) {
+ for _, tt := range setenvEinvalTests {
+ err := Setenv(tt.k, tt.v)
+ if err == nil {
+ t.Errorf(`Setenv(%q, %q) == nil, want error`, tt.k, tt.v)
+ }
+ }
+}
src/pkg/syscall/env_unix.go
--- a/src/pkg/syscall/env_unix.go
+++ b/src/pkg/syscall/env_unix.go
@@ -71,6 +71,16 @@ func Setenv(key, value string) error {
if len(key) == 0 {
return EINVAL
}
+ for i := 0; i < len(key); i++ {
+ if key[i] == '=' || key[i] == 0 {
+ return EINVAL
+ }
+ }
+ for i := 0; i < len(value); i++ {
+ if value[i] == 0 {
+ return EINVAL
+ }
+ }
envLock.Lock()
defer envLock.Unlock()
コアとなるコードの解説
src/pkg/os/env_unix_test.go
このファイルは、os
パッケージのテストの一部として、Unix系システム(Darwin, FreeBSD, Linux, NetBSD, OpenBSD)でのSetenv
の挙動を検証するために新規に作成されました。
+build darwin freebsd linux netbsd openbsd
: この行は、このファイルが指定されたOSでのみビルドされることを示します。setenvEinvalTests
変数: これは、無効なキーと値の組み合わせを定義した構造体のスライスです。各要素は、テスト対象のキー(k
)と値(v
)を含みます。{"", ""}
: 空のキーをテストします。{"k=v", ""}
: キーに=
が含まれるケースをテストします。{"\x00", ""}
: キーにNULL文字が含まれるケースをテストします。{"k", "\x00"}
: 値にNULL文字が含まれるケースをテストします。
TestSetenvUnixEinval
関数: このテスト関数は、setenvEinvalTests
の各要素をループで処理します。err := Setenv(tt.k, tt.v)
: 定義された無効なキーと値でSetenv
を呼び出します。if err == nil
:Setenv
がエラーを返さなかった場合、それは予期せぬ動作であるため、t.Errorf
を使ってテストを失敗させます。これにより、Setenv
が無効な入力に対して正しくEINVAL
エラーを返すことを保証します。
src/pkg/syscall/env_unix.go
このファイルは、Go言語のsyscall
パッケージの一部として、Unix系システムにおける環境変数操作の低レベルな実装を含んでいます。
func Setenv(key, value string) error
: この関数は、指定されたkey
とvalue
で環境変数を設定します。if len(key) == 0 { return EINVAL }
: 既存のチェックで、キーが空文字列の場合はEINVAL
を返します。- 追加されたキーのバリデーション:
このループは、for i := 0; i < len(key); i++ { if key[i] == '=' || key[i] == 0 { return EINVAL } }
key
文字列をバイト単位で走査します。key[i]
は、文字列のi
番目のバイト(文字)を表します。key[i] == '='
: 現在の文字がイコール記号であるかをチェックします。key[i] == 0
: 現在の文字がNULL文字(\x00
)であるかをチェックします。 どちらかの条件が真であれば、EINVAL
エラーを即座に返して関数を終了します。
- 追加された値のバリデーション:
このループは、for i := 0; i < len(value); i++ { if value[i] == 0 { return EINVAL } }
value
文字列をバイト単位で走査します。value[i] == 0
: 現在の文字がNULL文字(\x00
)であるかをチェックします。 NULL文字が検出された場合、EINVAL
エラーを即座に返して関数を終了します。
これらの追加されたチェックにより、Setenv
関数は、無効な文字を含む環境変数名や値がシステムに渡されることを防ぎ、より堅牢な環境変数操作を提供します。
関連リンク
- Go CL (Code Review) リンク: https://golang.org/cl/7311061
参考にした情報源リンク
- POSIX Environment Variables: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html (特に "Environment Variable Names" セクション)
- C言語におけるNULL終端文字列: https://en.wikipedia.org/wiki/Null-terminated_string
- Go言語の
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語の
syscall
パッケージドキュメント: https://pkg.go.dev/syscall