Comment by sshine

Comment by sshine 10 days ago

15 replies

> Therefore Go is not a memory safe language.

Interesting.

To quote the NSA [1], "Some examples of memory safe languages are Python, Java, C#, Go, Delphi/Object Pascal, Swift, Ruby, Rust, and Ada. Memory safe languages provide differing degrees of memory usage protections, so available code hardening defenses, such as compiler options, tool analysis, and operating system configurations, should be used for their protections as well."

The narrow definition of memory safety here is:

Go has garbage collection, so you won't have memory leaks or use-after-free.

Go is powerful enough that beginners can cause segfaults by accidentally abusing internals, okay.

I'm not sure this is a very redeeming property of Go: Being able to crash the GC, without the flexibility of manual memory management.

But I'm not sure I'd categorize it as "not memory safe" for the same reason C/C++ aren't (a trade-off).

Because I don't believe that you can generally leverage this for the kinds of memory exploits made in C/C++.

I recall that some ML dialects (Standard ML and OCaml) have a library function Obj.magic : 'a -> 'b which escapes the type system. Using this can easily cause segfaults. Does that mean Standard ML and OCaml are not memory safe? Generally, no, they're extremely safe if you avoid that feature, which is most likely. This is arguably less safe than Go, since you most likely won't accidentally run that function.

[1]: https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI...

kccqzy 10 days ago

I'm trying to provide some commentary to OP's original term of "ordinary code" three comments above. While this term is inherently ambiguous and subjective, my personal opinion is that appending to slices simultaneously from multiple goroutines count as "ordinary code" but Obj.magic does not.

  • consteval 9 days ago

    I don't think that's ordinary code. In any language, if you don't use a thread safe container and mutate it from multiple threads you'll get problems. This isn't an issue of memory safety but rather thread safety. You have to check the documentation for thread safe operations or otherwise use a lock. This goes for C#, Java, Go, you name it - the one singular exception being Rust. But, even Rust does not fully get around it.

    • kccqzy 9 days ago

      You missed the point.

      > In any language, if you don't use a thread safe container and mutate it from multiple threads you'll get problems.

      Yes I agree there will be problems but what kind of problems do you get? Can you potentially get a memory safety problem, or are you guaranteed that the problem is not a memory safety problem?

      The point is that thread safety problems in Go lead to memory safety problems. That's not the case in Java. You can crash the whole Go program by doing that, but you cannot crash the JVM by doing the same thing.

      • yawaramin 9 days ago

        Crashing the whole program is actually memory safety. Because then the program can't get into an undefined state where parts of the program have access to memory they shouldn't.

  • [removed] 10 days ago
    [deleted]
  • kiitos 8 days ago

    Appending to slices concurrently, without synchronization, is unambiguously invalid code.

  • tptacek 10 days ago

    Yes. And: you will run into correctness bugs quickly if you mutate shared references in Go code. It's only my contention that you won't create a security vulnerability, in the colloquial understanding of the term (ie: a panic doesn't count).

    • tsimionescu 9 days ago

      You can, though it's much harder than in C or C++ or unsafe Rust for this to be exploitable. A data race on an interface value can give you a corrupted interface value, overwriting the vtable with struct contents. This can happen to lead to arbitrary code execution if you're unlucky enough, though in most cases it would be a SIGSEGV. It's also very hard for an attacker to craft a payload that can be guaranteed to reach this, though with a microservixe architecture with automatic restarts of failed services, they might get a lot of tries.

    • lll-o-lll 9 days ago

      If I can induce a race that corrupts a data structure so that it leaks data back to me that I shouldn’t have access to, does that count?

    • kaba0 9 days ago

      I mean, a very serious security vulnerability is/was row hammering, where an attacker was waiting on flipping a bit they have no access to by continuously flipping neighboring ones. Compared to that a race condition is "trivial" to exploit.

Cthulhu_ 9 days ago

To add to Go being memory safe, it automatically blanks/zeroes memory, unlike C.

capitol_ 9 days ago

Could you share more of your thoughts on why that kind of memory corruption wouldn't be exploitable? Do go have something in place that prevents it?