Linuxカーネルにおいて、以下の脆弱性が修正されました: can: gs_usb: タイムスタンプカウンタの初期化の修正です。gs_usbデバイスドライバがインターフェースの停止前にアンロード(またはバインド解除)されると、USBスタックは最初にstruct usb_driver::disconnectを呼び出し、その後struct net_device_ops::ndo_stopコールバックを呼び出します。gs_usb_disconnect()では、すべての保留中のバルクURBが終了されます。つまり、USBデバイスからホストへ受信されたCANフレームは送信されなくなります。その後、gs_can_close()によって各CANチャネルにリセット制御メッセージが送信され、コントローラがCANバスから除去されます。この競合状態の間に、USBデバイスは依然としてCANフレームをバスから受信して内部的にキューイングし、ホストへ送信しようとします。現行のcandlelightファームウェアの少なくとも現バージョンでは、リセットコマンド中に受信したCANフレームのキューは空になりません。gs_usbドライバのロード(またはバインド)後に、struct net_device_ops::ndo_openコールバックで新しいURBが送信され、candlelightファームウェアは既にキューにあるCANフレームの送信をホストへ開始します。しかし、このシナリオはハードウェアタイムスタンプ機能の実装時には考慮されていませんでした。サイクルカウンタおよびタイムカウンタのインフラはUSBのURB送信後(gs_usb_timestamp_init())にセットアップされるため、timecounter_cyc2time()(呼び出し経路: gs_usb_receive_bulk_callback() - gs_usb_set_timestamp() - gs_usb_skb_set_timestamp())が早すぎるタイミングで呼ばれるとNULLポインターデリファレンスが発生します。この問題を修正するために、gs_usb_timestamp_init()をURB送信前に移動しました。包括的な解決策として、複数チャネルを持つgs_usbデバイスを考慮する必要があります。サイクルカウンタおよびタイムカウンタのインフラはチャネル単位でセットアップされますが、RX URBはデバイス単位です。一つのチャネルのgs_can_open()が呼ばれてURBが送信されると、gs_usb_receive_bulk_callback()は全チャネル(まだ動作していないチャネルも含む)で呼ばれる可能性があります。サイクルカウンタおよびタイムカウンタがセットアップされていないため、再びNULLポインターデリファレンスが発生します。サイクルカウンタおよびタイムカウンタの機能を「チャネル単位」から「デバイス単位」に変更し、URB送信前にセットアップします。さらにgs_usb_receive_bulk_callback()内では、開始されていないCANチャネルのURBは処理せず、単にURBを再送信するだけに変更しました。
|