> You'll notice my address() trick to get the address of a function or variable that I used in my previous exploit. We're relying on package fmt and its %p format specifier which is implemented by using the unsafe package, so we don't need to use it ourselves.
> A crash on out of bounds will always happen, unless unsafe package is being used to subvert memory accesses, or if you've used something that exposes details that only the unsafe package exposes, such as fmt's %p specifier.
I mean, you are like, the ultimate pedant, so I figured you'd uniquely appreciate this.
You can't just say, "use unsafe or anything that uses unsafe," because it's turtles all the way down. You've got to draw that line somewhere. If the %p specifier really is required for an exploit and there's nothing else that exposes that (sans unsafe), then that's great news! But is that the whole story?
The unsafe address() is used to get the address of a function to store in the int, to demonstrate the potential for shellcode injection. But you could just as easily assign pp := 12345 and produce a SIGSEGV or SIGILL, which would not be possible if Go were memory safe.
The exploit was only possible thanks to using the unsafe package, even if indirectly.
It is exactly because Go is memory safe that a SIGSEGV or SIGILL is produced the exact moment the memory gets corrupted and not 2 hours later in a complete different stack trace.
If you have an out of bound in C, your program keeps running in 9/10 cases. In Go you'll cause a panic in 10/10 cases which you can either handle and propagate as error or let the program crash entirely, the memory will be in a defined state if you choose to recover (your array might be garbage but you won't have written data into random memory belonging to other threads)
The %p formatting used to gain access to the pointer of a variable uses the unsafe package, the formatting itself is incredibly rarely use to begin with.
I don't see anybody doing any security-related exploits doing that unless you explicitly write for it.
Go won't do out of bounds, edges cases do happen. You can find the same stuff on Java and Rust (yes, I had OoB in Rust, though on a baremetal environment without OS, even Rust ain't safe.)
On safe languages an out-of-bounds will cause a crash on the access point, while on unsafe languages it will silently corrupt memory.
Also multithreading gets some improvements which will take more of the manual sync details away from the business logic. (http://www.modernescpp.com/index.php/multithreading-in-c-17-...)
It's still delivered attached to a foot-gun, but you could do worse.
Why is this choice better than a language that provides memory safety using linear types so you don't even need a runtime or garbage collector?
Not really a huge number, no. Java is probably the most obvious, if you count that as compiled. Maybe Haskell or D? I suppose even Swift of Objective C if you include RC in the definition of GC.
I would say the focus shouldn't be entirely on GC, however. Safety as a whole is the most important factor, and it's possible to be say without GC, as you point out. I reckon Go is actually quite an attractive language for this sort of application regardless – quite safe, quite lightweight, good libraries.
Of course I used my favorite programming language for building gokrazy :).
I can't resist while here thanking you for i3. I've been a mac user recently, but will likely be back to linux in the next year or so. Using i3 again will be probably be the greatest pleasure involved in that return ;)
I love your stuff! I enjoyed your episode on Go Time as well!
Cheers!
gokrazy’s unit of application is a Go package, so you’d need to write a Go program which then executes the Lua VM. I don’t know what dependencies Lua has — if it cannot be compiled statically, I’d recommend against using Lua in this context.