Remix.run Logo
tptacek 5 days ago

Right, the issue here is that the "Rust and Java sense" of memory safety is not the actual meaning of the term. People talk as if "memory safety" was a PLT axiom. It's not; it's a software security term of art.

This is just two groups of people talking past each other.

It's not as if Go programmers are unaware of the distinction you're talking about. It's literally the premise of the language; it's the basis for "share by communicating, don't communicate by sharing". Obviously, that didn't work out, and modern Go does a lot of sharing and needs a lot of synchronization. But: everybody understands that.

moefh 5 days ago | parent | next [-]

I agree that there are two groups here talking past each other. I think it would help a lot to clarify this:

> the issue here is that the "Rust and Java sense" of memory safety is not the actual meaning of the term

So what is the actual meaning? Is it simply "there are no cases of actual exploited bugs in the wild"?

Because in another comment you wrote:

> a term of art was created to describe something complicated; in this case, "memory safety", to describe the property of programming languages that don't admit to memory corruption vulnerabilities, such as stack and heap overflows, use-after-frees, and type confusions. Later, people uninvolved with the popularization of the term took the term and tried to define it from first principles, arriving at a place different than the term of art.

But type confusion is exactly what has been demonstrated in the post's example. So what kind of memory safety does Go actually provide, in the term of art sense?

tptacek 5 days ago | parent [-]

It's a contrived type confusion bug. It reads 42h because that address is hardcoded, and it does something that ordinary code doesn't do.

If you were engaged to do a software security assessment for an established firm that used Go (or Python, or any of the other mainstream languages that do shared-memory concurrency and don't have Rust's type system), and you said "this code is memory-unsafe", showing them this example, you would not be taken seriously.

If people want to make PLT arguments about Rust's correctness advantages, I will step out of the way and let them do that. But this article makes a security claim, and that claim is in the practical sense false.

ralfj 4 days ago | parent | next [-]

> It reads 42h because that address is hardcoded,

It is trivial to change this example into an arbitrary int2ptr cast.

> Go (or Python, or any of the other mainstream languages that do shared-memory concurrency and don't have Rust's type system),

As the article discusses, only Go has this issue. Python and Java and JavaScript and so on are all memory-safe. Maybe you are mixing up "language has data races" and "data races can cause the language itself to be broken"?

> If people want to make PLT arguments about Rust's correctness advantages, I will step out of the way and let them do that. But this article makes a security claim, and that claim is in the practical sense false.

This article makes a claim about the term "memory safety". You are making the claim that that's a security term. I admit I am not familiar with the full history of the term "memory safety", but I do know that "type safety" has been used in PLT for many decades, so it's not like all "safety" terms are somehow in the security domain.

I am curious what your definition of "memory safety" is such that Go satisfies the definition. Wikipedia defines it as

> Memory safety is the state of being protected from various software bugs and security vulnerabilities when dealing with memory access, such as buffer overflows and dangling pointers.

My example shows that Go does not enforce memory safety according to that definition -- and not through some sort of oversight or accident, but by design. Out-of-bounds reads and writes are possible in Go. The example might be contrived, but the entire point of memory safety guarantees is that it doesn't matter how contrived the code is.

I'm completely fine with Go making that choice, but I am not fine with Go then claiming to be memory safe in the same sense that Java or Rust are, when it is demonstrably not the case.

tptacek 4 days ago | parent [-]

The problem isn't that you couldn't hardcode a scarier value; it's that you have to demonstrate a plausible scenario in realistic code where an attacker controls both the value and the address it's written to.

While you're wondering why I keep claiming Go is a memory-safe language, you can also go ask the ISRG, which says the same thing I am at (checks notes) https://www.memorysafety.org/.

ralfj 4 days ago | parent [-]

> While you're wondering why I keep claiming Go is a memory-safe language, you can also go ask the ISRG, which says the same thing I am at

And yet Go violates the definition they give -- it doesn't prevent out-of-bounds accesses. (And just to be sure we're talking about the same thing, I'm specifically talking about Go here. All the other languages on their list are actually memory safe, as far as I know.)

> you have to demonstrate a plausible scenario in realistic code where an attacker controls both the value and the address it's written to.

So your definition of memory safety includes some notion of "plausible" and "realistic"? Neither https://www.memorysafety.org/docs/memory-safety/ nor Wikipedia have such a qualification in their definition. It would help if you could just spell out your definition in full, rather than having us guess.

4 days ago | parent | next [-]
[deleted]
HAL3000 4 days ago | parent | prev | next [-]

> So your definition of memory safety includes some notion of "plausible" and "realistic"? Neither https://www.memorysafety.org/docs/memory-safety/ nor Wikipedia have such a qualification in their definition. It would help if you could just spell out your definition in full, rather than having us guess.

This is a strawman argument, you're arguing semantics here. You're a smart person, so you know exactly what he means. The perception created by your article is that people shouldn't use Go because it's not memory-safe. But the average developer hearing "not memory-safe" thinks of C/C++ level issues, with RCEs everywhere.

Unless you can show a realistic way this could be exploited for RCE in actual programs, you're just making noise. Further down the thread, you admit yourself that you're in a PLT research bubble and it shows.

dcow 4 days ago | parent | next [-]

You definitely shouldn’t use Go, but it’s not because of the discussion in TFA. I jest, rhetorically.

Seriously, why are we bashing a researcher for being academic? This makes no fucking sense. Nobody claimed anywhere that people should stop using Go.

esoterae 4 days ago | parent | prev | next [-]

Did you not notice how this started over someone saying "That's not the definition of memory safety" and then prevaricating about the bush when asked to provide their definition? Your theory that this is an argument over semantics is correct, but not fully understood.

ralfj 4 days ago | parent | prev | next [-]

> The perception created by your article is that people shouldn't use Go because it's not memory-safe.

Uh, where exactly am I saying or implying that? I am, in fact, saying that Go is much closer to memory-safe languages than to C, safety-wise.

But I am arguing that the term "memory safe" should only be used for languages that actually went through the effort of thinking this problem through to the end and plugging all the holes through which memory safety violates can sneak in. Go is 99% there, but it's falling slightly short of the goal. I think that's a useful distinction, and I am disappointed that it is regularly swept under the rug, which is why I wrote this blog post. You are free to disagree, I never expected to convince everyone. But I think I gave some people some new food for thought, and that's all I can hope for.

hdevalence 4 days ago | parent | prev [-]

> you're arguing semantics here

Yes, semantics — what do things mean, exactly? — is the subject of the discussion here and is actually quite important in general.

tptacek 4 days ago | parent | prev [-]

You're just wrong about this. The ability to write contrived code that does an out-of-bounds write, or to induce crashes, doesn't violate the notion of "memory safety" as an ordinary term of art.

ralfj 4 days ago | parent | next [-]

Yeah I understand that that's how you like to use the term, you've been very clear about that. What I am curious about is whether that's just you. Because the source you gave last time, https://www.memorysafety.org/docs/memory-safety/, doesn't agree with what you are saying, and neither does Wikipedia.

I am honestly curious here. I am a PLT researcher so I am in a bubble where people use the term consistently with how I use it. You are the first person I meet (for some notion of "meet" ;) that uses the term differently. But without external sources it's hard to judge how wide-spread your definition (that you still haven't spelled out...) is.

tptacek 4 days ago | parent | next [-]

Again: my usage of the term is widespread enough that the ISRG uses it to refer to Go as well, as does, well, basically everybody else in the industry. I think you've just message-boarded yourself into believing this is a live debate. There is no sequence of words you're going to come up with to convince me that everybody is wrong when they say "Go is a memory safe language".

ralfj 4 days ago | parent [-]

You keep making arguments by assertion without giving sources, so :shrug: yeah this isn't going to go anywhere.

I think we actually agree on all of the factual points here, we just don't agree on how languages should be categorized/labeled according to their guarantees in both a theoretical and a practical sense, and that's largely a subjective matter anyway. So, happy to agree to disagree here.

Thaxll 4 days ago | parent | prev [-]

Go is memory safe, what do you think of: https://www.nsa.gov/Press-Room/Press-Releases-Statements/Pre...

U.S. and International Partners Issue Recommendations to Secure Software Products Through Memory Safety

They recommand Go among other language in their paper.

https://media.defense.gov/2023/Dec/06/2003352724/-1/-1/0/THE...

ralfj 4 days ago | parent [-]

Yeah, Go is often listed with memory-safe languages, I know that. And yet when people define memory safety, Go usually fails to satisfy that definition. That's why I was asking for a definition of memory safety that would include Go.

kiitos 2 days ago | parent [-]

I suppose Go's notion of memory safety is satisfied by forbidding pointer arithmetic, and, maybe somewhat transitively, preventing arbitrary out-of-bounds access to memory. It definitely satisfies this notion of memory safety. Maybe this notion of memory safety is not considered to be correct, or relevant, or whatever, by whomever. That's fine.

rowanG077 4 days ago | parent | prev | next [-]

Did you consider that the organization can be wrong?

> Memory safety is a property of some programming languages that prevents programmers from introducing certain types of bugs related to how memory is used. Since memory safety bugs are often security issues, memory safe languages are more secure than languages that are not memory safe.

That is the definition they give. Since Go does not "prevent programmers from introducing certain types of bugs related to how memory is used." it does not fall under this definition. They can list go as memory safe, but then either they disagree with their own definition or made the mistake of adding Go to that list. Memory safety is not a spectrum. You are either memory safe or unsafe. The spectrum is in the unsafety. Go is obviously less unsafe than C for example.

kiitos 2 days ago | parent [-]

> Memory safety is not a spectrum. You are either memory safe or unsafe.

if there is one takeaway from this discussion, i think it must be that memory safety does not have any single, commonly-accepted, or objective definition -- and that it is pretty obviously a spectrum, not a boolean

rowanG077 19 hours ago | parent [-]

I could agree to that if the people who claim it would at least put it in their definition. But as it stands it indeed is a boolean. You have to give a definition of something like:

"Memory safety denotes the degree to which a programming language guides and protects developers from memory‑related errors—ranging from minimal, manual checks to comprehensive static and runtime enforcement—through mechanisms like strong typing, ownership or borrow checking, and garbage collection."

And then also include modern C++ in their lists. because by all accounts it is memory safe by that definition.

zozbot234 4 days ago | parent | prev [-]

Then the "security" definition is totally useless, because even C can be memory safe. What about pointers, malloc(), free(), unchecked enums etc. etc.? Oh, those are just "contrived" language features you're not really supposed to use. You can write FORTRAN in any language!

tptacek 4 days ago | parent [-]

C is the archetypical memory-unsafe language. When you've reached the point where you're simultaneously arguing that C is memory-safe and Go isn't, you should recognize you've made a wrong turn somewhere.

zozbot234 4 days ago | parent [-]

My point with those comparisons is that you have not bothered to define a reasonable and verifiable standard for what counts as "contrived" code - which is what ultimately seems to determine whether a language is memory safe, according to your definition.

nicoburns 4 days ago | parent | prev | next [-]

You are however replying to thread where a Dropbox engineer calls it "a right of passage" to introduce such bugs to their codebase. Which suggests that it is by no means unheard of for these problems to crop up in real-world code.

tptacek 4 days ago | parent | next [-]

Again: introducing surprising correctness bugs? Crashing programs? Absolutely. I don't know how many different ways I can say that my concern here is the misuse of a security term of art. Dropbox engineers do not have as a rite of passage introducing or finding RCE vulnerabilities in Go code. Would that it were so! My job would be much more interesting.

zozbot234 4 days ago | parent [-]

> correctness bugs? Crashing programs? Absolutely.

Denial of service can absolutely be a security issue, as can any correctness bug if it leads to unintended behavior or corrupted data.

tptacek 4 days ago | parent [-]

If that's where we're at, where unhandled exceptions are the security issues we're hanging on, I'll consider my argument won.

zozbot234 4 days ago | parent [-]

That might be a reasonable argument if you were guaranteed an unhandled exception in this instance. Unfortunately that's not the case.

tptacek 4 days ago | parent [-]

If you could demonstrate something better than that, we wouldn't be arguing about the severity of DOS attacks.

samus 4 days ago | parent | prev | next [-]

Doesn't Dropbox write a lot of Python extensions in C for speedup?

pclmulqdq 4 days ago | parent [-]

Excuse me, but in this thread we are bashing go, not making logical arguments.

ioasuncvinvaer 4 days ago | parent [-]

What is the argument?

pclmulqdq 4 days ago | parent [-]

That Dropbox is very happy with unsafe languages despite the top-level comment.

blub 4 days ago | parent | prev [-]

Many FAANG & co engineers are overrated. If every new hire is introducing concurrency bugs in a Golang codebase, refactor, do better review and maybe use concurrency questions instead of leetcode.

I’ll take tptacek’s word over most FAANG type on such topics if we’re doing appeals to authority. The guy is very practical, unlike the Rust community which is incredibly focused on theoretical correctness instead of real-world experiences.

stickfigure 5 days ago | parent | prev | next [-]

I have recently come to the conclusion that everything I ever thought was "contrived" is currently standard practice in some large presently existing organization.

tptacek 5 days ago | parent [-]

Take that to the Apple bounty program with your crasher bug and tell them they should pay out as if you'd confirmed RCE, see how it goes. This is an engineering question; it's not about vibes.

It's not even always the case that corrupted data structures (or even pointers) in C code are exploitable. You need attacker control of data and where it goes in memory. It's far less often the case in Python or Go --- in fact, it's basically never the case. As evidence for that claim: the zero memory corruption RCEs in all of shipping Go code, of which there is a lot.

NitpickLawyer 5 days ago | parent [-]

Dunno about Apple, but goog sometimes pays out bugs that are "theoretical" in the way you describe. That is, you show that there's a bug somewhere, but you can't "reach" it from user data. They'll pay less than a PoC, obviously, but will pay. YMMV, etc.

jacquesm 4 days ago | parent | prev [-]

My own takeaway after looking at corporate codebases for four decades is that the state of the art in software development at banks, governments, insurance companies, airlines, health care and so on is such that I long for the time before the internet.

Sure, those mainframes from the 80's weren't bullet proof either. But you first had to get to them. And even if the data traveled in plain text on leased lines (point-to-point but not actually point-to-point (that would require a lot of digging), no multiplexing) you had to physically move to the country where they were located to eavesdrop on them, and injecting data into the stream was a much harder problem.

Ygg2 5 days ago | parent | prev | next [-]

> People talk as if "memory safety" was a PLT axiom. It's not; it's a software security term of art.

It's been in usage for PLT for at least twenty years[1]. You are at least two decades late to the party.

    Software is memory-safe if (a) it never references a memory location outside the address space allocated by or that entity, and (b) it never executes intstruction outside code area created by the compiler and linker within that address space.
[1]https://llvm.org/pubs/2003-05-05-LCTES03-CodeSafety.pdf
zbentley 5 days ago | parent | next [-]

Not GP, but that definition seems not to be the one in use when describing languages like Rust--or even tools like valgrind. Those tools value a definition of "memory safety" that is a superset (a big one) of the definition referenced in that paper: safety as preventing incorrect memory accesses within a program, regardless of whether those accesses are out of bounds/segmentation violations.

adgjlsfhk1 4 days ago | parent [-]

it's not, but for a very subtle reason. To prove memory safety, you need to know that the program never encounters UB (since at that point you have nothing known about the program)

Wowfunhappy 5 days ago | parent | prev [-]

...by that definition, can a C program be memory safe as long as it doesn't have any relevant bugs, despite the choice of language? (I realize that in practice, most people are not aware of every bug that exists in their program.)

cibyr 5 days ago | parent | next [-]

Can a C program be memory safe as long as it doesn't have any relevant bugs? Yes, and you can even prove this about some C programs using tools like CBMC.

Waterluvian 5 days ago | parent | prev | next [-]

This is way outside my domain but isn’t the answer: yes, if the code is formally proven safe?

Doesn’t NASA have an incredibly strict, specific set of standards for writing safety critical C that helps with writing programs that can be formalized?

okanat 5 days ago | parent | next [-]

There are safety recommendations / best practice standards like CERT. None of them will prevent you from making intentional looking but logically unsound memory unsafe operations with C and C++. The code can be very indistinguishable from safe code. The things that C and C++ allow you to do basically makes code written in those languages impossible to fully formally prove. Although there are subsets, the basic integer operations and primitive types are messed up with C. So without uprooting how basic integer and pointer types work, it is impossible to make C and C++ safer. Such change will make all C and C++ programs invalid.

C and C++ always defaults to minimum amount of safety for maximum allowance of the compiler interpretation. The priority of the language designers of them is keeping existing terrible code running as long as possible first, letting compilers interpret the source code as freely as possible second.

That's why many military and aerospace code actually uses much safer and significantly more formally verifiable Ada.

uecker 5 days ago | parent | next [-]

There is also a lot of formally verified in C.

spookie 4 days ago | parent | prev | next [-]

> impossible to formally prove

If you assume the entire lang, yes. If you use a large subset, no. Furthermore, compiler interpretation might actually be sane! There are more compilers out there than GCC, Clang or MSVC. I suspect many assumptions are being made on this claim.

Waterluvian 5 days ago | parent | prev [-]

Thanks for explaining that. It really fills in a lot for me.

arto 4 days ago | parent | prev [-]

https://david-haber.github.io/posts/the-right-stuff/

ratmice 5 days ago | parent | prev | next [-]

It just seems like a bad definition (or at least ambiguous), it should say "cannot", or some such excluding term. By the definition as given if a program flips a coin and performs an illegal memory access, are runs where the access does not occur memory safe?

Ygg2 4 days ago | parent | prev | next [-]

Sure. It can be. In the same way, a C program can be provably correct. I.e., for all inputs it doesn't exhibit unexpected behavior. Memory safety and correctness are properties of the program being executed.

But a memory-safe program != memory safe language. Memory safe language helps you maintain memory-safety by reducing the chances to cause memory unsafety.

tremon 3 days ago | parent | prev [-]

There is a huge difference between "a C program can be memory safe if it is proven to be so by an external static analysis tool" and "the Java/Rust language is memory safe except for JNI resp unsafe sections of the code".

socalgal2 5 days ago | parent | prev | next [-]

> But: everybody understands that.

Everybody does not understand that otherwise there would be zero of these issues in shipping code.

This is the problem with the C++ crowd hoping to save their language. Maybe they'll finally figure out some --disallow-all-ub-and-be-memory-safe-and-thread-safe flag but at the moment it's still insanely trivial to make a mistake and return a reference to some value on the stack or any number of other issues.

The answer can not be "just write flawless code and you'll never have these issues" but at the moment that's all C++, and Go, from this article has.

blub 4 days ago | parent | next [-]

This comment highlights a very important philosophical difference between the Rust community and the communities of other languages:

- in other languages, it’s understood that perhaps the language is vulnerable to certain errors and one should attempt to mitigate them. But more importantly, those errors are one class of bug and bugs can happen. Set up infra to detect and recover.

- in Rust the code must be safe, must be written in a certain way, must be proven correct to the largest extent possible at compile time.

This leads to the very serious, solemn attitude typical of Rust developers. But the reality is that most people just don’t care that much about a particular type of error as opposed to other errors.

zozbot234 4 days ago | parent | next [-]

> ... it's understood that perhaps the language is vulnerable to certain errors and one should attempt to mitigate them. But more importantly, those errors are one class of bug and bugs can happen. Set up infra to detect and recover.

> in Rust the code must be safe, must be written in a certain way, must be proven correct to the largest extent possible at compile time.

Only for the Safe Rust subset. Rust has the 'unsafe' keyword that shows exactly where the former case does apply. (And even then, only for possible memory unsoundness. Rust does not attempt to fix all possible errors.)

blub 3 days ago | parent | next [-]

Well yes, only in the safe subset, but the safe subset is the alpha and omega of Rust.

Woe to those that use unsafe, for the scorn of the community shall be upon them. :)

pclmulqdq 4 days ago | parent | prev [-]

A not-so-secret secret of Rust is that liberal use of 'unsafe' is pretty much required for certain classes of high-performance code.

aystatic 4 days ago | parent [-]

imo if you're sprinkling around `unsafe` in your codebase "liberally", you're holding it wrong. In general it's really not that hard to encapsulate most unsafety into a wide-contract abstraction; I’d argue where Rust really shines is when you take advantage of the type system and static analyzer to automatically uphold invariants for you

J_Shelby_J 4 days ago | parent | prev [-]

> This leads to the very serious, solemn attitude typical of Rust developers.

Opposite really. I like rust because I can be care free and have fun.

tptacek 5 days ago | parent | prev [-]

Again: if you want to make that claim about correctness bugs, that's fine, I get it. But if you're trying to claim that naive Go code has memory safety security bugs: no, that is simply not true.

saurik 5 days ago | parent | next [-]

I cannot find anyone in this thread (nor in the article) making the claim you are arguing against, though... the reason for the example isn't "this demonstrates all Go code is wrong", but merely that "you can't assume that all Go code is correct merely because it is written in Go"; now, most code written in Go might, in fact, be safe, and it might even be difficult to write broken Go code; but, I certainly have come across a LOT of people who are claiming that we don't even have to analyze their code for mistakes because it is written in Go, which is not the case, because people do, in fact, share stuff all over the place and Go, in fact, doesn't prevent you from all possible ways of writing broken code. To convince these people that they have to stop making that assumption requires merely any example of code which fails, and to those people these examples are, in fact, elucidating. Of course, clearly, this isn't showing a security issue, but it isn't claiming to be; and like, obviously, this isn't something that would be sent to a bug bounty program, as who would it even be sent to? I dunno... you seem to have decided you want to win a really minute pedantic point against someone who doesn't exist, and it makes this whole thing very confusing.

ngrilly 4 days ago | parent [-]

The terms correctness (from a PLT perspective) and safety (from a security perspective) are not equivalent and interchangeable. I see them mixed up too much in this discussion.

ralfj 4 days ago | parent [-]

PLT has used the term "type safety" for a very long time -- so "safety" does not imply a security perspective. And yes it is indeed very different from correctness. But the article doesn't claim that memory safety should imply correctness -- that would be ridiculous, obviously you can write buggy programs in memory-safe languages. The article claims that Go is not memory-safe.

ngrilly 4 days ago | parent [-]

I was referring to comments mentioning correctness and safety as interchangeable terms. The article doesn’t mix them up.

ralfj 4 days ago | parent [-]

Fair, I misunderstood then. :)

const_cast 3 days ago | parent | prev [-]

I'm not understanding - if you're able to produce segfaults by, presumably, writing to memory out of bounds, what's stopping a vulnerability? Surely, if I can write past an array's bounds, then I can do a buffer overflow of some sort in some situations?

dev_l1x_be 4 days ago | parent | prev | next [-]

> But: everybody understands that.

I had to convince Go people that you can segfault with Go. Or you mean the language designers with using everybody?

pclmulqdq 4 days ago | parent [-]

You can segfault in Rust, too - there's a whole subset of the language marked "unsafe" that people ignore when making "safe language" arguments. The question is how difficult is it to have a segfault, and in Go it's honestly pretty hard. It's arguably harder in Rust but it's not impossible.

ralfj 3 days ago | parent [-]

It's impossible in safe Rust (modulo compiler bugs and things like using a debugger to poke in the program's memory from the outside). That's the key difference.

Of course unsafe Rust is not memory safe. That's why it is called like that. :) Go has unsafe operations too (https://go.dev/ref/spec#Package_unsafe), and of course if you use those all bets are off. But as you will notice, my example doesn't use those operations.

blub 4 days ago | parent | prev [-]

The problem Rust has is that it’s not enough to be memory safe, because lots of languages are memory safe and have been for decades.

Hence the focus on fearless concurrency or other small-scale idioms like match in an attempt to present Rust as an overall better language compared to other safe languages like Go, which is proving to be a solid competitor and is much easier to learn and understand.

zozbot234 4 days ago | parent [-]

Except that Swift also has safe concurrency now. It's not just Rust. Golang is actually a very nice language for problems where you're inherently dependent on high-performance GC and concurrency, so there's no need to present it as "better" for everything. Nevertheless its concurrency model is far from foolproof when compared to e.g. Swift.

blub 3 days ago | parent [-]

But that’s bad news for Rust adoption… Worst case for Rust is it takes just some (not all) marketshare from C and C++, because Swift, Golang, Java, Python, TypeScript, etc have cornered the rest.