-
Notifications
You must be signed in to change notification settings - Fork 151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Issue #918: Enable avrdude to send full input file incl trailing 0xff #936
Conversation
I'd prefer a separate option. |
We could use option |
Cool; thanks for supporting this change. Would a new option Using |
Well, after all, it's the most widespread deployment of that bug … and I cannot see any mnemonic for Yes, I still call it a bug. If someone is asked to "chip erase" (as this is the only available erase command in the chosen protocol), and they do – just nothing, I cannot call this anything but a bug. I see it as their responsibility to do the closest approximation of erasing the chip. The minimum for a bootloader is to erase the application flash area then (ideally, they'd also honor the EESAVE fuse, and depending on it, erase EEPROM). I don't think there's a big difference in program size between "upon 'chip erase', loop over all application flash pages, and erase them" vs. "upon 'chip erase', do nothing, but when programming a page, first erase it". In addition, a boot loader not acting on chip erase creates a huge security hole. Suppose you have a "secure application" inside, and taken care to set the lock fuses appropriately so nobdy can read it out. With that bootloader, one can come along, craft a minimal application that just covers the first flash page, and then toggles out the entire remaining flash contents through a GPIO pin. :-o This is probably not a big deal for opensource-like Arduino applications, but if anyone would have the idea to use that "well-proven bootloader" for their own purposes, it's getting hot. (That's also where the EEPROM erasing might get into the game. There's a reason Atmel has made erasing the EEPROM on "chip erase" the default.) Don't get me wrong, I'm all for also providing an option to perform page erases instead of a chip erase (and for them, the 0xFF input must obviously be examined), but for the mentioned security reasons, this must never be the default. |
Another minimalist idea is to not use any option at all, but instead to automatically disable trailing-0xff optimisation in Of course, this could (and I think should) still be done in tandem with giving the user an explicit option to disable trailing-0xff optimisation independently: who knows which of the 112 programmers that Yes, I agree, the very fact of using a bootloader increases the security attack surface. Going down that road mellows the strict Harvard architecture by providing functioning SPM opcodes. This allows the kind of attack you describe. (There is a neat 2008 paper by Francillon and Castelluccia, INRIA (free-access preprint here) with an example of code injection on an ATmega128 using a bootloader and, you will have guessed, some buggy software in addition.) Note, though, the problem in your example is not that optiboot ignores avrdude's explicit chip erase command. The attacker could have instructed |
Here is a use case without a bootloader: I program an ATxmega384D3 to display light effects based on the text of Chaucer's Canterbury Tales. In order to not always have to upload the full monty for testing the light effects I put the 380 kB text in the top of the 392 kB flash and rig up an external programmer (smr-0815x, since you asked, which communicates with the host through the STK500 protocol and uses PDI with the atomic erase-and-write-page for a paged write). Now I reprogram my test runs using
in an attempt to keep the Canterbury Tales in top flash ( So, we have two use cases in which Hence, a simple and unobtrusive solution to this is to piggy-back "disable trailing 0xff-optimisation" onto Of course, other option names exist. Happy to oblige. |
Now, trailing 0xff sequences are no longer removed when either invoking
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides the API I mentioned, looks good to me. I like the fact that you hardcoded the disableffopt for the Arduino programmer. One less trap to step in.
src/main.c
Outdated
@@ -528,6 +528,7 @@ int main(int argc, char * argv []) | |||
|
|||
case 'D': /* disable auto erase */ | |||
uflags &= ~UF_AUTO_ERASE; | |||
avr_mem_hiaddr(NULL); /* disable trailing 0xff optimisation */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avr_mem_hiaddr(NULL)
looks strange. How about creating a new API for this purpose? May I suggest something like
disable_trailing_ff_optimisation()
? That way we could remove the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a prob. Can do so almost trivially by
#define disable_trailing_ff_optimisation() avr_mem_hiaddr(NULL)
in src/libavrdude.h in the line preceding the declaration of int avr_mem_hiaddr(AVRMEM * mem);
This (in my world) passes as a self-documenting API. OK?
The STK500 protocol simply cannot do that. So, your testcase is invalid. Just keep in mind, if you call it STK500, it must behave as if it were an STK500. If you'd do something similar on a real STK500, you'd end up in the same disaster: since you don't do a chip erase between your uploads (and there is no other erase command in the STK500 protocol), you'll end up in programming only those bits to 0 which are still at 1 - regardless of whether AVRDUDE sends all the 0xFFs or not. As already told, I'm all for implementing page erases, but not by abusing existing protocols that have never been intended to handle that. It's not only bootloaders, it's also all modern AVRs with modern Atmel/Microchip tools that will benefit from that. If we do page erases then, we can safely ask the programmer to erase each page before programming it (and still have no need to send 0xFF pages ;-). Still, to avoid security surprises, I'd keep the default to chip erase before programming the flash, so page erases must be explicitly asked for (e.g. Having said this, I'm all for enabling that feature for the Arduino programmer – simply because I'm pretty sure they won't ever fix their bootloader anyway. I agree that |
I completely agree with that. |
I assume you do mean the entire input file, not the entire flash range? Well, #918 is about the (actually, not particularly radical) idea of enabling AVRDUDE to send the full input file to the device under certain circumstances. This PR does that. And, when it does so, it also verifies the complete input file. One of the 30-odd comments (to what I initially thought to be a relatively uncontroversial improvement) identified the additional orthogonal issue with trailing-0xff removal that the verification is only done on the actually programmed bytes. However, I can deal with that, too. Intellectually, this is trivial: when reading the input file for verification do not remove trailing 0xff from it. The implementation is a bit more involved, owing to the need to pass down to |
We seem to be disagreeing about the semantics of STK500's In my reading this command tries to write one page to be programmed to FLASH, not more, not less. So, my smr-0815x physical programmer carries out the semantics of that command faithfully on the target chip, exactly as Atmel's document says it does: it writes one page to flash. What we disagree on is that I think this command is allowed to succeed, while you seem to be implying that the command must not succeed, if it happens to wish to flip a Atmel's documentation does not appear to be so apodictic about that point! Just in case you view my use of an ATxmega and the implementation with the physical PDI layer as a slight of hand, I could have based my thought experiment on the venerable ATmega328p: My physical STK500 programmer smr-0815p (note this is now the model's p version, not the x version) does the following upon the STK500 Summarising, NAND memory can look like a normal memory (just that it's a bit more complicated, but not impossible, to change a |
It's quite simple: get a real STK500, and try it. (I can borrow you one if you want.) |
OK, now all done:
Future work: If/when discussion around SPM programmers concludes, one outcome might be that there is an option in |
Hehe, there is a radical idea... I am more of the "Five months in the lab can save you two hours in the library" persuasion :) |
@mariusgreuel @dl8dtl |
As a reminder: The merged PR adds the option -A to AVRDUDE to switch off trailing-0xff optimisation. Although that was mildly controversial at the time, it is an important feature. Another effect of the PR is that |
Piggy-backs "Do not remove trailing 0xff sequences from avr reads or file input" onto option
-D
, see Issue #918The rationale is that some SPM programmers (bootloaders) are unable to carry out chip erase, but perfectly able to carry out paged writes clearing the memory to 0xff using SPM page erase internally. These SPM programmers need to see the full input file including any trailing 0xff.
This PR provides this functionality under
-D
.Testing with this sketch-ending-in-ff.hex now works as it should:
Documentation will be changed when/if this PR is accepted