Hacker News new | ask | show | jobs
by pcwalton 1636 days ago
> (you can still get a segmentation fault, and I did a few times - by erroneously holding on to pointers inside a container while it resized. Still, uncomparably safer)

This is a severe problem, and I predict that this is going to cause real security issues that will hurt real people if Zig gets used in production before it gets production-ready memory safety. This exact pattern (pointers into a container that resized, invalidating those pointers) has caused zero-days exploited in the wild in browsers.

5 comments

> This is a severe problem, and I predict that this is going to cause real security issues

That is a nasty problem, particularly in larger projects with different subsystems interacting (like say an xml parser and another).

I suspect it's worse in some ways as Zig has good marketing as being "safer" language despite still having the same fundamental memory flaws as C/C++. In the worse case that could lull programmers into complacency. I mean it looks "modern" so it's safe right? Just do some testing and it's all good.

Currently I'm skeptical Zig will get a production-ready memory safety. Currently there's only GC's or linear/affine types and Zig doesn't appear to be pursuing either. Aliased pointers aren't something that's properly handled by adhoc testing IMHO.

FWIW, "safe" doesn't appear anywhere on the Zig homepage. I've been trying out Zig for the past couple weeks, and while I love it so far, it gives anything but the feeling of safety. I would say there's guardrails, but those are optionally disabled in the compiler for faster execution.

It seems to be that Zig is really not trying to be a replacement for all programming, but fill its niche as best it can. If your niche requires memory safety as a top priority because it accepts untrusted input, Rust would probably be a better choice than Zig.

Reminds me of modern C++, where the language and standard library features all work together to increase safety. And then it backfires because you feel like it's safe, but in reality it's not, and bugs still happen, they just catch you off-guard.
Some sort of pointer tagging system, like 128-bit pointers where the upper word is a unique generation ID, might be the simplest approach to eliminate security problems from use-after-free, but it's going to have some amount of runtime overhead (though new hardware features may help to reduce it).

Alternately, use a GC.

Another option is something like Type-After-Type (make allocations use type-specific regions, so use-after-free is still fully type safe at least):

https://download.vusec.net/papers/tat_acsac18.pdf

Yes, something like that may work. Note that this approach also has time and memory overhead quoted in the paper. There's no free lunch.
If you write tests in zig you will probably find this using the testing allocator. Yes, I get that some people really don't like writing tests.
Many of the highest-profile memory safety security issues are in very well-tested codebases, like browsers.
What's your point? You're comparing apples to oranges.
The point is that "write tests" has empirically not been a satisfactory solution to this class of vulnerability.
I think you don't get it. This isn't "write tests to make sure the vulnerability doesn't exist" this is "as you're testing, all of your code is automatically scanned for these vulnerabilities".

For a big project like a browser, I would imagine the tests would include property tests, fuzzing, etc.

This is obviously strictly less powerful than a proof assistant, which, yes, rust has, but we don't empirically know what the delta and the risk factor is between something like what zig gives you and something like what rust gives you... Moreover, I think it's likely that something like an proof assistant will be developed to track resources based off of zig's AIR. This is something that would be costly, but you could write it as a "linter" that blocks commits as a part of CI.

> "as you're testing, all of your code is automatically scanned for these vulnerabilities".

For browsers, that's been done for years and years, probably even a decade at this point. Tooling for memory safety has gotten incredibly good.

Yes, when I invariably had to debug the first UAF in Zig I did pause for a bit and pondered my rust. It's definitely an argument against Zig that is unlikely to go away anytime soon.
Zig is not memory safe on purpose. So when you need or want that you don’t use Zig
Zig apparently has valgrind support. Maybe it’s not turned on by default?
A better way to put it is "valgrind integration". It is enabled by default (when compiling for a target that has Valgrind support). Mainly it integrates with the `undefined` language feature which helps catch branching on undefined values. The nice thing you get beyond what C gives you, is that in Zig you can set things to undefined when you are done with them. Meanwhile in C, Valgrind is only aware of undefined for uninitialized variables.

But as others have pointed out, although Valgrind is a nice debugging tool, you would not run your application in it under normal circumstances. It's also not available on some important targets, such as macOS and Windows.

I don't think Zig has any particular Valgrind support, it's just a binary after all. In order to properly utilize valgrind though you're going to have to change from the GPA or whatever allocator you're using to the libc one so that Valgrind can trace memory allocations correctly via preloading.
Here is some kind of valgrind API [1] and a here is a report from someone who tried using valgrind [2]. Yes, it doesn’t sound all that special.

[1] https://github.com/ziglang/zig/blob/master/lib/std/valgrind.... [2] https://dev.to/stein/some-notes-on-using-valgrind-with-zig-3...

Valgrind support is cool but it's not a solution to the problem.