[インデックス 12547] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto/x509
パッケージにおけるWindows環境での証明書コンテキストの解放に関するバグ修正です。具体的には、createStoreContext
関数内で syscall.CertFreeCertificateContext(ctx)
の呼び出しが、その前の syscall.CertAddCertificateContextToStore
のエラーチェックの後に配置されていたため、エラーが発生した場合に ctx
が解放されない可能性があった問題を修正しています。
コミット
commit 9fffe45c6551a495f00d5593e941f7f1b1b7e784
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Sat Mar 10 09:35:56 2012 +1100
crypto/x509: do not forget to free cert context
R=golang-dev, krautz, rsc
CC=golang-dev
https://golang.org/cl/5783059
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9fffe45c6551a495f00d559e941f7f1b1b7e784
元コミット内容
crypto/x509: do not forget to free cert context
このコミットメッセージは、証明書コンテキストの解放を忘れないようにするという簡潔な内容です。これは、リソースリークの修正を示唆しています。
変更の背景
この変更の背景には、Windows APIを介して証明書ストアを操作する際に、リソースリークが発生する可能性があったという問題があります。createStoreContext
関数は、証明書をWindowsの証明書ストアに追加する役割を担っています。この関数内で、syscall.CertAddCertificateContextToStore
の呼び出しが成功したかどうかにかかわらず、取得した証明書コンテキスト (ctx
) を適切に解放する必要がありました。
しかし、元のコードでは syscall.CertAddCertificateContextToStore
の呼び出しの直後にエラーチェックがあり、もしこの関数がエラーを返した場合、その後の syscall.CertFreeCertificateContext(ctx)
の呼び出しがスキップされていました。これにより、ctx
が解放されずにメモリリークやリソースリークが発生する可能性がありました。
このコミットは、このようなリソースリークを防ぐために、syscall.CertFreeCertificateContext(ctx)
の呼び出しを、syscall.CertAddCertificateContextToStore
のエラーチェックよりも前に移動させることで、ctx
が常に解放されるように修正しています。
前提知識の解説
Go言語の crypto/x509
パッケージ
crypto/x509
パッケージは、Go言語でX.509証明書とPKIX (Public Key Infrastructure X.509) を扱うための機能を提供します。これには、証明書のパース、検証、署名、および証明書チェーンの構築などが含まれます。TLS/SSL通信やコード署名など、セキュリティが要求される多くの場面で利用されます。
Go言語の syscall
パッケージ
syscall
パッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、OS固有の機能(ファイルシステム操作、ネットワーク通信、プロセス管理など)にアクセスできます。Windows環境では、Win32 APIを呼び出すためにこのパッケージが使用されます。
Windowsの証明書ストアと CertContext
Windowsオペレーティングシステムは、証明書を管理するための「証明書ストア」という仕組みを持っています。これは、ユーザーやコンピュータの信頼されたルート証明書、個人証明書、中間証明書などを保存する場所です。
CertContext
(Certificate Context) は、Windows APIにおいて証明書を表すデータ構造です。これは、証明書データ自体だけでなく、そのプロパティや拡張情報へのポインタを含みます。Windows APIを介して証明書を操作する際には、この CertContext
オブジェクトを介して行われます。
CertAddCertificateContextToStore
関数
CertAddCertificateContextToStore
は、指定された証明書コンテキストを証明書ストアに追加するWindows API関数です。この関数は、証明書ストアへの参照と、追加する証明書コンテキスト、および追加方法を指定するフラグ(例: CERT_STORE_ADD_ALWAYS
)を引数に取ります。
CertFreeCertificateContext
関数
CertFreeCertificateContext
は、CertContext
オブジェクトが占有していたメモリやリソースを解放するためのWindows API関数です。Windows APIでは、多くの関数がリソース(メモリハンドル、ファイルハンドルなど)を割り当て、それらを使い終わったら明示的に解放する必要があります。これを怠ると、リソースリークが発生し、システムのパフォーマンス低下や不安定化につながる可能性があります。
技術的詳細
このコミットは、src/pkg/crypto/x509/root_windows.go
ファイル内の createStoreContext
関数におけるリソース管理のロジックを修正しています。
元のコードでは、以下の順序で処理が行われていました。
syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
を呼び出し、証明書をストアに追加。- 上記関数の戻り値
err
をチェック。err != nil
の場合、エラーを返して関数を終了。err == nil
の場合、処理を続行。
syscall.CertFreeCertificateContext(ctx)
を呼び出し、ctx
を解放。- 上記関数の戻り値
err
をチェック。err != nil
の場合、エラーを返して関数を終了。
このロジックの問題点は、ステップ2で syscall.CertAddCertificateContextToStore
がエラーを返した場合、ステップ3の syscall.CertFreeCertificateContext(ctx)
が実行されないことです。ctx
は CertAddCertificateContextToStore
に渡される前に既に有効なコンテキストとして存在しているため、エラーが発生した場合でも、そのコンテキストが占有していたリソースは解放されるべきです。
修正後のコードでは、syscall.CertFreeCertificateContext(ctx)
の呼び出しが syscall.CertAddCertificateContextToStore
のエラーチェックよりも前に移動されました。これにより、CertAddCertificateContextToStore
が成功したか失敗したかにかかわらず、ctx
は常に解放されることが保証されます。
// 修正前
err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
if err != nil {
return nil, err
}
err = syscall.CertFreeCertificateContext(ctx) // ここでエラーが発生すると、ctxが解放されない
if err != nil {
return nil, err
}
// 修正後
err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
syscall.CertFreeCertificateContext(ctx) // エラーチェックの前に移動
if err != nil { // CertAddCertificateContextToStoreのエラーのみをチェック
return nil, err
}
// CertFreeCertificateContextのエラーは無視されるか、別途処理されるべきだが、
// この修正ではCertAddCertificateContextToStoreのエラーパスのみを考慮している
この変更により、createStoreContext
関数がどのような状況で終了しても、ctx
に関連付けられたリソースが適切にクリーンアップされるようになり、リソースリークが防止されます。
コアとなるコードの変更箇所
--- a/src/pkg/crypto/x509/root_windows.go
+++ b/src/pkg/crypto/x509/root_windows.go
@@ -45,11 +45,7 @@ func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertCo
}
err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
- if err != nil {
- return nil, err
- }
-
- err = syscall.CertFreeCertificateContext(ctx)
+ syscall.CertFreeCertificateContext(ctx)
if err != nil {
return nil, err
}
コアとなるコードの解説
変更は src/pkg/crypto/x509/root_windows.go
ファイルの createStoreContext
関数内で行われています。
元のコードでは、以下の5行が削除されています。
if err != nil {
return nil, err
}
err = syscall.CertFreeCertificateContext(ctx)
そして、以下の1行が追加されています。
syscall.CertFreeCertificateContext(ctx)
これにより、syscall.CertAddCertificateContextToStore
の呼び出しの直後に syscall.CertFreeCertificateContext(ctx)
が無条件に呼び出されるようになりました。
元のコードでは、syscall.CertAddCertificateContextToStore
がエラーを返した場合、そのエラーをチェックして関数を早期に終了していました。このとき、ctx
は解放されませんでした。その後、syscall.CertFreeCertificateContext(ctx)
の呼び出しがありましたが、これは CertAddCertificateContextToStore
が成功した場合にのみ実行されるパスでした。
修正後は、syscall.CertAddCertificateContextToStore
の呼び出しが完了した直後に、その結果が成功か失敗かにかかわらず、syscall.CertFreeCertificateContext(ctx)
が呼び出されます。これにより、ctx
が指すリソースは常に解放されることが保証されます。その後の if err != nil
は、syscall.CertAddCertificateContextToStore
から返されたエラーをチェックするためのものであり、CertFreeCertificateContext
のエラーはここでは捕捉されなくなっています。これは、リソース解放のエラーよりも、証明書追加のエラーの方が上位の関心事であるという判断に基づいている可能性があります。
関連リンク
- Go言語の
crypto/x509
パッケージのドキュメント: https://pkg.go.dev/crypto/x509 - Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - Microsoft Learn:
CertAddCertificateContextToStore
関数: https://learn.microsoft.com/ja-jp/windows/win32/api/wincrypt/nf-wincrypt-certaddcertificatecontexttostore - Microsoft Learn:
CertFreeCertificateContext
関数: https://learn.microsoft.com/ja-jp/windows/win32/api/wincrypt/nf-wincrypt-certfreecertificatecontext
参考にした情報源リンク
- Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Go言語のコードレビューシステム (Gerrit): https://go.dev/cl/5783059 (コミットメッセージに記載されているCLリンク)
- 一般的なリソースリークに関する情報 (プログラミングのベストプラクティス)
- Windows APIのメモリ管理に関する情報