At (tr)uSDX bootloader corruption – a smoking gun I proposed that the (tr)uSDX (trusdx) is vulnerable to users attempting to program the initial bootloader file using the (tr)uSDX USB port and its bootloader interface because without protection, that will attempt to overlay the bootloader while it is being executed and that is likely to corrupt the bootloader.
The (tr)uSDX bootloader code is proprietary, ie secret.
This article documents an experiment that demonstrates the vulnerability, and the effect of bootloader section protection.
Below are a series of verbose AVRDUDE logs of the operations to discover / demonstrate the outcomes.
Because this experiment is conducted on a 16MHz Nano and the bootloader uses a 20MHz clock, the bootloader port speed is adjusted to 92160. If this experiment was conducted on a real (tr)uSDX, use 115200.
Take note also of the clock rate issue raised at ISP programming of the (tr)uSDX.
Above, the test jig has a Nano with USB connection and ISP connection (Atmel AVRisp MkII).
Write the (tr)uSDX bootloader using an ISP programmer
Reading fuses... >>>: avrdude -c avrispmkII -p m328p -P usb -b 115200 -B 0.5 -vv -U hfuse:r:-:h -U lfuse:r:-:h -U efuse:r:-:h SUCCESS: Read high fuse SUCCESS: Read low fuse SUCCESS: Read extended fuse Reading lock bits... >>>: avrdude -c avrispmkII -p m328p -P usb -b 115200 -B 0.5 -vv -U lock:r:-:h SUCCESS: Read lock bits truSDX-initial_Bootloader.hex: 32,366 / 32,768 Bytes (98.77%) ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ >>>: avrdude -c avrispmkII -p m328p -P usb -b 115200 -B 0.5 -e -vv -U flash:w:"D:\project\trusdx\truSDX-initial_Bootloader.hex":i avrdude.exe: Version 7.0 Copyright (c) Brian Dean, http://www.bdmicro.com/ Copyright (c) Joerg Wunsch System wide configuration file is "D:/Program Files (x86)/AVRDUDESS/avrdude.conf" Using Port : usb Using Programmer : avrispmkII Overriding Baud Rate : 115200 Setting bit clk period : 0.5 avrdude.exe: usbdev_open(): Found AVRISP mkII, serno: 001D2C990079 Using p = 0.50 us for SCK (param = 2) avrdude.exe: Skipping parameter write; parameter value already set. AVR Part : ATmega328P Chip Erase delay : 9000 us PAGEL : PD7 BS2 : PC2 RESET disposition : dedicated RETRY pulse : SCK Serial program mode : yes Parallel program mode : yes Timeout : 200 StabDelay : 100 CmdexeDelay : 25 SyncLoops : 32 PollIndex : 3 PollValue : 0x53 Memory Detail : Block Poll Page Polled Memory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack ----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff lfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 hfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 efuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 lock 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 calibration 0 0 0 0 no 1 1 0 0 0 0x00 0x00 signature 0 0 0 0 no 3 1 0 0 0 0x00 0x00 Programmer Type : STK500V2 Description : Atmel AVR ISP mkII Programmer Model: AVRISP mkII Hardware Version: 1 Firmware Version Master : 1.24 Vtarget : 4.5 V SCK period : 0.50 us avrdude.exe: AVR device initialized and ready to accept instructions Reading | avrdude.exe: stk500isp_read_byte(.., signature, 0x0, ...) avrdude.exe: stk500isp_read_byte(): Sending read memory command: avrdude.exe: stk500isp_read_byte(.., signature, 0x1, ...) avrdude.exe: stk500isp_read_byte(): Sending read memory command: ################avrdude.exe: stk500isp_read_byte(.., signature, 0x2, ...) avrdude.exe: stk500isp_read_byte(): Sending read memory command: ################################## | 100% 0.00s avrdude.exe: Device signature = 0x1e950f (probably m328p) avrdude.exe: erasing chip avrdude.exe: reading input file "D:\project\trusdx\truSDX-initial_Bootloader.hex" avrdude.exe: writing flash (32768 bytes): Writing | ################################################## | 100% 1.97s avrdude.exe: 32768 bytes of flash written avrdude.exe: verifying flash memory against D:\project\trusdx\truSDX-initial_Bootloader.hex: avrdude.exe: load data flash data from input file D:\project\trusdx\truSDX-initial_Bootloader.hex: avrdude.exe: input file D:\project\trusdx\truSDX-initial_Bootloader.hex contains 32768 bytes avrdude.exe: reading on-chip flash data: Reading | ################################################## | 100% 1.28s avrdude.exe: verifying ... avrdude.exe: 32768 bytes of flash verified avrdude.exe done. Thank you.
All good.
Write application firmware using the USB connection and bootloader
Reading fuses... >>>: avrdude -c avrispmkII -p m328p -P usb -b 115200 -B 0.5 -vv -U hfuse:r:-:h -U lfuse:r:-:h -U efuse:r:-:h SUCCESS: Read high fuse SUCCESS: Read low fuse SUCCESS: Read extended fuse Reading lock bits... >>>: avrdude -c avrispmkII -p m328p -P usb -b 115200 -B 0.5 -vv -U lock:r:-:h SUCCESS: Read lock bits >>>: avrdude -c arduino -p m328p -P COM33 -b 92160 -B 0.5 -e -vv -U flash:w:"D:\project\trusdx\truSDX_*_Firmware.hex":i avrdude.exe: Version 7.0 Copyright (c) Brian Dean, http://www.bdmicro.com/ Copyright (c) Joerg Wunsch System wide configuration file is "D:/Program Files (x86)/AVRDUDESS/avrdude.conf" Using Port : COM33 Using Programmer : arduino Overriding Baud Rate : 92160 Setting bit clk period : 0.5 avrdude.exe: Found device at port 'COM33' avrdude.exe: serial_baud_lookup(): Using non-standard baud rate: 92160 AVR Part : ATmega328P Chip Erase delay : 9000 us PAGEL : PD7 BS2 : PC2 RESET disposition : dedicated RETRY pulse : SCK Serial program mode : yes Parallel program mode : yes Timeout : 200 StabDelay : 100 CmdexeDelay : 25 SyncLoops : 32 PollIndex : 3 PollValue : 0x53 Memory Detail : Block Poll Page Polled Memory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack ----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff lfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 hfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 efuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 lock 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 calibration 0 0 0 0 no 1 1 0 0 0 0x00 0x00 signature 0 0 0 0 no 3 1 0 0 0 0x00 0x00 Programmer Type : Arduino Description : Arduino Hardware Version: 3 Firmware Version: 7.0 avrdude.exe: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude.exe: Device signature = 0x1e950f (probably m328p) avrdude.exe: erasing chip avrdude.exe: reading input file "D:\project\trusdx\truSDX_*_Firmware.hex" avrdude.exe: writing flash (31828 bytes): Writing | ################################################## | 100% 6.80s avrdude.exe: 31828 bytes of flash written avrdude.exe: verifying flash memory against D:\project\trusdx\truSDX_*_Firmware.hex: avrdude.exe: load data flash data from input file D:\project\trusdx\truSDX_*_Firmware.hex: avrdude.exe: input file D:\project\trusdx\truSDX_*_Firmware.hex contains 31828 bytes avrdude.exe: reading on-chip flash data: Reading | ################################################## | 100% 4.72s avrdude.exe: verifying ... avrdude.exe: 31828 bytes of flash verified avrdude.exe done. Thank you.
All good.
Write the bootloader hex file using the USB connection and bootloader
>>>: avrdude -c arduino -p m328p -P COM33 -b 92160 -B 0.5 -e -vv -U flash:w:"D:\project\trusdx\truSDX-initial_Bootloader.hex":i avrdude.exe: Version 7.0 Copyright (c) Brian Dean, http://www.bdmicro.com/ Copyright (c) Joerg Wunsch System wide configuration file is "D:/Program Files (x86)/AVRDUDESS/avrdude.conf" Using Port : COM33 Using Programmer : arduino Overriding Baud Rate : 92160 Setting bit clk period : 0.5 avrdude.exe: Found device at port 'COM33' avrdude.exe: serial_baud_lookup(): Using non-standard baud rate: 92160 AVR Part : ATmega328P Chip Erase delay : 9000 us PAGEL : PD7 BS2 : PC2 RESET disposition : dedicated RETRY pulse : SCK Serial program mode : yes Parallel program mode : yes Timeout : 200 StabDelay : 100 CmdexeDelay : 25 SyncLoops : 32 PollIndex : 3 PollValue : 0x53 Memory Detail : Block Poll Page Polled Memory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack ----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff lfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 hfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 efuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 lock 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 calibration 0 0 0 0 no 1 1 0 0 0 0x00 0x00 signature 0 0 0 0 no 3 1 0 0 0 0x00 0x00 Programmer Type : Arduino Description : Arduino Hardware Version: 3 Firmware Version: 7.0 avrdude.exe: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude.exe: Device signature = 0x1e950f (probably m328p) avrdude.exe: erasing chip avrdude.exe: reading input file "D:\project\trusdx\truSDX-initial_Bootloader.hex" avrdude.exe: writing flash (32768 bytes): Writing | ################################################## | 100% 6.83s avrdude.exe: ser_recv(): programmer is not responding avrdude.exe: stk500_recv(): programmer is not responding avrdude.exe: ser_recv(): programmer is not responding avrdude.exe: stk500_recv(): programmer is not responding avrdude.exe: ser_recv(): programmer is not responding avrdude.exe: stk500_recv(): programmer is not responding avrdude.exe: ser_recv(): programmer is not responding avrdude.exe: stk500_recv(): programmer is not responding avrdude.exe: ser_recv(): programmer is not responding avrdude.exe: stk500_recv(): programmer is not responding avrdude.exe: ser_recv(): programmer is not responding avrdude.exe: stk500_recv(): programmer is not responding AVRDUDE killed
Fail: the bootloader which is executing has been corrupted by attempting to overwrite itself (probably most directly the associated flash page erase operation).
Write the bootloader hex file using the USB connection and bootloader with LOCK=0xCF
After reloading the bootloader using ISP…
>>>: avrdude -c arduino -p m328p -P COM33 -b 92160 -B 0.5 -e -vv -U flash:w:"D:\project\trusdx\truSDX-initial_Bootloader.hex":i avrdude.exe: Version 7.0 Copyright (c) Brian Dean, http://www.bdmicro.com/ Copyright (c) Joerg Wunsch System wide configuration file is "D:/Program Files (x86)/AVRDUDESS/avrdude.conf" Using Port : COM33 Using Programmer : arduino Overriding Baud Rate : 92160 Setting bit clk period : 0.5 avrdude.exe: Found device at port 'COM33' avrdude.exe: serial_baud_lookup(): Using non-standard baud rate: 92160 AVR Part : ATmega328P Chip Erase delay : 9000 us PAGEL : PD7 BS2 : PC2 RESET disposition : dedicated RETRY pulse : SCK Serial program mode : yes Parallel program mode : yes Timeout : 200 StabDelay : 100 CmdexeDelay : 25 SyncLoops : 32 PollIndex : 3 PollValue : 0x53 Memory Detail : Block Poll Page Polled Memory Type Alias Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack ----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff lfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 hfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 efuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 lock 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00 calibration 0 0 0 0 no 1 1 0 0 0 0x00 0x00 signature 0 0 0 0 no 3 1 0 0 0 0x00 0x00 Programmer Type : Arduino Description : Arduino Hardware Version: 3 Firmware Version: 7.0 avrdude.exe: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude.exe: Device signature = 0x1e950f (probably m328p) avrdude.exe: erasing chip avrdude.exe: reading input file "D:\project\trusdx\truSDX-initial_Bootloader.hex" avrdude.exe: writing flash (32768 bytes): Writing | ################################################## | 100% 6.82s avrdude.exe: 32768 bytes of flash written avrdude.exe: verifying flash memory against D:\project\trusdx\truSDX-initial_Bootloader.hex: avrdude.exe: load data flash data from input file D:\project\trusdx\truSDX-initial_Bootloader.hex: avrdude.exe: input file D:\project\trusdx\truSDX-initial_Bootloader.hex contains 32768 bytes avrdude.exe: reading on-chip flash data: Reading | ################################################## | 100% 4.74s avrdude.exe: verifying ... avrdude.exe: 32768 bytes of flash verified avrdude.exe done. Thank you.
All good. AVRDUDE completes without corrupting the memory image of the running bootloader, and the verify test shows the bootloader is still functional after the attempted overwrite.
Be be aware that the reason it appears to work is that the attempts to overwrite the bootloader section were silently ignored, and the file verified ok against the originally written part of the image. If you were actually trying to update the bootloader section to a new version, this would not have written the changes and the verify would fail.
Forensics
Above is a file comparison of a read of flash after the corruption with that before the corruption, and it can be seen that the flash page (0x80 bytes) at 0x7f00 (which is within the bootloader section) has been erased preparatory to writing the new data. The bootloader was probably executing instructions in this region when the rug was pulled from under it!
A further comparison was made of the boot section after loading and after loading the application firmware, and it appears that the application writes to the boot section starting at 0x7ff6. If that is true, one might say that the system is designed to be vulnerable.
Summary
The (tr)uSDX bootloader will happily attempt to overwrite itself, and that is likely to result in corruption of the bootloader.
If you don't attempt to load a file that writes to the bootloader section, no problem.
An easy thing for a novice, the confused or the fatigued to do is to attempt to write the intial bootloader file using the USB bootloader interface.
The bootloader can be restored ONLY using an ISP programmer (or the like).
The hardware contains protection features which are effective in preventing overwrite of the bootloader section… if they are enabled.
The (tr)uSDX may require an unprotected boot section for its operation… in other words, a designed in vulnerability.