Threads for saaramar

  1. 7

    Great blogpost. In general, I find Hubris really elegant and beautiful.

    The first thing I like is the isolation in architecture. To quote Cliff, Hubris has three points where it kind of unusual in its class, compare to other OSes:

    1. components are separately compiled and isolated from one another using the processor’s memory protection hardware. We refer to these isolated components as tasks.

    2. drivers run in unprivileged mode, outside the kernel, and are typically isolated in their own tasks.

    3. Hubris is an aggressively static system. The configuration file defines the full set of tasks that may ever be running in the application. These tasks are assigned to sections of address space by the build system, and they will forever occupy those sections.

    The second thing I like, is the use of Rust memory safety properties. Quote:

    _Because of this, we don’t need to restrict how each task is written under the hood. While most of Hubris itself and our application code is written in Rust’s safe subset, which grants immunity from common classes of memory usage errors, the unsafe subset of Rust is incredibly valuable, particularly when writing fast drivers, or doing things like DMA. While code using unsafe Rust is still significantly safer than C – for instance, array indexing is still checked and integer overflows are still caught – it has access to operations that suppress those checks, and so it has the ability to corrupt any memory it can reach if it works hard enough. The combination of encouraging (but not requiring) safe Rust, while using memory isolation as a backstop, gives us a lot more flexibility without any loss of system-level safety.

    Which is not to say things never go wrong – just that, when they do, it is not typically a memory safety issue. It is far more likely to be a misread of a component datasheet, a subtle interaction between two tasks, or a plain-old logic error. In these cases, we break out Humility._

    I’m also excited about how Hubris relies on Rust’s references and borrowing for across task boundaries: _In Rust, references represent borrowed data, which comes from somewhere else, possibly your caller’s stack. References are analyzed, at compile time, by the compiler to check that code that operates on borrowed data will stop operating on it before returning. In general, it’s legal to pass references to borrowed data down into functions you call, and then operate on it after the function has returned, because you can rely on the compiler to ensure that that function hasn’t secretly hung onto a reference.

    The Hubris lease mechanism extends this function-to-function borrowing mechanism across task boundaries._

    A lot of the text was copied from here:

    1. 2

      Absolutely fantastic work. Also, I really like all the information the author shared during this journey.

      It’s also nice to see this great property: “A nice aspect of this race condition is that if you only hit the difficult race (close() the FD and run unix_gc() while dup() is preempted between FD table lookup and refcount increment), no memory corruption happens yet, but you can observe that the GC has incorrectly removed a socket buffer (SKB) from the victim socket. Even better, if the race fails, you can also see in which direction it failed, as long as no FDs below the victim FD are unused:”

      This kind of “side-channel” is beautiful in my opinion. I like it how in many cases we can get information regarding what happened via return values.

      1. 1

        Does this translate to a FreeBSD kernel bug? It’s my understanding the switch kernel is derived from the FreeBSD kernel.

        1. 3

          It’s not.


          There was this rumor it was running FreeBSD, and everyone was asking, “Does it run…” No. It doesn’t run it and stop asking.

          Instead it runs a custom microkernel called Horizon that’s been in development at Nintendo since the 3DS.

            1. 2

              The copyright notice is required if they copy any code from the FreeBSD kernel. My understanding is that, as with a lot of other systems, they bundle the FreeBSD network stack, but the rest of the kernel is not FreeBSD.

              1. 3

                My apologies, I joined yesterday and didn’t see that. I assumed someone shared it already, but did not find it :) Thanks for pointing this out! :)

              1. 4

                I would be happy to see more CHERI everywhere, so such classic bugs (in this case, a straightforward OOB write; a simple buffer overflow) won’t be exploitable. Especially when it’s in the TCB.

                1. 1

                  New changes re-introduce MTECheckedPtr into the machinery of PartitionAlloc.It’s interesting to keep track of how memory allocators adopt memory tagging.

                  1. 1

                    I can’t really tell from this commit in isolation what it’s doing. What is MTECheckedPtr? The commit message doesn’t really tell me anything useful.

                    1. 1

                      Sorry, more details below.

                      First of all, let me add here the link to this document, which has the definitions and overview of the design [0].

                      MTECheckedPtr is a proposal for the implementation of MiraclePtr (covered here [1]). I didn’t see yet a public documentation/full code for MiraclePtr, but the existing sources say it’s a generic term for a set of algorithms aim to mitigate exploitation of UAFs (not sure about all temporal safety issues in general, they specifically mention UAF). These algorithms are based on “smart-pointer-like” wrappers (and here I have many unanswered questions – how would the adaptation would look like? is this fully compatible with existing code? etc.).

                      The implementation of MTECheckedPtr is very similar to the concept of hardware MTE, but it does not use that as far as I can see.

                      // Note: cast means reinterpret_cast.
                      template<typename T>
                      class MTECheckedPtr {
                        MTECheckedPtr(T* ptr) {
                          uint64_t tag = GetTag(ptr);
                          // Use the upper 16 bits to memorize the tag.
                          encoded_ptr_ = (tag << 48) | cast<uintptr_t>(ptr);
                        T* operator->() {
                          uint64_t tag = GetTag(decoded_ptr());
                          // The returned pointer has the upper 16 bits set to 0
                          // (and thus the pointer dereference works) only when the tag matches.
                          return cast<T*>((tag << 48) ^ encoded_ptr_);
                        uint16_t GetTag(T* ptr) {
                          uintptr_t address = cast<uintptr_t>(ptr);
                          // Round down the address to the 2 MiB boundary
                          uintptr_t page_base = address & ~((1 << 20) - 1);
                          uint64_t offset = address & ((1 << 20) - 1);
                          return *cast<uint16_t*>(page_base + BITMAP_BASE + (offset / 16) * sizeof(uint16_t));
                        T* decoded_ptr() {
                          // The lower 48 bits are the real pointer.
                          return cast<T*>(encoded_ptr_ & 0x0000ffffffffffff);
                        uintptr_t encoded_ptr_;

                      I’m very curious about solutions for temporal safety issues, especially when it’s fully software. Personally, I believe we should take advantage on new silicon features for such solutions (this will help us get much better perf and security guarantees). So, I’m looking forward to see how this work will look like eventually, and which bug-classes it will actually mitigate (and how). I shared it here because I believe tracking such projects is interesting and we could have interesting discussions about it :)

                      [0] [1]

                  1. 1

                    (I’ve seen a prior submission about this here with a non-existing link, so I’ve submitted the new one :) )

                    1. 2

                      Yup. It looks like Microsoft’s BlueHat IL YouTube channel might have deleted and re-uploaded the video, causing a new URL to be created.

                      1. 2

                        Thanks for posting it again, I must have missed the first one.

                      1. 2

                        At BluehatIL 2022 I’ve presented my MTE research. It was on behalf of work in MSRC, with collaboration with MSR and partners. The talk covers the overview of the extension, applications, security properties, and practical examples. I’ll be more than happy to discuss the materials :)

                        Slides are here: