[HN Gopher] Memory safety is necessary, not sufficient
       ___________________________________________________________________
        
       Memory safety is necessary, not sufficient
        
       Author : weinzierl
       Score  : 54 points
       Date   : 2023-12-22 08:44 UTC (1 days ago)
        
 (HTM) web link (steveklabnik.com)
 (TXT) w3m dump (steveklabnik.com)
        
       | weinzierl wrote:
       | Regarding _" Now, I am not a politican, and these bills are huge,
       | so I wasn't able to figure out how these bills do this
       | specifically [..]"_, I think the relevant reference is on page
       | 864 of [1]:
       | 
       |  _" SEC. 1613. POLICY AND GUIDANCE ON MEMORY-SAFE SOFT- WARE
       | PROGRAMMING. (a) POLICY AND GUIDANCE.--Not later than 270 days
       | after the date of the enactment of this Act, the Secretary of
       | Defense shall develop a Department of Defense wide policy and
       | guidance in the form of a directive memorandum to implement the
       | recommendations of the National Security Agency contained in the
       | Software Memory Safety Cybersecurity Information Sheet published
       | by the Agency in November, 2022, regarding memory-safe software
       | programming languages and testing to identify memory-related
       | vulnerabilities in software developed, acquired by, and used by
       | the Department of Defense."_
       | 
       | The mentioned _" Software Memory Safety Cybersecurity Information
       | Sheet"_ is probably [2] which explicitly lists _" C#, Go,
       | Java(r), Ruby(tm), Rust(r), and Swift"_ as examples for memory
       | safe languages.
       | 
       | I'm still looking for the equivalent EU document and would be
       | grateful for any hints.
       | 
       | EDIT: I could not find any reference to memory safety in any of
       | the EU documents but interestingly the _" Impact Assessment
       | Report"_ [3] mentions Rust and Go specifically.
       | 
       | [1] https://www.armed-
       | services.senate.gov/imo/media/doc/fy24_nda...
       | 
       | [2]
       | https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI...
       | 
       | [3] https://ec.europa.eu/newsroom/dae/redirection/document/89545
        
         | steveklabnik wrote:
         | Thank you! I really appreciate it.
        
       | zelon88 wrote:
       | I don't think the government's goal in improving memory safety is
       | because of Rust or any other particular technology.
       | 
       | The government buys technology from wherever, and until recently
       | they never really cared where they got it from. If they need a
       | USB Emulator, they buy the same Chinese Gotek from Ebay that you
       | or I buy, and they get the same "Driver CD" full of buggy, broken
       | English software, written by one person for $27 over the course
       | of about 7 hours. Same thing with DVR systems, access controls,
       | network appliances, access points. I've worked on government
       | projects that were using 20 year old, broken, encryption
       | libraries on active web servers. And when brought to their
       | attention the people who use it don't care, and the people who
       | are capable of doing something about it will never find out
       | because it's too much work to replace and nobody wants to take
       | that Zoom call.
       | 
       | I think the author is getting a little over-excited about Rust.
       | Granted, they are a Rust developer. I'd love it if we could build
       | everything in my favorite language. But the government doesn't
       | want to replace everything with Rust. The government wants
       | results. Period. It is the DOD, NSA, and CISA who need to become
       | experts on how to realize those results. And they will probably
       | release guidance that says "if you can't program securely in a
       | memory unsafe language, don't use a memory unsafe language". The
       | thing I think the author is missing is that nobody is going to
       | mistaken "Made with RUST!" for "Impossible to cause undefined
       | behavior!"
       | 
       | You can be a terrible programmer and still create undefined
       | behavior, insecure code, data leaks, or any number of other
       | problems in a memory safe language.
       | 
       | What the government is going to do is implement strict code
       | import controls, similar to the export controls we already have.
       | Purchasing departments will have to get software purchases signed
       | off multiple times by qualified parties, and department leaders
       | will have to prove that the technology they procure is adequately
       | safe. In some situations I anticipate that means re-writing a
       | bunch of code in Rust, and in other situations I'm sure that
       | means hardening existing C. The majority of the government's
       | security holes that need to be patched are coming from low
       | quality unvetted imported technology, low quality self-written
       | code, and code that should have been replaced 20 years ago. While
       | it's exciting to think that this could mean a renaissance for the
       | author's technology of choice, I just don't see it working out
       | that way. If the government could write memory safe code, it
       | would have. Rust isn't safe ENOUGH to save the government from
       | itself alone.
        
         | alilleybrinker wrote:
         | Just a small clarification here. The author isn't just a fan of
         | Rust. Steve was a member of the Rust Core Team for years and
         | was co-author of the book "The Rust Programming Language,"
         | which is the main recommended introductory text for the
         | language.
        
           | zelon88 wrote:
           | I saw the authors credentials and I do respect them a lot.
           | But to be fair, I'm sure the person who wrote the Go manual
           | could have written the same blog post with the same outlook
           | for the future only with Go in place of Rust. I'm trying to
           | broaden the scope of conversation to a more holistic one,
           | rather than just "this is our chance to take over the world!"
           | 
           | Like my Gotek USB emulator reference. The device costs $50,
           | and it's pretty much the ONLY option you have for emulating a
           | floppy drive with a USB stick in a bunch of obsolete
           | hardware. The software that it comes with was written by a
           | Chinese high school student in C++ during a study break and
           | it is about as insecure and sketchy as you would expect it to
           | be.
           | 
           | If you're the government looking to buy this, your choices
           | are;
           | 
           | 1. Buy this sketchy retroft device that is insecure and may
           | be backdoored for a cost of $60.
           | 
           | 2. Replace whatever needs the retrofit for a cost of $2m.
           | 
           | 3. Write your own drivers for $100k.
           | 
           | Currently they just use the $60 device. The upcoming policy
           | changes will take that option off the table for a lot of
           | agencies, forcing them to make wiser purchasing decisions. It
           | doesn't automatically mean Rust wins the day, or that rust
           | deserves to win the day. It means intelligent conversations
           | must be had and difficult decisions have to be made that used
           | to get avoided.
        
             | alphager wrote:
             | Nobody is claiming that rust wins the day. Memory-safe
             | languages, of which rust is one of them, will get a boost.
             | That's it.
        
         | steveklabnik wrote:
         | > But the government doesn't want to replace everything with
         | Rust.
         | 
         | To be clear, I don't think that they do. To be honest, I am
         | mostly confused by your post, not because I disagree, but
         | because I am unsure how you came to the conclusion that I
         | believe these things.
        
           | brabel wrote:
           | Funny, because I came out with the almost opposite
           | impression: that perhaps the legislators will require
           | something stronger than even Rust to consider something
           | "safe" because Rust still allows easy access to things like
           | `unsafe` and FFI like most other languages - and true safety
           | may require more than that.
           | 
           | I think our biases, together with the lack of a firm
           | conclusion in this post, leaves the door open to vastly
           | different interpretations.
        
         | marcosdumay wrote:
         | Just like in every other kind of engineering, for software
         | capability pulls the requirements.
         | 
         | The only reason everybody is complaining about lack of memory
         | safety now is because there are alternatives for every use
         | case. Before Rust existed, it was seen as an inevitable issue
         | that one must work with, not as a problem to solve.
        
         | lowbloodsugar wrote:
         | lol. The government doesn't want results, unless the result is
         | siphoning as much public money into private pockets as
         | possible.
        
       | pornel wrote:
       | I think it's underappreciated that Rust's `unsafe{}` doesn't
       | exist in isolation. Rust has facilities for building safe
       | abstractions on top of it, and has a culture of taking this
       | abstraction layer seriously.
       | 
       | Danger of unsafe features and FFI is usually conditional -- you
       | can use a pointer only until some point, or only on a single
       | thread, etc. A use of unsafe in Rust doesn't become "be careful!"
       | kryptonite spreading around the program. It's possible to build
       | walls around it to contain it completely.
       | 
       | In Swift + unsafe or Java + JNI I've struggled building equally
       | solid abstractions around FFI. They don't have "you can call it
       | only once" or "you can't call go() after finish()" as a compile-
       | time check. They don't have "you can use it only within this
       | scope" (they may use a closure/callback to give access to an
       | unsafe object, but these aren't hermetic, so that's a convention
       | not a guarantee). Exposing objects to Swift or Java requires the
       | higher level language to be in charge of their lifetime.
        
         | mplewis9z wrote:
         | I haven't had a chance to fully explore the new features and
         | there are probably still some sharp edges, but the addition of
         | non-copyable types and borrowing/consuming bindings in Swift
         | 5.9 should bring it a lot closer to Rust in those respects,
         | especially the hermeticity aspect. If you haven't experimented
         | recently, might be worth doing - this is also one of the big
         | focuses of the language in the near term, so there should be
         | lots more progress coming too.
        
       | mannuch wrote:
       | I wonder what the author thinks about Swift's new C++ interop
       | story? Since the Swift compiler includes Clang, and can thus
       | compile both your C++ and Swift into LLVM IR, without the need
       | for an FFI later between the two, couldn't this be the
       | "Typescript for C++" that the author points out a space for? The
       | Swift folks are very much thinking about Swift as a C++ successor
       | that can be incrementally migrated to so I'm a bit surprised the
       | author didn't discuss it further -- especially given Swift's
       | spiritual similarities to Rust.
       | 
       | There's a couple great talks on this by folks on the Swift team.
       | 
       | John McCall at CppNow https://m.youtube.com/watch?v=lgivCGdmFrw
       | 
       | Konrad Malawski at StrangeLoop 2023
       | https://m.youtube.com/watch?v=ZQc9-seU-5k
        
         | steveklabnik wrote:
         | I do not know a ton about it. Thanks for the pointers.
         | 
         | I kept up with Swift more in the old days, but it doesn't seem
         | to have gained a ton of relevance outside of Apple platforms,
         | which I don't develop for. Doesn't mean that I think that it's
         | bad, just that that's why I haven't spent a lot of time with it
         | yet.
        
       | fweimer wrote:
       | I agree with the sentiment. Consider a hypothetical variant of
       | Python that requires using eval() (with the same behavior as in
       | Python, so full Python expression support) for converting from
       | strings to integers or floats. Or that implicitly calls eval() on
       | list subscripts, to turn strings into integers. None of these
       | changes impact memory safety, but it still makes it much more
       | likely that common code has security vulnerabilities. (There is
       | actually a widely used programming language with the eval-on-
       | subscript feature ...)
       | 
       | > While a Go program may exhibit what a Rust or C++ program would
       | consider undefined behavior, and it does also consider it an
       | error, the consequences are very different. You don't get time
       | travel. You get 998 instead of 1,000.
       | 
       | This isn't correct. Data races on multi-word objects of built-in
       | type, such as slices and interfaces, actually have undefined
       | behavior, in the sense that array bounds checking and type
       | checking may break down.
       | 
       | Russ Cox's old example still works if you disable optimizations:
       | https://research.swtch.com/gorace
       | 
       | It looks like some form of dead store elimination happens to
       | eliminate the data race with current compilers. For now, it's
       | possible to bring it back by adding a pointless atomic operation,
       | like this:                   go func(){           for !done {
       | k = i             atomic.AddUint32(&global, 1)             k = j
       | }         }()
        
       | lambdaone wrote:
       | Enforcing memory safety is good thing, even if it's not perfect;
       | it's the first stage in the long-needed move from throw-it-in-a-
       | bucket-and-hope-it-works "software engineering" toward proper
       | formal-methods-driven actual software engineering.
       | 
       | I feel complaining about it as insufficient is not the ideal way
       | to push things forward. Instead, let's treat the progress on
       | memory safety policy as a first victory in that process, and
       | build on it.
        
       | dgreensp wrote:
       | I think it's worth emphasizing that the C spec's love of
       | undefined behavior--if you do X by accident, anything can happen
       | --and the apparently massive amount of memory-unsafe software
       | that has been written that will just allocate 16 bytes on the
       | stack and then read from a file descriptor until it encounters a
       | null byte... are examples of things that aren't considered
       | remotely sane or reasonable to a modern programmer or language
       | designer. Any vague notion of "unsafe" in the context of a modern
       | language--like saying well, if there's a syscall, maybe something
       | unexpected could happen--doesn't compare to the bad decisions
       | made by C and C programmers/culture that affect us today because
       | we still use C code in our things.
       | 
       | The deep, idiosyncratic flaws of C trace back to "worse is
       | better." Few people remember or look up what "worse is better"
       | actually meant. Wikipedia wrongly says it's a "less is more" sort
       | of thing, and some people think it's about not being a
       | perfectionist.
       | 
       | But actually... actually actually, if you read the essay, it says
       | "worse is better" means (paraphrasing) it's _more important that
       | C compilers be easy to implement than easy to use_. Also, _it is
       | more important that the implementation--or the design of the
       | implementation--of a piece of software be simple than that it be
       | correct. It is more important that it be simple than that it be
       | consistent. It is more important that it be simple than that it
       | be "complete" (for example, handle edge cases; it just needs to
       | work in "most situations")._ This is not just anti-perfectionism,
       | it is an objectively terrible set of engineering values. But
       | there were so many different kinds of computers and operating
       | systems back then--you didn't even know if a byte was 8 bits--
       | that it helped a lot that C compilers could do whatever they
       | wanted in many situations. And making it easy for C compiler
       | implementers enabled C to spread far and wide. It was a very
       | different world, and just being able to write in a higher-level
       | language than assembly on a particular computer was a big deal.
        
       | angiosperm wrote:
       | Nobody has been able explain to me what would be lost if we
       | defined data races to yield one of the values that had been
       | written to the memory in the past, instead of being undefined. It
       | is not as if any optimizer can see that you are racing and delete
       | the code path that has it.
        
         | atq2119 wrote:
         | "One of the values written to memory" isn't really a thing when
         | memory accesses can tear (e.g. because the values are 16 bytes
         | large and are accessed using 8 byte memory ops). So it's not
         | even necessarily about what would be lost, it's about what can
         | be reasonably defined in the first place.
         | 
         | If you restrict yourself to relaxed atomic loads and stores --
         | i.e., memory accesses that are atomic in the sense that they
         | cannot tear, but don't have much in the way of ordering
         | guarantees -- then you do get "one of the values that had been
         | written to the memory in the past".
         | 
         | Aside from memory tearing, one other issue is that you
         | generally want to be able to rematerialize loads (i.e., in the
         | face of register pressure, you may want to turn one load of a
         | value into multiple loads instead of loading it once, then
         | spilling to the stack and reloading from the stack). But when
         | the compiler rematerializes a load, then you don't get "one of
         | the values written to memory". From the perspective of the
         | original program it looks like you get some weird superposition
         | of values.
        
         | Gehinnn wrote:
         | I'm pretty sure that you have either an undecidable problem or
         | a non deterministic piece of code that sometimes computes some
         | value, other times a different value, depending on how the
         | threads are scheduled. Neither is good.
        
       | amelius wrote:
       | Our programs are growing so big by having so many (indirect)
       | dependencies that we need a way to sandbox the libraries that we
       | include from our main programs. This is the type of safety that
       | I'm looking for, really.
        
       ___________________________________________________________________
       (page generated 2023-12-23 23:00 UTC)