Live data from Hacker News

This shouldn't have happened: A vulnerability postmortem

googleprojectzero.blogspot.com

461–470 of 499 posts

Re: This shouldn't have happened: A vulnerability postmortem

#461
post #227

Earlier quoted context omitted.

> Suggesting a tabula rasa rewrite of NSS would more likely be met with genuine concern for your mental well-being, than by incredulity or skepticism. In my experience, porting code more or less directly from one language to another is faster and easier than people assume. Its certainly way faster than I assumed. I hand ported chipmunk2d to javascript a few years ago. Its ~30k LOC and it took me about a month to get…

> In my experience, porting code more or less directly from one language to another is faster and easier than people assume. That's often true right up to the point where you have to be keenly aware of and exceptionally careful with details such as underlying memory management functionality or how comparisons are performed. With this in mind, cryptographic code is likely a pathological case for porting. It would be v…

If a programs reads from uninitialised memory, I hope for its sake that it does not do it in C/C++. Setting aside that uninitialised memory is a hopelessly broken RNG seed, or the fact that the OS might zero out the pages it gives you before you can read your "uninitialised" zeroes…

Reading uninitialised memory in C/C++ is Undefined Behaviour, plain and simple. That means Nasal Demons, up to and including arbitrary code execution vulnerabilities if you're unlucky enough.

Re: This shouldn't have happened: A vulnerability postmortem

#462

Earlier quoted context omitted.

> Auto-translation won't work because Rust won't allow you to build it in the same way you would have built it in C. That is not entirely true, but if you translate the C code to Rust, you get C code, in Rust, with similar issues (or possibly worse). Of course the purpose would be to clean it up from there on, but it's unclear whether that's a better path than doing the conversion piecemeal by hand. The C2Rust people…

The jury's out on whether Rust code with unsafe around all of it is better than C. It's good that you can slowly reduce the unsafe, which is not something you can do with C, but the code is frequently harder to read and may have new bugs.

> The jury's out on whether Rust code with unsafe around all of it is better than C.

The goal definitely isn't to keep it as is, the entire point of C2Rust is to provide a jumping point then not have to shuffle between the two as you perform the conversion.

Re: This shouldn't have happened: A vulnerability postmortem

#463

Earlier quoted context omitted.

nss was also generally considered to be thoroughly vetted though

There’s a world of difference between ASN.1 validation and validation of cryptographic primitives. The serialization/deserialization routines for cryptographic data formats or protocols are where you typically get problems. Things like AES and ECDSA itself, less so, especially when you’re talking about the code in BoringSSL. Maybe some more obscure algorithms but I imagine BoringSSL has already stripped them and ring…

For symmetric cryptography (ciphers & hashes), I agree. I'd say as far as to say they're stupidly easy to test.

Polynomial hashes, elliptic curves, and anything involving huge numbers however are more delicate. Depending on how you implement them, you could have subtle limb overflow issues, that occur so extremely rarely by chance that random test don't catch them. For those you're stuck with either proving that your code does not overflow, or reverting to simpler, slower, safer implementation techniques.

Re: This shouldn't have happened: A vulnerability postmortem

#464
post #453

Earlier quoted context omitted.

Memory corruption doesn't always trigger segfaults. I don't believe it will be obvious why some random other part of your program will start giving intermittent errors even if it is in Rust.

In Rust, or any other systems programming language with unsafe code blocks, all the way back to JOVIAL and ESPOL, one can search for those code blocks. At very least they provide an initial searching point. On C, C++ and Objective-C, any line of code is a possible cause for memory corruption, integer overflow, or implicit conversions that lead to data loss.

This is starting from the point of knowing it is a memory corruption issue though. From my experience, memory corruption usually manifests in logic or data behaviour changes. In a Rust program you'd probably spend a few days pulling your hair out trying to understand why some data structure doesn't do what it's supposed to before considering that it's one of the unsafe blocks.

Re: This shouldn't have happened: A vulnerability postmortem

#465
post #75

Earlier quoted context omitted.

I'd like to write go or rust but embedded constraints are tough. I tried and the binaries are just too big!

How big is too big? I haven't run into any size issues writing very unoptimized Go targeting STM32F4 and RP2040 microcontrollers, but they do have a ton of flash. And for that, you use tinygo and not regular go, which is technically a slightly different language. (For some perspective, I wanted to make some aspect of the display better, and the strconv was the easiest way to do it. That is like 6k of flash! An unabas…

I have 16MB of flash and I wanted to link in some webrtc Go library and the binary was over 1MB. As I had other stuff it seemed like C was smaller.

Re: This shouldn't have happened: A vulnerability postmortem

#466
post #459

Earlier quoted context omitted.

I think you're making my point for me, no? Your arguments are all variants on "I don't understand modern Java and prefer to keep writing buffer overflows than finding out". To answer your questions: 1. Java is these days like UNIX, there are lots of "distros". OpenJDK is the upstream on which most of them are based. You can just use that unless you have some particular preference for the other vendors. However the co…

> "I don't understand modern Java" Exactly! > "and prefer to keep writing buffer overflows than finding out" Not exactly. I would rather take the risk of writing buffer overflows than using over-bloated infrastructure, being in code size and/or performance, tooling, including learning time. It's a tradeoff. It's always a tradeoff. Mozilla might have had their own reasons, and probably not on a whim. If I have to writ…

Right, as I said up thread: "I think it's rather than the market rewards performance above security." - so we're not really disagreeing.

In this case I doubt there'd be a big CPU overhead. There'd be some memory overhead, and browsers compete on that, although of course they're kind of memory pigs already.

"The code is there. You can try to link Java JCA/JSSE to Firefox or whatever the project is about. I'm interested in learning how it looks and how it works."

I think once Panama (the new FFI) gets released it'd be interesting to experiment with this sort of thing, though I don't care about Firefox personally. That would eliminate a lot of the tedious boilerplate you'd otherwise have to churn out.

Re: This shouldn't have happened: A vulnerability postmortem

#467
post #367
post #289

Earlier quoted context omitted.

This is a really hard problem because you have to discard the magic wand of a compiler and look at what is really happening under the hood. At its most rudimentary level, a "memory safe" program is one that does not access memory that is forbidden to it at any point during execution. Memory safety can be achieved using managed languages or subsets[1] of languages like Rust - but that only works if the language implem…

Is there a way to do FFI without having languages directly mutate each other's memory, but still within the same process. So all 'communication' between the languages happens by serializing data, no shared memory being used for FFI. But you don't get the massive overhead of having to launch a second process. You are still depending on the called function not clobbering over random memory. But if the called function i…

In practice you run all your process-isolated code in one process as a daemon instead of spawning it per call.

I think you're on the right track in boiling down the problem to "minimize the memory shared between languages and restrict the interface to well defined semantics around serialized data" - which in modern parlance is called a "remote procedure call" protocol (examples are gRPC and JSON RPC).

It's interesting to think about how one could do an RPC call without the "remote" part - keep it all in the same process. What you could do is have a program with an API like this :

    int rpc_call (int fd); 
where `fd` is the file descriptor (could even be an anonymous mmap) containing the serialized function call, and the caller gets the return value by reading the result back.

One tricky bit is thread safety, so you'd need a thread local file for the RPC i/o.

Re: This shouldn't have happened: A vulnerability postmortem

#468
post #137

Wow. We continue to be reminded that it's hard to write fully memory secure code in a language that is not memory secure? And by hard, I mean, very hard even for folks with lots of money and time and care (which is rare). My impression is that Apple's imessage and other stacks also have memory unsafe languages in the api/attack surface, and this has led to remote one click / no click type exploits. Is there a point a…

> Or are C/C++ benefits just too high to ever give up? FFI is inherently memory-unsafe. You get to rewrite security critical things from scratch, or accept some potentially memory-unsafe surface area for your security critical things for the benefit that the implementation behind it is sound. This is true even for memory-safe languages like Rust. The way around this is through process isolation and serializing/deseri…

Writing a small wrapper that enforces whatever invariants are needed at the FFI boundary is much, much easier to do correctly than writing a whole program correctly.

You are never going to get 100% memory safety in any program written in any language, because ultimately you are depending on someone to have written your compiler correctly, but you can get much closer than we are now with C/C++.

Re: This shouldn't have happened: A vulnerability postmortem

#469

Earlier quoted context omitted.

One of the things I like about Zig is that it takes the memory allocator as a kind of “you will supply the correct model for this for your needs/architecture” as a first principle, and then gives you tooling to provide guarantees downstream. You’re not stuck with any assumptions about malloc like you might be with C libs. On the one hand, you might need to care more about what allocators you use for a given use case.…

Zig is, however, not memory safe, which outweighs all of those benefits in this context.

It can be memory safe. It's up to you to choose memory safety or not. That's a piece of what I was getting at. Unless I misunderstand something. I've only dabbled with Zig.

Re: This shouldn't have happened: A vulnerability postmortem

#470
post #356

Earlier quoted context omitted.

Why is indirect Internet access less of a problem for C than Rust/Go/etc? Seems like for modern systems, you just run a pre-populated caching proxy on your target and `cargo install` like you normally would. In C, you're manually checking versions and putting files in the right spot on disk for every stage of the build (this can be alleviated a bit if you can find pre-built binaries and so on, but even in the best ca…

> Why is indirect Internet access less of a problem for C than Rust/Go/etc? Because C codes tend to have less dependencies and shallow/more "clustered" dependency graph. To be fair, that's more or less due to dependency management being a 100% pain 0 fun experience.

I agree with your characterization of the dependency graphs, but I don't see how that changes the calculus. Let's say in both cases you're copying a tarball of dependencies onto your friend's AIX machine--why is it harder to copy a tarball with a few large dependencies rather than a tarball with more small dependencies (I also posit that the Rust tarball would be smaller because you're less likely to be bringing in things you don't need--e.g., think of all the things curl does versus a straightforward HTTP lib)?
Post reply on HN