Hacker News new | ask | show | jobs
by ddevault 1502 days ago
We do take security pretty seriously with Hare. To quote our crypto module's introduction as an example:

> Cryptography is a difficult, high-risk domain of programming. The life and well-being of your users may depend on your ability to implement cryptographic applications with due care. Please carefully read all of the documentation, double-check your work, and seek second opinions and independent review of your code. Our documentation and API design aims to prevent easy mistakes from being made, but it is no substitute for a good background in applied cryptography.

We have many safety features built into the language and the standard library is designed to be difficult to use incorrectly. I will address these concerns directly in a subsequent blog post covering the safety and security features of Hare.

The main problem is that some programmers view anything less than what Rust provides as morally unjustified.

3 comments

When you say you take security pretty seriously, and mention the Hare crypto module, are you talking about the crypto module which silently falls back to storing secure data on the heap when Linux keyctl is not present on the platform?

https://lwn.net/Articles/893327/

Yes. As I reiterated many times in that thread, having your data stored in the heap does not introduce any immediate vulnerabilities, and this behavior is thoroughly documented in the standard library.

It is possible for two people who both take security seriously to come away with different take-aways. Once some CVEs are found in Hare you might have some fuel for your argument, but until then it's just speculation.

Because rust inherently treats humans as fallible to a large extent. Which all of us are.

That introduction is simply an appeal to "I can write safe correct C." with more words. Which obviously is not true.

> Because rust inherently treats humans as fallible to a large extent. Which all of us are.

No it doesn't. It has a bypassable compile-time verified lifetime system, not an infallible programming guarantee. It leaves it entirely up to the developers to write correct and safe applications and libraries, and merely provides (powerful) tools to help.

(I realize this context was in avoiding common security bugs which are usually less likely in memory-safe languages, but it's important to not overstate the benefits.)

I think Rust kinda has a marketing problem: the myth that "Writing in Safe Rust automatically makes your code memory-safe". It doesn't (well, it does most of the time but it isn't guaranteed), but it rather defers the responsibility to other low-level system programmers writing Unsafe code behind the scenes. And oh boy they have a fuckton of responsibility... Stacked Borrows along with various sanitizers can help when writing unsafe code, but it isn't perfect. I highly recommend anyone trying out Rust for the safety guarantees to take a look at the Rustonomicon (https://doc.rust-lang.org/nomicon/), which debunks a lot of the misconceptions around safe/unsafe Rust.

In an ideal la-la land world, there exists an abstract interpreter that can consume safe Rust code and does not enforce any contracts upon the programmer (and hence will never have any undefined behavior). However, real world hardware definitely has contracts which developers have to obey (manually! because of the constraints of actual semiconductor physics! no compiler hand-holding here!). And on top of that all major OSes (Windows, MacOS, Linux) are written in C (so you need unsafe FFI to interact with the OS).

There seems to be a perception among Rust programmers that C's status as a defacto standard came to be in spite of C's contradictions, rather than as a result of them. Skimming the Rustonomicon just now left me with the impression that at least one Rust person gets it. Though it still seemed as if the author felt the need to choose their words very carefully, lest they "make the memory model people angry".
The memory model people are intense but really quite friendly :) Here's a great recent post: https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html
exactly. if i'm writing safe rust and encounter memory safety issues, their origin is with my dependencies, and my responsibility is limited to having chosen such dependencies.

In practice, this makes vulnerabilities in eg. argument parsers (like the recent "baron samedit" vulnerability in sudo) incredibly unlikely.

> the myth that "Writing in Safe Rust automatically makes your code memory-safe"

Of course you're right that that isn't true as stated, but I think it's interesting to try to situate this point along a continuum of other similar points:

1. C with Valgrind and sanitizers isn't always memory safe, because those tools are limited by test coverage.

2. Python isn't always memory safe, because many libraries including the standard library call into C code.

3. Pure Python that doesn't call into any C code isn't always memory safe, because the interpreter might have bugs.

4. Provably correct Ada with a provably correct compiler isn't always memory safe, because the proof checker, the compile-time hardware, or the runtime hardware might have bugs.

I think we all agree that there are important differences between 1 and 4, beyond the simple fact that the defects get less common as you go down the list. Here are some things that stand out to me:

- In cases #2 and below, the application code isn't "at fault" for any memory unsafety that comes up, and whatever code is at fault can be fixed to restore memory safety without changing the application.

- In case #1, there's no clear boundary in any sense between "safe code" (which we know isn't at fault for memory unsafety) and "unsafe code" (which might be at fault). There may be a distinction between code that's well covered by tests and code that isn't, for example, but it's often not easy to tell which is which. In case #2 and below, the boundary is pretty clear.

- In case #1, the amount of "unsafe code" in an application probably grows linearly with the size of the application, or maybe we just consider the whole application unsafe. But in cases #3 and #4, unsafe code is confined to low-level dependencies that get a lot of "battle testing" compared to how much code is in them. Case #2 is kind of a gray area, and we need to look at what dependencies the application is using.

So where should we situate Rust in that continuum? Is being able to write unsafe Rust code more or less risky than being able to call into C? It's certainly a lot more convenient to write an `unsafe` block than to cross the FFI barrier, and maybe that convenience is dangerous. On the other hand (contrary to some common misconceptions), unsafe Rust still benefits a lot from the borrow checker and other safety features, and it might end up having a lower rate of defects for that reason. Maybe it's too early to tell?

But anyway yes, I totally agree that the Rust community has a hard time getting the messaging right about how safe code and unsafe code work. But even though this discussion is really important to Rust, I'm not sure it's a "Rust problem" per se. I think it's actually quite difficult to talk clearly and correctly and precisely about memory safety in general.

http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=rust

"use-after-free", "data race", "memory corruption", "out-of-bounds write", "read from uninitialized memory", "execute arbitrary code"...

This list is actually quite interesting for a few reasons.

One is that a large fraction of these security issues are not real, potentially exploitable vulnerabilities, but merely the fact that it is possible to abuse an API to subvert Rust's safety guarantees. These are things would, by the standards of other programming languages, not be worth even reporting and be considered user error.

The other is that a surprisingly large fraction of these are not from regular unsafe Rust code, but from misunderstanding the guarantees a C library makes when creating bindings for it. This is to be expected, as fully understanding those as a library is pretty difficult.

A total of one memory safety issue reported for an entire ecosystem this year so far also seems pretty good.

All in all, I think these are both pretty promising signs that the safety guarantees Rust provides working as intended.

Wait, that's all? On the entire Rust ecosystem those are the only ones found?

Everybody already knows Rust has unsafe blocks and C FFI. It is not invulnerable to those problems, Rust just makes it very clear where those problems may appear, and if you are smart, you will place most of your code outside of those regions.

Looks like Rust is much safer on practice than what I expected.

Note that unsafe does not contain anything. The problem propagates to the unsuspecting caller of claimed safe code.

Ending up compromised by a problem in tokio, Pin semantics, actix or all the necessary ffi bindings is no different than, say, a C program being compromised by a vulnerability in OpenSSL or libcurl.

A very significant number of memory issues in C stemmed from issues in such single high-profile dependency, so one should not undermine the threat of a bit of unsafe code in the corner of a library.

Not being perfect does not translate to not being better. Being safe by default and having compiler-enforced safety as a top design choice is great.

Rust is better.

It's very much human nature to trace the line in the sand juuuuuust right behind one's heels though, depicting everyone behind as bad and everyone ahead as zealots.

Yes, unsafe marks the places where your code must be correct no matter what. If it's wrong, the problems can appear anywhere.

That's very different from environments where all code must be correct no matter what. But the impact of bugs isn't what changes.

Well... if you consider the proportion of "lines of code (or projects) ever written in the history of a language" over "security issues found" then Rust will be probably losing.
A lot of those bugs are in C code...
You don't know what you're talking about re: security lol
I can assure you that Hare takes security more seriously than assuming the programmer is smart enough to do it right. I don't appreciate shallow takes which make unsympathetic judgements on the language which are not based in any understanding of how Hare actually works, and I've heard nothing but such takes for a week.
How does Hare prevent use-after-free, then? I'd welcome an explanation.
Hare does not prevent use-after-free, but it does prevent many other kinds of bugs which are common in C. I will go into greater detail in another blog post.
Rust has compile time checks that avoid one category of bugs out of many. It’s “safe” in a very narrow sense.
And that category of bugs (memory safety) is only avoidable if the unsafe code itself doesn't have undefined behavior (which responsibility is left to the programmer rather than the compiler). If unsafe code is compromised then it's still game over (hence the recent development of various tools/methods like Stacked Borrows in MIRI that checks potential errors outside the borrow checker, as well as various guidelines for developers to write safer unsafe code)

Safe Rust cannot ever cause undefined behavior, but Unsafe Rust can. The ultimate merit of Rust is that when you suspect any undefined behavior you only need to check the unsafe part, which is a much smaller percentage of your codebase (as opposed to C/C++ where you need to check the entirety of your code)

It is not enough to check your unsafe code for UB, you also need to make sure it does not violate the invariants Rust relies on to prove the safe code safe.
...which I consider as one of the bullet points in the list when checking UB in unsafe code.
????

Whatever that means lol

You mean the borrow checker? People are working on formally proving that, and have already done so for large subsets of the language.

They mean that in unsafe code, you have to adhere to some rules to prevent safe code from becoming unsafe.

In other words, incorrect code in "unsafe Rust" can cause safety issues that only appear when you use it in a certain way from "safe Rust".

a very narrow sense representing 70% of all security vulnerabilities at microsoft and google (self-reported). i'd say it's a class of vulnerabilities worth eliminating, especially when the "cost" is getting a competent and standard package manager and a general focus on correctness that ultimately increases developer productivity and ergonomics (compared with C++, IME)
I didn't mention Rust (beyond mentioning you discussed it). You seem very Rust obsessed.
Honestly, I don't blame him, after the onslaught he's been defending against in every other thread since Hare's launch. It's really embarrassing to see that side of the Rust community acting this way.