Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15321] ファイルの概要

このコミットは、Go言語の標準ライブラリであるsyscallパッケージ内のsecurity_windows.goファイルに対する変更です。具体的には、Windowsのセキュリティ識別子(SID)のタイプを定義する定数群において、SidTypeUserの初期化方法を修正しています。

コミット

commit e378aef1def490cec4b86e2d341a287b5286d01f
Author: Brian Dellisanti <briandellisanti@gmail.com>
Date:   Wed Feb 20 15:38:35 2013 +1100

    windows: fix syscall.SidTypeUser so following consts have correct values.
    
    Fixes #4844.
    
    R=golang-dev, alex.brainman
    CC=golang-dev
    https://golang.org/cl/7366043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/e378aef1def490cec4b86e2d341a287b5286d01f

元コミット内容

    windows: fix syscall.SidTypeUser so following consts have correct values.
    
    Fixes #4844.

変更の背景

このコミットは、Go言語のsyscallパッケージにおけるWindows固有の定数定義に関するバグ(Issue #4844)を修正するために行われました。元のコードでは、iotaというGoの特殊な定数ジェネレータをビットシフト演算子(<<)と組み合わせて使用していましたが、これが意図しない値を生み出し、後続の定数にも誤った値が割り当てられる原因となっていました。

Windowsのセキュリティ識別子(SID)タイプは、特定の整数値を持つことが期待されます。しかし、SidTypeUser = 1 << iotaという定義では、iotaが0から始まるため、SidTypeUser1 << 01となりますが、その後のSidTypeGroupなどは1 << 12SidTypeDomain1 << 24となり、期待される連続した整数値とは異なる値が割り当てられていました。

この問題は、Windows APIが期待するSIDタイプの値とGoの定数定義が一致しないために、syscallパッケージを利用するアプリケーションが正しく動作しない可能性を示唆していました。

前提知識の解説

Go言語のiota

iotaはGo言語における特殊な定数ジェネレータです。constブロック内で使用され、連続する定数に自動的にインクリメントされる整数値を割り当てます。

  • constブロックの最初のiota0に初期化されます。
  • 同じconstブロック内で、新しいconst宣言が現れるたびにiotaの値は1ずつ増加します。
  • iotaは、明示的に値を指定しない定数に自動的に適用されます。

例1: 基本的なiota

const (
    A = iota // A = 0
    B        // B = 1 (iotaは自動的にインクリメントされる)
    C        // C = 2
)

例2: iotaと演算子

iotaは他の演算子と組み合わせて使用することもできます。

const (
    KB = 1 << (10 * iota) // KB = 1 << 0 = 1
    MB                    // MB = 1 << 10 = 1024
    GB                    // GB = 1 << 20 = 1048576
)

この例では、iotaが0, 1, 2とインクリメントされるにつれて、1 << (10 * iota)1 << 01 << 101 << 20と計算され、それぞれ1、1024、1048576という値になります。

Windowsのセキュリティ識別子(SID)とSIDタイプ

Windowsオペレーティングシステムでは、ユーザーアカウント、グループ、コンピュータ、ドメインなどのセキュリティプリンシパルを一意に識別するためにセキュリティ識別子(SID: Security Identifier)を使用します。SIDは、S-1-5-21-3623811015-3361044348-30300820-1013のような形式の可変長構造です。

SIDには様々なタイプがあり、それぞれが特定の種類のセキュリティプリンシパルを表します。これらのタイプは、Windows APIによって定義された特定の整数値で識別されます。例えば、SidTypeUserはユーザーアカウントを表し、SidTypeGroupはグループを表します。これらのタイプは、セキュリティ関連の操作(例: アクセス制御リストの操作、ユーザー情報の取得)において、SIDの性質を判断するために使用されます。

技術的詳細

このコミットの核心は、Goのiotaと定数定義の組み合わせが、Windows APIが期待する連続した整数値のSIDタイプとどのように衝突したかを理解することです。

元のコードでは、以下のようになっていました。

const (
    // do not reorder
    SidTypeUser = 1 << iota
    SidTypeGroup
    SidTypeDomain
    SidTypeAlias
    // ...
)

この定義では、iotaconstブロックの最初の定数であるSidTypeUser0に初期化されます。

  • SidTypeUser1 << 0 となり、値は 1 です。
  • 次に、SidTypeGroupは明示的な値が指定されていないため、iotaがインクリメントされ、前の定数の式が繰り返されます。つまり、SidTypeGroup1 << 1 となり、値は 2 です。
  • 同様に、SidTypeDomain1 << 24SidTypeAlias1 << 38 となります。

このように、元のコードではSIDタイプが1, 2, 4, 8, ...という2のべき乗の値として定義されていました。しかし、Windows APIが期待するSIDタイプは、通常、1, 2, 3, 4, ...のような連続した整数値です。この不一致が、syscallパッケージがWindowsのセキュリティ機能と正しく連携できない原因となっていました。

修正後のコードは以下の通りです。

const (
    // do not reorder
    SidTypeUser = 1 + iota
    SidTypeGroup
    SidTypeDomain
    SidTypeAlias
    // ...
)

この変更により、SidTypeUserの定義が1 + iotaに変更されました。

  • SidTypeUser1 + 0 となり、値は 1 です。
  • 次に、SidTypeGroupは明示的な値が指定されていないため、iotaがインクリメントされ、前の定数の式が繰り返されます。つまり、SidTypeGroup1 + 1 となり、値は 2 です。
  • 同様に、SidTypeDomain1 + 23SidTypeAlias1 + 34 となります。

この修正により、SidTypeUser以降のSIDタイプ定数に1, 2, 3, 4, ...という連続した整数値が割り当てられるようになり、Windows APIの期待する値と一致するようになりました。これにより、syscallパッケージがWindowsのセキュリティ機能と正しく連携できるようになり、Issue #4844で報告されたバグが解消されました。

コアとなるコードの変更箇所

--- a/src/pkg/syscall/security_windows.go
+++ b/src/pkg/syscall/security_windows.go
@@ -70,7 +70,7 @@ type UserInfo10 struct {
 
  const (
  	// do not reorder
-	SidTypeUser = 1 << iota
+	SidTypeUser = 1 + iota
  	SidTypeGroup
  	SidTypeDomain
  	SidTypeAlias

コアとなるコードの解説

変更はsrc/pkg/syscall/security_windows.goファイルの73行目です。

  • 変更前: SidTypeUser = 1 << iota

    • iota0から始まるため、SidTypeUser1 << 01となります。
    • しかし、続くSidTypeGroup1 << 12SidTypeDomain1 << 24となり、2のべき乗の値が割り当てられていました。これはWindows APIが期待する連続した整数値のSIDタイプとは異なります。
  • 変更後: SidTypeUser = 1 + iota

    • iota0から始まるため、SidTypeUser1 + 01となります。
    • 続くSidTypeGroup1 + 12SidTypeDomain1 + 23となり、期待される連続した整数値が割り当てられるようになりました。

この小さな変更により、GoのsyscallパッケージがWindowsのセキュリティ識別子タイプを正しく解釈し、Windows APIとの互換性が確保されました。

関連リンク

参考にした情報源リンク

  • Go言語のiotaに関する公式ドキュメントやチュートリアル
  • Windows Security Identifiers (SIDs) のMicrosoft Learnドキュメント
  • Go言語のsyscallパッケージのドキュメント
  • Go言語のGitHubリポジトリにおけるIssue #4844の議論