Author Topic: Remote Code Execution, issues and best practices  (Read 1941 times)

0 Members and 1 Guest are viewing this topic.

Offline jnzTopic starter

  • Frequent Contributor
  • **
  • Posts: 593
Remote Code Execution, issues and best practices
« on: March 23, 2017, 09:03:43 pm »
Ok... Look, you all go way over my head fast. So for this thread, maybe consider how you'd explain it to your dumb cousin who just happened to ask a question you are interested in :D

In terms of ARM Cortex M4:

I have a project where I need the micro to perform some code quickly but I don't yet know what that code is. External source.

The last time I asked this many people directed me towards remote code execution, interpreters like Forth, or towards a DSL. The issue with a DSL I may need to do things tomorrow I didn't think of today, so that means firmware updates and version-hell, I self-limited to NOT LOGIC IN MY DSL, and about a week later saw a spot I could really use a loop. The problem with scripting or interpretive languages like Forth or eLua is they have almost no serious support with active communities, all years out of date at best for a turnkey solution. Python can do it, but it's really heavy and includes a ton of things I don't want to do.

The pro of remote code execution is that I should rarely need firmware updates for small changes, I can have any logical or C method available to me at any time, and it's a lot lighter than the other options as it's just all native ARM code, no extra layers of translation. It really simplifies the interaction too as I just need to provide the correct bytestring, there won't be any extra work to interpret and pack.

The questions I have with remotely executing code:

  • If I send a pre-compiled byte string to my device and execute in RAM, can I call functions from the original flash on demand? Freely switch from my RAM code to my Flash code and return back? Does the micro care where instructions are actually located?
  • Obviously the issue would be if there was a function Foo(uint8_t) in flash, and I want to call it from my RAM code I need to know where it's located explicitly. This is a job for the linker and libraries right? What if I want to possibly move things around between two hardware versions of code, does it become a job for a _SVC? Is there a "safe" way to do this other than to ALWAYS locate this function at a specific address no matter what?
  • I know this is dangerous, allowing remote code. I can do my best by encrypting the byte string before transit and only decrypt on chip, but are there any other good practices? CRC or better yet sign the string? Assigning the Memory Protection Unit to only allow RAM code to access specific regions? It might be difficult, but maybe a simple ARM instruction interpreter that checks the string for commands that I don't allow like reading from X memory or any writing to flash?

I know some of this is really basic, but I've never had to do anything like this yet.

Thanks! You guys are great.
 

Offline alm

  • Super Contributor
  • ***
  • Posts: 2903
  • Country: 00
Re: Remote Code Execution, issues and best practices
« Reply #1 on: March 23, 2017, 09:25:41 pm »
Instead of messing around with linkers and having to update the byte string when you recompile your firmware, I would probably implement something like syscall(2) on UNIX systems as a software interrupt. But I have never built something like this either, so that is just a hunch. When loading machine code, you would also need to make sure it is position independent code (PIC), i.e. no absolute addresses.

One thing I would worry about (both for the machine code version or the interpreter route) is how are you going test the firmware? How do you guarantee your code does not mess up the firmware? You would need a well defined API (limited set of API functions, stack usage, heap memory, access to peripherals) to have any chance of having it be stable.

I would probably go the Forth / Lua / DSL interpreter route just so the firmware has some control over what the code can and can not do. And then fuzz test the hell out of it to make sure the firmware recovers regardless of the nonsense thrown at it. And I am pretty sure stuff like this will never make it in any high-reliability environment. What does MISRA say about self-modifying code? ;)

Offline jnzTopic starter

  • Frequent Contributor
  • **
  • Posts: 593
Re: Remote Code Execution, issues and best practices
« Reply #2 on: March 23, 2017, 10:43:19 pm »
you would also need to make sure it is position independent code (PIC), i.e. no absolute addresses.

Of course.

Quote
One thing I would worry about (both for the machine code version or the interpreter route) is how are you going test the firmware? How do you guarantee your code does not mess up the firmware? You would need a well defined API (limited set of API functions, stack usage, heap memory, access to peripherals) to have any chance of having it be stable.

Yes. That is a concern, but it's a concern both ways. If I load a script, I can't step debug it like I would like either, and now if I'm running a scripting engine there is other people's code involved as another layer. Short version on testing is that the environment I use to build the code will be the same environment it's destined for (obviously). I'd treat the development of these remote snippets as if they were production firmware components, then verify they worked the same way in ram before pushing them out. Yes, very limited in what Flash functions and existing RAM data they can access Best I can do I think.

Quote
I would probably go the Forth / Lua / DSL interpreter route just so the firmware has some control over what the code can and can not do. And then fuzz test the hell out of it to make sure the firmware recovers regardless of the nonsense thrown at it. And I am pretty sure stuff like this will never make it in any high-reliability environment. What does MISRA say about self-modifying code? ;)

I like the IDEA of those things but between zero support and/or 3rd party code, and looking like dead projects, I can't really trust them. Basically, even if you found the world's most secure Forth interpreter ready for ARM M4, it would still have to access my C functions directly, seems like the same issues. The DSL is fine but I really feel like I'm going to wind up with something that works at launch and not 10 minutes after I talk to the first user. There is a really big issue of having to write a compiler and an interpreter on two ends of chain then make sure they match all the time.

But anyhow... In terms of this topic, I'd like to keep the discussion about the native remote code concerns/practices.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->