1. Virtual bugs
I first really knew that all software was fundamentally insecure back in 2001.
I was working for an artificial life games company. We made virtual pets – amazing ones with a simulated brain, biochemistry and genetics.
I’d just built a new networked version called Creatures Docking Station. It let the cute, furry, egg-laying Norns travel through portals, crossing the Internet directly between player’s computers.
The game engine was built using the language C++. It was fiendishly complicated – neuron simulators for the Norn brains, a scripting language implementing all the in game objects. About 20 people had worked on it, with varying needs, skills and time pressures.
I knew that there were bugs in it. I’d previously stress tested the code – randomly mutating Norns and force breeding them with each other in a diabolical machine, while the game was running in a debugger. It found a new crash bug every hour – I’d tap Gavin on the shoulder and get him to fix each one. We never got them all.
The symptom – the game crashing occasionally due to a mutation – wasn’t itself a world shattering problem. No real lives were on the line. Bad user experience, but so what?
1) In C++, bugs in this category let an attacker do anything they like. That is, much like a chain saw, with great power comes great responsibility.
2) With the new networked game, it would let an attacker do anything they liked, remotely and automatically from across the network.
In short, a player of our game could have their machine taken over remotely – their documents deleted, spam sent, their Internet banking password sniffed (not that many people used Internet banking back then). Whatever the attacker wanted.
At the time, there was no tool or technology or budget available for me to fix this. I did what every programmer did – closed my eyes. Ignored the problem. Hoped nobody would do bad things with it.
I knew though that nearly all general purpose software, particularly written in C/C++, was likely to be insecure.
2. A simple promise
Wind forward to 2015.
I’ve been worrying for a while about the long, cold cyberwar. A small part of that war is basic security of all computer systems – so it’s hard for criminals or rogue states to, say, remotely turn on your microphone without you knowing.
Peter had shown me how good Go is now (we use it a lot at work), making my historical needs for C/C++ now obsolete. Suddenly, it felt possible to completely stop using those languages.
I promise never to use C/C++ for a new project
If you’re a programmer, go on, go and sign it!
This seemingly simple promise felt like putting my head over a parapet during a siege. I learnt quite a lot.
3. Things I learnt
Embedded systems – lots of people wouldn’t take the promise because they work on embedded systems where C dominates. Others pointed out various rays of hope – Python for microcontrollers, OCaml for PICs, LLVM for AVR chips, embedded Rust, even Go for Arduinos (OK, not quite!). Are those going to be good enough, even if you have to direct code for cycle goals?
My view is that it is particularly important to sort this out now. Embedded devices are joining the internet more and more – even if you’re writing something which is standalone now, some other programmer will connect it to something in 5 or 10 years. I don’t want my physical devices to be easy to hack into. The pledge I’d really like embedded systems developers to take is to try using and improve on the new more secure toolchains.
In principle I’m up for this, but only if it is forced in an explicit language variant – otherwise someone will shoot themselves in the foot later. I’m not sure it is worth it in most cases, compared to using Go or Rust. Either way, legacy C/C++ code is the really big issue.
Go or Rust flaws – a few people don’t like them, sometimes for aesthetic syntax reasons, sometimes claiming they are hard to use. I don’t think C has a particularly great syntax – I can remember trying to learn it when I was 15, it wasn’t easy. Sure, if you don’t like them, pick something else. It doesn’t mean you have to juggle with chainsaws.
Of course, these new languages still have parts written in C, at least for now. There can always be bugs in their compilers and assemblers. I don’t think this is a big problem, as those parts are a much much smaller surface of attack – albeit a valuable one.
Application binary interfaces – what can we use instead of C as the standard ABI? Pretty well all languages in the “open source” world interoperate with each other via C bindings. If you took my promise, would you still be able to write Python bindings to an existing C library? Pretending we don’t need C is just fantasy.
This is by far the best criticism. Of course, the Java and .NET worlds have spent a decade building entirely new ecosystems which strongly discourage C bindings. So it’s perfectly possible. We will need something specific to use instead. I don’t know what it should be – this needs strong leadership, maybe from the Rust people.