awnumar / memguard

Secure software enclave for storage of sensitive information in memory.
Apache License 2.0
2.49k stars 124 forks source link

proposal: minimise the amount of unmanaged memory #124

Open jpaskhay opened 4 years ago

jpaskhay commented 4 years ago

Is your feature request related to a problem? Please describe. Using guard pages has a tradeoff of taking up more unmanaged memory pages, which could be a potential concern in high traffic scenarios.

Describe the solution you'd like Would be nice if there was an option to skip use guard pages when creating LockedBuffers. Can obviously keep using them by default but allow the user to pass in an option to avoid them. Whether this is exposed as part of the Enclave related usage should be considered, but could probably be handled separately, if needed.

Describe alternatives you've considered Considered using Enclave, but in the expected traffic/usage patterns (cached keys, multiple concurrent users), it would likely lead to more unmanaged memory usage.

Additional context N/A

awnumar commented 4 years ago

I've thought about doing something like this, but for temporal benefits instead of spacial.

For the use-case you've specified perhaps we can add a Region structure:

type Region struct {
    pages [][]byte // array of page-sized blocks
    data  []byte   // reference to entire region
}

And then LockedBuffers can also export this perhaps, although it would trivially leak the canary if this was inadvertently passed somewhere, so maybe not.

Another solution I was thinking about is a Pool structure that is essentially a queue of byte slices acting like an allocator or a buffer pool. For performance reasons this is useful as it means we don't need to allocate three pages and set them up every time we need a 32 byte region, but it's also advantageous from a spacial perspective as a single LockedBuffer region can be split into N slices and added to this pool, retaining the guard pages but minimizing wasted space. Two birds with one stone.

awnumar commented 4 years ago

We could also implement a custom allocator that's backed by LockedBuffers. It's potentially the most versatile solution but also the most complicated.

awnumar commented 4 years ago

:: Adding a new container without guard pages

Proposal: Add a new LockedBuffer-like container which is essentially the same as a LockedBuffer but without the guard pages or canary.

For

Against

Conclusion: If we go with this then I would rather implement it in the core package. If not, it can very trivially be implemented by third-parties with the help of github.com/awnumar/memcall.

:: Adding a buffer pool implementation

Proposal: Add a queue/stack of fixed-size buffers that are backed by one or more LockedBuffer objects.

For

Against:

:: Implementing a custom allocator

Proposal: Implement a custom allocator that can be queried for N bytes and will return a byte slice N bytes in length, backed by some memory within a LockedBuffer.

For

Against

awnumar commented 1 year ago

Another solution: you can use memcall to allocate unmanaged memory regions of specific sizes, as well as mlock & mprotect them, and disable core dumps.