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

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

コミット

commit 67a0c4f7f9c4bb2c76b738ca41171785cb16c35c
Author: Joel Sing <jsing@google.com>
Date:   Mon May 21 00:13:22 2012 +1000

    syscall: fix SockaddrDatalink on netbsd
    
    RawSockaddrDatalink and SockaddrDatalink need to match - make Data
    have length 12 for both.
    
    R=golang-dev, mikioh.mikioh
    CC=golang-dev
    https://golang.org/cl/6223051

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

https://github.com/golang/go/commit/67a0c4f7f9c4bb2c76b738ca41171785cb16c35c

元コミット内容

syscall: fix SockaddrDatalink on netbsd

RawSockaddrDatalinkSockaddrDatalink は一致する必要があるため、Data フィールドの長さを両方とも12にする。

変更の背景

このコミットは、Go言語の syscall パッケージにおけるNetBSD固有の実装に関するバグ修正です。具体的には、SockaddrDatalink 構造体と RawSockaddrDatalink 構造体の Data フィールドの長さが一致していないという問題がありました。

Go言語の syscall パッケージは、オペレーティングシステムのシステムコールをGoプログラムから呼び出すための低レベルなインターフェースを提供します。ネットワーク関連の操作、特にデータリンク層(レイヤ2)の情報を扱う際には、OSが提供する sockaddr_dl のような構造体とGoの構造体を正確にマッピングする必要があります。

NetBSDシステムにおいて、SockaddrDatalink はGo言語でデータリンク層のアドレスを表現するための構造体であり、RawSockaddrDatalink はその基盤となるC言語の sockaddr_dl 構造体に対応するGoの表現です。これら二つの構造体は、OSとのやり取りにおいて整合性が保たれている必要があります。

しかし、このコミット以前は、SockaddrDatalinkData フィールドが [24]int8 の長さを持っていたのに対し、対応する RawSockaddrDatalinkData フィールドは [12]int8 の長さを持っていました。この不一致が原因で、システムコールを介してデータリンク層のアドレス情報を取得または設定する際に、データの切り捨てや不正なメモリアクセスが発生する可能性がありました。このコミットは、この不整合を解消し、両者の Data フィールドの長さを 12 に統一することで、NetBSD上での syscall パッケージの安定性と正確性を向上させることを目的としています。

前提知識の解説

  • Go言語の syscall パッケージ: Go言語の標準ライブラリの一部であり、オペレーティングシステムが提供するシステムコールへの低レベルなアクセスを提供します。これにより、ファイル操作、プロセス管理、ネットワーク通信など、OSカーネルと直接対話する機能を実現できます。OSごとに異なるシステムコールのインターフェースを抽象化し、Goプログラムから利用できるようにしています。

  • データリンク層 (Datalink Layer): OSI参照モデルの第2層に位置し、物理層の上位にあります。ネットワーク上の隣接するノード間でデータを転送するための機能を提供します。MACアドレスによるアドレッシング、フレームの送受信、エラー検出・訂正などが主な役割です。イーサネットやWi-Fiなどがこの層の代表的なプロトコルです。

  • ソケットアドレス (Socket Address): ネットワーク通信において、通信のエンドポイントを識別するための情報です。通常、IPアドレスとポート番号の組み合わせで構成されますが、データリンク層においてはMACアドレスやインターフェースインデックスなどが含まれることがあります。

  • sockaddr_dl 構造体 (NetBSD): NetBSDオペレーティングシステムにおいて、データリンク層のソケットアドレスを表現するためにカーネルが使用するC言語の構造体です。この構造体には、アドレスの長さ、アドレスファミリー(AF_LINK)、インターフェースインデックス、MACアドレスなどのデータリンク層固有の情報が含まれます。Go言語の syscall パッケージは、このOS固有の構造体をGoの型にマッピングして利用します。

  • SockaddrDatalinkRawSockaddrDatalink (Go言語): Go言語の syscall パッケージ内で定義されている、NetBSDの sockaddr_dl 構造体に対応するGoの型です。

    • RawSockaddrDatalink: NetBSDカーネルの sockaddr_dl 構造体に直接対応する、より低レベルなGoの構造体です。バイト列としてOSとやり取りされる生データを表現します。
    • SockaddrDatalink: RawSockaddrDatalink をラップし、Goの慣習に沿った形でデータリンク層のアドレス情報にアクセスできるようにする高レベルな構造体です。通常、Len (アドレス全体の長さ), Family (アドレスファミリー), Index (インターフェースインデックス), Type (インターフェースタイプ), Nlen (ネットワークアドレス長), Alen (アドレス長), Slen (セレクタ長), そして実際のデータを含む Data フィールドなどを含みます。また、内部に RawSockaddrDatalink のインスタンスを保持しています。

技術的詳細

このコミットの技術的な核心は、Go言語の syscall パッケージがNetBSDのデータリンク層ソケットアドレスを扱う際に、Goの構造体とOSのネイティブ構造体との間で Data フィールドのサイズが不一致であった点にあります。

NetBSDの sockaddr_dl 構造体は、データリンク層のアドレス情報を格納するための可変長な Data フィールドを持っています。Go言語の syscall パッケージでは、この sockaddr_dl に対応する RawSockaddrDatalink と、それをよりGoらしい形で扱う SockaddrDatalink の2つの構造体を定義しています。

問題は、SockaddrDatalinkData フィールドが [24]int8 として定義されていたのに対し、RawSockaddrDatalinkData フィールド(またはその基盤となるCの sockaddr_dl の関連部分)が実質的に 12 バイトの長さを想定していたことです。この 24 バイトと 12 バイトの不一致は、以下のような問題を引き起こす可能性があります。

  1. データの切り捨て/オーバーフロー: OSから sockaddr_dl 構造体を受け取る際、Goの SockaddrDatalink 構造体の Data フィールドが 24 バイトであると、OSが 12 バイトのデータを書き込もうとしたときに、Go側で期待されるサイズと実際のサイズが合致しません。これにより、データが正しく読み取れない、あるいは余分なメモリ領域にゴミデータが残る可能性があります。逆に、Go側からOSにデータを渡す場合も、24 バイトの Data フィールドから 12 バイトしかOSが読み取らない場合、意図しないデータが渡されたり、重要な情報が欠落したりする可能性があります。

  2. メモリレイアウトの不整合: Goの構造体とCの構造体(またはGoの RawSockaddrDatalink)の間で、フィールドのオフセットやサイズが一致しないと、システムコールを介したデータのマーシャリング(Goのデータ構造をOSが理解できる形式に変換すること)やアンマーシャリング(その逆)が正しく行われません。これは、Goの unsafe パッケージや reflect パッケージを使って構造体のメモリレイアウトを操作する際に特に重要になります。

このコミットは、SockaddrDatalinkData フィールドの長さを [12]int8 に修正することで、RawSockaddrDatalink との整合性を確保し、上記の問題を解決します。これにより、NetBSD上でのデータリンク層ソケットアドレスの処理が正確かつ安定して行われるようになります。この修正は、Goの syscall パッケージがOS固有の低レベルなインターフェースを正確に反映することの重要性を示しています。

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

--- a/src/pkg/syscall/syscall_netbsd.go
+++ b/src/pkg/syscall/syscall_netbsd.go
@@ -22,7 +22,7 @@ type SockaddrDatalink struct {
 	Nlen   uint8
 	Alen   uint8
 	Slen   uint8
-	Data   [24]int8
+	Data   [12]int8
 	raw    RawSockaddrDatalink
 }
 

コアとなるコードの解説

変更は src/pkg/syscall/syscall_netbsd.go ファイル内の SockaddrDatalink 構造体に対して行われています。

具体的には、SockaddrDatalink 構造体の Data フィールドの型定義が以下のように変更されました。

  • 変更前: Data [24]int8
  • 変更後: Data [12]int8

この変更は、SockaddrDatalink 構造体内の Data フィールドが保持するバイト配列のサイズを 24 バイトから 12 バイトに縮小することを意味します。

この修正の目的は、コミットメッセージにもある通り、「RawSockaddrDatalinkSockaddrDatalink が一致する必要がある」という点にあります。NetBSDのデータリンク層ソケットアドレスのネイティブな表現(sockaddr_dl に対応する RawSockaddrDatalink)が Data フィールドに対して 12 バイトの長さを想定しているため、Go側の SockaddrDatalink もそれに合わせることで、GoプログラムとNetBSDカーネル間のデータ交換における整合性を確保しています。

これにより、データリンク層のアドレス情報が正しくマーシャリングおよびアンマーシャリングされ、データの切り捨てやメモリレイアウトの不一致による潜在的なバグが解消されます。これは、Goの syscall パッケージがOSの低レベルなインターフェースを正確に反映し、クロスプラットフォームでの互換性を保ちつつ、各OSの特性に合わせた適切な実装を行うことの重要性を示す典型的な例です。

関連リンク

参考にした情報源リンク