18

I'm trying to get a ram-resident image to checksum itself, which is proving easier said than done.

The code is first compiled on a cross development platform, generating an .elf output. A utility is used to strip out the binary image, and that image is burned to flash on the target platform, along with the image size. When the target is started, it copies the binary to the correct region of ram, and jumps to it. The utility also computes a checksum of all the words in the elf that are destined for ram, and that too is burned into the flash. So my image theoretically could checksum its own ram resident image using the a-priori start address and the size saved in flash, and compare to the sum saved in flash.

That's the theory anyway. The problem is that once the image begins executing, there is change in the .data section as variables are modified. By the time the sum is done, the image that has been summed is no longer the image for which the utility calculated the sum.

I've eliminated change due to variables defined by my application, by moving the checksum routine ahead of all other initializations in the app (which makes sense b/c why run any of it if an integrity check fails, right?), but the killer is the C run time itself. It appears that there are some items relating to malloc and pointer casting and other things that are altered before main() is even entered.

Is the entire idea of self-checksumming C code lame? If there was a way to force app and CRT .data into different sections, I could avoid the CRT thrash, but one might argue that if the goal is to integrity check the image before executing (most of) it, that initialized CRT data should be part of that. Is there a way to make code checksum itself in RAM like this at all?

FWIW, I seem stuck with a requirement for this. Personally I'd have thought that the way to go is to checksum the binary in the flash, before transfer to ram, and trust the loader and the ram. Paranoia has to end somewhere right?

Misc details: tool chain is GNU, image contains .text, .rodata and .data as one contiguously loaded chunk. There is no OS, this is bare metal embedded. Primary loader essentially memcpy's my binary into ram, at a predetermined address. No relocations occur. VM is not used. Checksum only needs testing once at init only.


updated Found that by doing this..

__attribute__((constructor)) void sumItUp(void) {
    // sum it up
    // leave result where it can be found
}

.. that I can get the sum done before almost everything except the initialization of the malloc/sbrk vars by the CRT init, and some vars owned by "impure.o" and "locale.o". Now, the malloc/sbrk value is something I know from the project linker script. If impure.o and locale.o could be mitigated, might be in business.

update Since I can control the entry point (by what's stated in flash for the primary loader), it seems the best angle of attack now is to use a piece of custom assembler code to set up stack and sdata pointers, call the checksum routine, and then branch into the "normal" _start code.

JustJeff
  • 12,640
  • 5
  • 49
  • 63
  • Do you not have the option to put the code into a segment other than .data? That way, you can avoid modification entirely when calculating your checksum. – Oliver Charlesworth Dec 31 '12 at 15:01
  • I could easily enough just sum the .text and .rodata, but this would leave out things like initialized tables etc from the sum. – JustJeff Dec 31 '12 at 15:05
  • 1
    Yes, that's true. In which case, you have a problem. Maybe there's some way to completely subvert the CRT startup and run your checksum routine before that, but that's well beyond my expertise! What platform is this; is there any way to modify the loader itself? – Oliver Charlesworth Dec 31 '12 at 15:08
  • Drat. Was hoping for -Wl,-weird_corner_case kind of thing. Oh well, "requirements pushback" begins to appeal – JustJeff Dec 31 '12 at 15:16
  • There may well be some magic options for your platform's compiler (like I said, this is some way out of my area of expertise!). But requirements pushback is always healthy; this sounds a little bit like over-engineered specifications. – Oliver Charlesworth Dec 31 '12 at 15:18
  • 1
    By the way, why include the data segment into the checksum? The essential, in terms of security, is to make sure **executable code** hasn't been altered. –  Dec 31 '12 at 15:19
  • Well for example, before the ram load, the system is wide open, but one thing the ram resident code does is configure a memory protection unit. I know, should have the flash code do that. Would have been a great catch at design review. – JustJeff Dec 31 '12 at 15:42

5 Answers5

5

If the checksum is done EARLY enough, you could use ONLY stack variables, and not write to any data-section variables - that is, make EVERYTHING you need to perform the checksumming [and all preceding steps to get to that point] ONLY use local variables for storing things in [you can read global data of course].

I'm fairly convinced that the right way is to trust the flash & loader to load what is in the flash. If you want to checksum the code, sure, go and do that [assuming it's not being modified by the loader of course - for example runtime loading of shared libraries or relocation of the executable itself, such as random virtual address spaces and such]. But the data loaded from flash can't be relied upon once execution starts properly.

If there is a requirement from someone else that you should do this, then please explain to them that this is not feasible to implement, and that "the requirement, as it stands" is "broken".

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • I think 'early enough' is the key, and toward that end it looks like the best route may be to use a pinch of assembler to do the summing before the _start point is called. Seems hard to imagine a failure mode that would require this, but I wasn't "on the team" when the requirements/design were laid down. – JustJeff Jan 01 '13 at 03:13
  • I would still discuss with the originator of the req, it may be that it's a misunderstanding of what can be done (easily). By all means, some assembler should do it, but I just think it may be a bit more work than necessary. – Mats Petersson Jan 01 '13 at 10:52
  • Giving this the accept b/c "early enough" is the actual solution I'm using; found the way to get an assembly language stub to do the dirty work and then jump into CRT. Not a pure C solution, but it's what worked in the end. – JustJeff Jan 03 '13 at 15:47
2

I'd suggest approaching this like an executable packer, like upx.

There are several things in the other answers and in your question that, for lack of a better term, make me nervous.

  • I would not trust the loader or anything in flash that wasn't forced on me.
  • There is source code floating around on the net that was used to secure one of, I think, HTCs recent phones. Look around on forum.xda-developers.com and see if you can find it and use it for an example.
  • I would push back on this requirement. Cellphone manufacturers spend a lot of time on keeping their images locked down and, eventually, all of them are beaten. This seems like a vicious circle.
JimR
  • 15,513
  • 2
  • 20
  • 26
  • not actually trying to lock anything down or prevent system being rooted or anything like that, this is just a straight up integrity check b/c someone was worried that something would get corrupt *during the copy to RAM* – JustJeff Dec 31 '12 at 21:30
  • I would suggest using a more robust integrity check than a simple checksum. At the very least you could easily use CRC32 or cryptographic hash function such as MD5 or SHA – marko Jan 01 '13 at 20:30
  • @JustJeff: It's entirely possible for it to get corrupted, but pretty unlikely. We had a problem like this with modems in the '90s but it only hit about once in 4 million transactions. It took almost 2 years for the app to see 4 million transactions and for us to find the problem. Still we had to fix it. I still believe the exe packer approach has merit and that is how I would approach it were I stuck with this requirement. – JimR Jan 03 '13 at 09:55
  • I'd have preferred crc32, but got stuck with checksum. Either way the problem would have been the same; the code modifying data before the chosen algorithm could be run. Anyway, as interesting as this exe packer sounds, I think it is probably over the top in my case, but could be a boon to others. – JustJeff Jan 03 '13 at 15:44
1

Can you use the linker script to place impure.o and locale.o before or after everything else, allowing you to checksum everything but those and the malloc/sbrk stuff? I'm guessing malloc and sbrk are called in the bootloader that loads your application, so the thrash caused by those cannot be eliminated?

It's not an answer to just tell you to fight this requirement, but I agree that this seems to be over-thought. I'm sure you can't go into any amount of detail, but I'm assuming the spec authors are concerned about malicious users/hackers, rather than regular memory corruption due to cosmic rays, etc. In this case, if a malicious user/hacker can change what's loaded into RAM, they can just change your checksumming routine (which is itself running from RAM, correct?) to always return a happy status, no matter how well the checksum routine they aren't running anymore is designed.

Even if they are concerned about regular memory corruption, this checksum routine would only catch that if the error occurred during the original copy to memory, which is actually the least likely time such an error would occur, simply because the system hasn't been running long enough to have a high probability of a corruption event.

Sam Skuce
  • 1,666
  • 14
  • 20
  • 1
    Does seem absurd, doesn't it? If flash checks ok, and ram test passes, the only thing that might go wrong during the copy itself would be maybe the CPU register used to pick the data up and write it back out has a bad bit, which would highly probably result in bigger woes than just a mangled copy. The mind boggles. – JustJeff Jan 01 '13 at 15:01
0

In general, what you want to do is impossible, since on many (most?) platforms the program loader may "relocate" some program address constants.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
0

Can you update the loader to perform the checksum test on the flash resident binary image, before it is copied to ram?

kkrambo
  • 6,643
  • 1
  • 17
  • 30