
MSP430ファームウェア向けのエミュレーションベースのファザーで、メモリ破壊バグを発見・分析し、詳細なクラッシュレポートと再現可能な入力を生成します。
Icicle によって MSP430 バイナリ内で発見されたクラッシュ。
| # | ターゲット | 説明 |
|---|---|---|
| I03 | Goodwatch | dmesg_buffer への書き込み時の誤った比較 |
| I04 | Goodwatch | メッセージ長ゼロ |
| I05 | Goodwatch | RNGオーバーフロー |
| I06 | Goodwatch | OOKキープレスにおける範囲外アクセス |
| I07 | Goodwatch | ストップウォッチにおける範囲外アクセス |
| I08 | Goodwatch | 曜日表示時の範囲外アクセス |
| I09 | Goodwatch | Hexビューアアプリケーション |
| I10 | Goodwatch | PEEK/POKEモニタコマンド |
| I11 | H4_PacketProtocol | Get Descriptor における未チェックのインターフェースインデックス |
| I12 | H4_PacketProtocol | Set Report におけるバッファオーバーフロー |
dmesg buffer への書き込み時の誤った比較putchar のオフバイワンエラーにより、0x2c00 への単一バイトのOOB書き込みが発生します。クラッシュ時のコールスタック例:
UnhandledException(code=WriteUnmapped, value=0x2c00):
0x000000c81a: putchar+0x1c
0x000000c832: dmesg_putc+0x6
0x0000009706: tfp_format+0x22
0x000000ad9c: tfp_printf+0x12
0x000000b924: key_scan.part.0+0x68
0x000000cd3c: PORT2_ISR+0x1a
0x0000008e04: <unknown>
長さフィールドがゼロに設定されたメッセージがUARTインターフェースに送信された場合、正しく処理されません。MSG 状態では、受信したばかりのバイトを uart_buffer の現在の index に格納した後、index をインクリメントし、それが length と等しいかどうかをチェックします。しかし、ゼロ長メッセージの場合、index の格納とインクリメントが length との比較よりも先に行われるため、index == length 条件が真になることはありません。
最終的に index が uart_buffer 配列を超えるため、uart_buffer の後に格納されているグローバル変数が変更される可能性があります。通常、stdout_putf または stdout_putp 関数ポインタが上書きされ、デバッグメッセージが出力されると、プログラムはクラッシュします。
クラッシュを引き起こす入力:
./run_goodwatch.sh I04a
クラッシュ時のコールスタック:
UnhandledException(code=InvalidInstruction)
0x000000d3d3: <unknown>
0x0000009648: putchw+0x40
0x0000009826: tfp_format+0x142
0x000000ad9c: tfp_printf+0x12
0x000000b924: key_scan.part.0+0x68
0x000000cd3c: PORT2_ISR+0x1a
0x0000008e04: <unknown>
appindex(または subindex) が上書きされ、次の applet が appindex を使用してロードされたときにクラッシュするものがあります (例: app_draw 内)。クラッシュ時のコールスタック:
UnhandledException(code=InvalidInstruction)
0x000000531c: <unknown>
0x0000009a96: app_init+0xe
0x000000c0a8: settime_draw+0x28
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
RANDINT モニタコマンドにより、ファームウェアは乱数のリストを生成して送信します。ただし、生成する乱数の個数は受信したコマンドによって制御されます。生成する値の数が多すぎると、rints がスタック用に確保された領域を超え、OOB書き込みが発生します。クラッシュを引き起こす入力:
./run_goodwatch.sh I05
クラッシュ時のコールスタック:
UnhandledException(code=WriteUnmapped, value=0x6e6a)
0x000000cbd4: USCI_A0_ISR+0x24c (inlined `send_randint`)
0x0000008e04: <unknown>
ook keypress における範囲外アクセス:OOKアプリケーションは、数字キー (0-9) のいずれかが押されたときに、button_array から事前設定されたOOKパケットを送信します。しかし、ook_keypress は押されたキーが button_array 配列の範囲内にあることを検証しません。数字ボタンは10個 (0-9) ありますが、button_array は9エントリしか含んでいません。
button_array はポインタの配列を含んでいます。OOKアプリケーションで 9 ボタンが押されると、setrate 関数が button_array の範囲外のポインタを読み取り、それをデリファレンスしてプログラムをクラッシュさせます。
読み取られるポインタは ook_settings (0x3012) の最初の値であり、これはメモリ内に存在しません。
クラッシュを引き起こす入力:
./run_goodwatch.sh I06
クラッシュ時のコールスタック:
UnhandledException(code=ReadUnmapped, value=0x3012)
0x000000b87a: ook_keypress+0x2c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
ファームウェアは、整数を2進化10進数 (BCD) に変換する際にルックアップテーブルを使用します。ただし、ルックアップテーブル (bcdtable) には整数0から59までを変換する値しか含まれていません。秒と分の変換では、これらの値はカウント時に60でロールオーバーするため問題ありませんが、hour 変数は60を超える可能性があり、インデックス範囲外が発生します。
このバグは、ゼロメッセージ長バグによって引き起こされる破損の副次効果として、ファザーによってのみ発見されました。ファザーが発見したクラッシュでは、uart_buffer がオーバーフローすると、min と hour の両方のグローバル変数が破損します。
クラッシュを引き起こす入力:
./run_goodwatch.sh I07
クラッシュ時のコールスタック:
UnhandledException(code=ReadUnmapped, value=0x4b57)
0x000000a3e4: stopwatch_draw+0x9e
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
RTCDOW ペリフェラルに対してファザーが大きな値を生成することによって引き起こされる誤検出バグ。
時計アプリケーションでボタン 9 を押すと、現在の曜日をLCDに描画しようとします。曜日はRTCペリフェラルのRTCDOWレジスタから直接読み取られます。このレジスタのデータシートでは戻り値は0〜6と指定されていますが、ファジング中はこのレジスタの値に制約がありません。この値は dayofweek 配列へのインデックスとして使用されるため、ファザーが RTCDOW レジスタに6より大きい値を生成すると、プログラムは daysofweek 配列の外側のポインタを読み取り、(誤検出の) クラッシュが発生します。
このクラッシュは、clock_keypress と hebrew_keypress の両方の一部として発生する可能性があります。
クラッシュを引き起こす入力:
./run_goodwatch.sh I08a
クラッシュ時のコールスタック:
UnhandledException(code=ReadUnmapped, value=0x5150)
0x0000009e6e: lcd_string+0x8
0x000000c1dc: clock_keypress+0x6c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
クラッシュを引き起こす入力:
./run_goodwatch.sh I08b
クラッシュ時のコールスタック:
UnhandledException(code=ReadPerm, value=0x1006)
0x0000009e6e: lcd_string+0x8
0x000000b2aa: hebrew_keypress+0x116
0x000000c48c: clock_keypress+0x31c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
クラッシュを引き起こす入力:
./run_goodwatch.sh I09
クラッシュ時のコールスタック:
UnhandledException(code=ReadUnmapped, value=0x7000)
0x0000009c74: hex_draw.part.0+0x3c
0x0000009c88: hex_draw+0x8
0x0000009b0a: app_draw+0x3e
0x000000cd8c: PORT2_ISR+0x6a
0x0000008e04: <unknown>
PEEK のクラッシュ入力:
./run_goodwatch.sh I10a
クラッシュ時のコールスタック:
UnhandledException(code=ReadUnmapped, value=0x5100)
0x000000cb00: USCI_A0_ISR+0x178
0x0000008e04: <unknown>
POKE のクラッシュ入力:
./run_goodwatch.sh I10b
クラッシュ時のコールスタック:
UnhandledException(code=WritePerm, value=0x4b00)
0x000000cb32: USCI_A0_ISR+0x1aa
0x0000008e04: <unknown>
Get_Descriptor ハンドラのいくつかでは、インターフェースインデックスがチェックされていません。これにより範囲外アクセスが発生する可能性があります。例:GetHidDescriptor:
./run_H4_PacketProtocol.sh I11a
クラッシュ時のコールスタック:
UnhandledException(code=ReadUninitialized, value=0xe90e)
0x0000011176: usbSendNextPacketOnIEP0 at ./USB_API/USB_Common/usb.c:1082.13
0x0000011c12: usbGetHidDescriptor at ./USB_API/USB_HID_API/UsbHidReq.c:78.5
0x0000010fb0: usbDecodeAndProcessUsbRequest at ./USB_API/USB_Common/usb.c:1655.5
0x0000011724: SetupPacketInterruptHandler at ./USB_config/UsbIsr.c:250.5
0x0000004410: iUsbInterruptHandler at ./USB_config/UsbIsr.c:88.9
0x0000004572: _c_int00_noargs
GetReportDescriptor:
./run_H4_PacketProtocol.sh I11b
クラッシュ時のコールスタック:
UnhandledException(code=ReadUninitialized, value=0xa44c)
0x0000011c28: usbGetReportDescriptor at ./USB_API/USB_HID_API/UsbHidReq.c:85.5
0x0000010fb0: usbDecodeAndProcessUsbRequest at ./USB_API/USB_Common/usb.c:1655.5
0x0000011724: SetupPacketInterruptHandler at ./USB_config/UsbIsr.c:250.5
0x00000044fe: iUsbInterruptHandler at ./USB_config/UsbIsr.c:166.9
0x0000004572: _c_int00_noargs
Set_Report パケットを受信すると、ファームウェアはレポートを格納するバッファを pbOEP0Buffer に割り当て、レポートの長さを wBytesRemainingOnOEP0 に設定します。しかし、ファームウェアはレポートが割り当てられたバッファに収まるかどうかをチェックしないため、後に usbReceiveNextPacketOnOEP0 でバッファに書き込む際にバッファオーバーフローが発生します。以下のクラッシュ入力では、8バイト配列 (0x24a4: abUsbRequestIncomingData) のアドレスが pbOEP0Buffer に割り当てられます。配列をオーバーフローさせた後、関数ポインタ (0x24b4: USB_RX_memcpy) が破損し、後でその関数ポインタが呼び出されたときにクラッシュが発生します。
./run_H4_PacketProtocol.sh I12
クラッシュ時のコールスタック:
UnhandledException(code=InvalidInstruction, value=0xf95b7)
0x00000f95b7: <unknown>
0x0000011066: HidCopyUsbToBuff at ./USB_API/USB_HID_API/UsbHid.c:417.5
0x0000010172: USBHID_receiveData at ./USB_API/USB_HID_API/UsbHid.c:577.13
0x000001026a: main at ./main.c:115.25
0x0000004572: _c_int00_noargs