Announcement

Collapse
No announcement yet.

BoringTun v0.4 Released For CloudFlare's Rust-Based WireGuard

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #11
    Originally posted by bug77 View Post

    Binding to C code is why unsafe was introduced in the first place. And probably the only place t should ever be used.
    I am aware that but the point I was trying to make is that, the unsafe marker is because in C you don't have a way to verify the safety, that doesn't mean it is automatically insecure, just that the compiler can't make the determination because the C language wasn't built around any strict notions of ownership. However whatever security vulnerability is there isn't caused by the binding, the binding is just the exposure point.

    Comment


    • #12
      Originally posted by RahulSundaram View Post

      I am aware that but the point I was trying to make is that, the unsafe marker is because in C you don't have a way to verify the safety, that doesn't mean it is automatically insecure, just that the compiler can't make the determination because the C language wasn't built around any strict notions of ownership. However whatever security vulnerability is there isn't caused by the binding, the binding is just the exposure point.
      Right, but even if the C code is correct, you can still do nefarious stuff inside the unsafe block. Perhaps something as innocuous as making the wrong call or sending the wrong parameters. Of course, when thigs go wrong, the unsafe block itself dramatically reduces things that must investigate.

      Comment


      • #13
        Originally posted by bug77 View Post

        Right, but even if the C code is correct, you can still do nefarious stuff inside the unsafe block. Perhaps something as innocuous as making the wrong call or sending the wrong parameters. Of course, when thigs go wrong, the unsafe block itself dramatically reduces things that must investigate.
        So it's still not the binding that is the issue, just that general lack of safety guarantees if you use the unsafe block and you are forced to use it because you are connecting to another language which can't offer that kind of guarantees and has a weaker type system.

        Comment


        • #14
          Originally posted by bug77 View Post

          Binding to C code is why unsafe was introduced in the first place. And probably the only place t should ever be used.
          This is incorrect. Unsafe is required for many low level things. In low level programming Unsafe is a requirement for most interfacing with the underlying hardware, for example accessing status register values.

          I'm a big fan of Rust and their philosophy but people who tend to do things on the high level only get this odd impression that unsafe is this forbidden niche part of the language mostly just for C FFI. That's just not true.

          Comment


          • #15
            Originally posted by RahulSundaram View Post
            Do you have an example of C <-> Rust language binding causing security issues that wasn't otherwise an inherent security vulnerability?
            Most security vulnerabilities due to the unsafe { } tags are usually due to this binding with C. There are a number of examples around on how to exhibit (and luckily in many cases mitigate) against it.

            If you want to find specific examples, perhaps check out a number of Rust memory checking tools. Here is one from 2021: https://www.micahlerner.com/2021/10/...tem-scale.html

            264 memory safety bugs and 76 CVEs.

            There is also Miri: https://github.com/rust-lang/miri#bugs-found-by-miri

            You could argue that these bugs aren't really Rust's fault. It is where it connects to C that the problem arises. I absolutely agree but it *does* need to connect to C. There is no way around that if you plan to do anything useful with Rust. This unfortunately is a slight weakness of Rust (and every other language that is not C. Even C <-> C++ bindings can be a main source of memory issues if the order of deletion from RAII is not carefully considered).

            Originally posted by RahulSundaram View Post
            In any case, that doesn't seem to apply here, BoringTun is a pure Rust implementation although it does offer bindings to be called from C which itself is safe to do.
            This potentially demonstrates a slight misunderstanding of how crucial C is to... well everything. Rust can't access anything in POSIX, sys/*.h, sys/socket.h, netinet/in.h or anything like that without going through C. So even though the implementation is pure Rust, there are many, many cases where bindings are needed against C and the underlying system. You can't implement a userland version of wireguard without accessing the TCP stack (API in C)!

            The question is, which one is safer?

            1) Rust being the safer language but losing type safety "around the edges" of the underlying system
            2) C bring a less safe language but keeping type safety and simplicity when interacting with the underlying system

            Both remain to be seen. Rust is still relatively young but projects such as BoringTun are the best way to get a feel for which approach is ultimately better.

            Of course if a platform could be developed from the ground up in Rust (i.e RedoxOS is very close), then I do believe Rust to be the clear winner. However in mixed environments, everything is so much messier when interweaving different languages.
            Last edited by kpedersen; 08 March 2022, 01:47 PM.

            Comment


            • #16
              Originally posted by kpedersen View Post

              The question is, which one is safer?
              I am going to skip past the rest because that boils down to an illustration that language impedance mismatch is necessarily messy but I don't think this particular question is as seemingly as much up in the air, there are several major organizations already using mixed language environments including Rust and the evidence all points clearly in one direction, academic research that demonstrated that with prior art languages like Cyclone would still be relevant here.

              Comment


              • #17
                Originally posted by kpedersen View Post

                You could argue that these bugs aren't really Rust's fault. It is where it connects to C that the problem arises. I absolutely agree but it *does* need to connect to C. There is no way around that if you plan to do anything useful with Rust. This unfortunately is a slight weakness of Rust (and every other language that is not C. Even C <-> C++ bindings can be a main source of memory issues if the order of deletion from RAII is not carefully considered).
                Everything you can write in C, you can write in Rust. Pretty much the same as with Go, where you can entirely disable CGO. Libs would need to go out of their way of course, but you don't need to ever call C code. As long as you statically link, the only calling conventions you need to keep are the ones that interact with the kernel in one way or another (process bring up, syscalls, etc). Note you need to use unsafe to send the int 80h call. But it's still no C.

                Originally posted by kpedersen View Post
                You can't implement a userland version of wireguard without accessing the TCP stack (API in C)!
                You absolutely can. What really matters is the syscalls. Syscalls aren't just a regular C call, you set some registers (and IIRC stack data?) and send an interrupt. You can do all that in pure Rust. All POSIX implementations are essentially wrappers around syscalls, there's no magic that forces you to go through their APIs.

                EDIT: and a nit, WireGuard uses UDP, not TCP. You should never, ever, use TCP for encapsulation of IP unless you want catastrophic delays whenever a TCP-over-TCP packet is lost in transit.
                Last edited by sinepgib; 08 March 2022, 02:26 PM.

                Comment


                • #18
                  Originally posted by sinepgib View Post
                  As long as you statically link, the only calling conventions you need to keep are the ones that interact with the kernel in one way or another (process bring up, syscalls, etc). Note you need to use unsafe to send the int 80h call. But it's still no C.
                  You are certainly correct from a technical viewpoint but it is very unlikely that any implementation would do this. Developers will bind against C (libc and POSIX, system APIs). They will do this because it is still safer (and easier) than the direct alternative. So the safety is either limited by binding against C or an even less safe solution unfortunately.

                  Originally posted by sinepgib View Post
                  You absolutely can. What really matters is the syscalls. Syscalls aren't just a regular C call, you set some registers (and IIRC stack data?) and send an interrupt. You can do all that in pure Rust. All POSIX implementations are essentially wrappers around syscalls, there's no magic that forces you to go through their APIs.
                  Again, they wont implement it like this. They will go through libc and POSIX C API.
                  In fact, some operating systems don't even allow direct syscalls. I remember this occuring with golang and OpenBSD not too long ago (https://github.com/golang/go/issues/36435)

                  Originally posted by sinepgib View Post
                  EDIT: and a nit, WireGuard uses UDP, not TCP. You should never, ever, use TCP for encapsulation of IP unless you want catastrophic delays whenever a TCP-over-TCP packet is lost in transit.
                  Yes, good point I should have generalized it more. Actually, I wonder if it doesn't use raw sockets rather than even UDP. Admittedly not looked into it so much.

                  Originally posted by RahulSundaram View Post
                  I don't think this particular question is as seemingly as much up in the air, there are several major organizations already using mixed language environments including Rust and the evidence all points clearly in one direction, academic research that demonstrated that with prior art languages like Cyclone would still be relevant here.
                  To an extent, the fact that so much new code (underlying middleware and frontend GUI applications) is still commonly written in C does suggest that there are some reservations with safer languages vs some of the complexities (i.e bindings) they bring. I remember companies for decades telling us that Java was going to solve all this and it simply never did. No-one likes writing bindings via the JNI! So if this is still up in the air, I am not convinced that Rust is much better (Java does still outrank it in greenfield code I believe).

                  But... it is changing. Safety is becoming more of a focus (thankfully!). C++ is annoyingly focused on "zero overhead" and screw safety. Smart pointers are only half-safe and can still be made to dangle "this". So C++ is close but will never reach a satisfactory amount of safety. I am thankful for Rust to at least keep the pressure up in terms of safety.

                  My personal opinion is that the safe language that will come to save us all must be a superset of C rather than a new language entirely that needs bindings but admittedly this is simply an educated guess based on my experience. Perhaps if a tiny C compiler could be bolted onto Rust (similar to Zig and Golang) we might be close.
                  Last edited by kpedersen; 08 March 2022, 04:24 PM.

                  Comment


                  • #19
                    Originally posted by kpedersen View Post
                    Yes but no implementation would do this. It will bind against C. They will do this because it is still safer than the alternative. So the safety is either limited by binding against C or an even less safe solution unfortunately.
                    I fail to see how it would be an even less safe solution. You can make the implementation that way. The Go runtime does implement everything from scratch in Go, except from some DNS resolution that gets slightly more limited if you choose not to use the libc. So I don't see why the Rust stdlib would be so strongly opposed. Note I'm not saying apps themselves would be explicitly using the syscall interface, but the runtime. They would just use the crates.

                    Originally posted by kpedersen View Post
                    Again, they wont implement it like this. They will go through libc and POSIX C API.
                    In fact, some operating systems don't even allow direct syscalls. I remember this occuring with golang and OpenBSD not too long ago (https://github.com/golang/go/issues/36435)
                    Interesting. It _does_ make the exception for statically linked binaries such as what Rust does by default tho.

                    Originally posted by kpedersen View Post
                    Yes, good point I should have generalized it more. Actually, I wonder if it doesn't use raw sockets rather than even UDP. Admittedly not looked into it so much.
                    I haven't read the code, but I bet it uses UDP because that's how wg is specified and there's no advantage in using raw packets in userspace over UDP if you still transfer the latter. On the contrary, you either need to _additionally_ install a filter (now requiring a privileged service in many systems) or get a huge performance drop by reading pretty much everything that comes through your card into your userspace process. Besides, I'm not entirely sure you don't need privileges just to open the raw socket (and won't check, because this isn't really our core discussion).

                    Originally posted by kpedersen View Post
                    My personal opinion is that the safe language that will come to save us all must be a superset of C rather than a new language entirely that needs bindings but admittedly this is simply an educated guess based on my experience. Perhaps if a tiny C compiler could be bolted onto Rust (similar to Zig and Golang) we might be close.
                    A superset of C cannot be made safe. The moment you can build C as is, you can build unsafe code. You can make easier to do the right thing by extending C, but you can't make C inherently safer by doing that. If you want safety, you _need_ to make unsafe code explicit to the compiler, and that necessarily breaks most C code.

                    Comment


                    • #20
                      Originally posted by sinepgib View Post
                      A superset of C cannot be made safe. The moment you can build C as is, you can build unsafe code. You can make easier to do the right thing by extending C, but you can't make C inherently safer by doing that. If you want safety, you _need_ to make unsafe code explicit to the compiler, and that necessarily breaks most C code.
                      Or, to put it another way, making C safe requires so many additional annotations to give the compiler the information it requires to do its job that you end up with "just as incompatible/alien as Rust, but much uglier and more awkward from the attempt to remain 'technically C'".

                      Comment

                      Working...
                      X