clarification : running from ROM
Here is a clarification of my point : ( yeah my typing is bad sometimes , and no i'm not a troll. i am simply baffled by bad hardware/software engineering these days. Nasa flew to the moon and back, 40 years ago with 16 kilowords of memory space and a multitasking system running on a computer made only with dual nor gates ( fairchild 914's) ). Today we need a 5 megabyte kernel just to get to the point where we can start running an application... An old adagy says that any extra line of code adds a potential extra problem.
A mayor flaw with running critical code from ram is that: any memory leak ( whether a software bug , a shortcoming or an unintended side effect ) or a buffer overflow ( whether maliciously caused or not) can alter the intended loop of the program.
Running from ROM solves these problems. Code is unalterable. Additional traps in the rom image can force a reset.
Here is how i build critical systems the last 10 years: ( ARM based)
A real ROM ( not E2 or Flash but mask rom ) holds a bootloader. ( the bootloader is very small . about 76 words ... ) All this bootloader does, is initialise the SDRAM controller and then copy the executable code from FLASH to SDRAM. When this is done the bootloader sets a hardware flag. This flag can only be cleared by a power cycle or a hard reset ( somebody has to physically waddle over there and press the button ). The flag is used by the sdram controller to 'seal' a block of memory ( a simple hardware address comparator checks for a range of addresses and blocks write operations from the cpu side ). This whole mechanism resides in hardware. The SDRAM controller can still perform the refresh cycle, only the CPU can not write there. That is blocked by hardware.
At compile time i inject dummy code between subroutines and in unused space. All this dummy code contains is a JMP <bootvector>. If the code runs away , or is forced in limbo by the whole system will autoreset ( the bootloader gets re-invoked ) For debugging purposes the jump leaves a marker behind that tells me from which address it has jumped. The bootloader sends this to the serial debug port.
You can try all you want, the CPU will never execute anything from data space. Only if you succeed in overwriting the flash can this be done. The flash mechanism is also protected. Once the bootloader has ran the write access to flash is disabled ( same settable-only flag mechanism ). Only the bootloader has the flash mechanism. In order to flash firmware you need physical access to the system , hold the reset button 3 seconds and then it enters flashload mode. Flashload runs from the top of the flash memory. You can not jump there once the system is running ( The hardware flag has cut off access remember ).
All that is required is a couple of flipflops. The flipflop clk and data tied to ground. The CLR pin goes to the physical reset button , the SET pin goes to an address decoder. If address matches and a 1 is on d0 then set the flipflop. The whole thing is 2 lines in verilog code. On silicon you don't even see it..
Of course it is no excuse to write bad code, but a few simple hardware blocks can prevent unintended data execution, runtime code corruption and intrusion. Even if you find a way to execute data (you'll need physical access to the box and probe it as in solder wires to it) , this can not alter the cpu code. If you land in limbo : automatic reboot from a clean copy. simple as that.
In one of my systems i have extended this hardware block. When the bootloader finished copying flash to sdram it stores the memory pointer in a 'topmem register' and seals it by setting the flag. A hardware block monitors the address bus. If an instruction fetch happens from any address above this 'topmem' value :hardware reset , invoke bootloader : start from clean code. game over. So even if all else fails the bus cycle betrays you and forces a hardware reset.
The only point where the system is 'vulnerable' is prior to sealing the memory spaces. But that is when the bootloader runs from mask rom in the asic. So you can not corrupt this block. Prior to exiting the bootloader the sealing bits are turned on and memory is locked down. There is no speed penalty because code sits in sdram ( albeit a portion that has write access blocked by hardware )
Try all you want , you will only fail.
It baffles me that almost nobody takes care to put such simple mechanisms in place. It does not bother the programmers (actually it helps in debugging. You'll very quickly discover if you have a problem since the box will reboot immediately. The jumpvector gives you an indication from where the problem originated. You do need to take care about how you do the layout of your code, and you need to inject the dummy jump instructions. But that is a matter of code discipline. You can easily script such things.
And there is again another 'modern problem' most code these days is simply compiled and slapped on the box. The programmers do not understand the cpu, the hardware or care about memory layout. They are used to high level languages and 'leave it to the compiler'.. most of them don't even know how compilers behave.
One of the dangers of open source is the false sense of confidence and security.
The excuse is that it's been overlooked by so many people , so it must be bug free..
The last couple of days have proven that wrong , once more... Open source is good , because you can LEARN how things work. But blatantly dropping a chunk of code in a system is plain stupid. It would be like putting a floppy with unknown contents in the drive and booting from it... in the 80's and early 90's that was a sure way to get nasties on your machine.