-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Secure in memory data with libgcrypt #540
Comments
Hi @dol Thank you for reaching out. Protecting against memory analysis is something explicitly called out in our Thread Model: https://vaultproject.io/docs/internals/security.html as something that is not part of our model. |
@sethvargo Thx for the quick response. I was not looking at the thread model. Sorry. |
Hey @dol No problem 😄. If it's easy to implement, I don't see a reason why we can't use libgcrypt, so let's keep this open until we can do some research. |
👍 |
The library is brand new, but promising: https://github.com/libeclipse/memguard |
I took a look at it. Unless I'm missing something about the internals of the Go allocator, it doesn't really fix the problem. When you "move" data into one of these memguarded objects, you still are coming from a Go-allocated byte slice. Once that byte slice has been allocated, even if the memguard library attempts to zero/free it, you don't know when the garbage collector will actually free it or what it will do with the memory. This leaves you in the same boat as what we have right now in Vault where we attempt to zero out memory that contained very critical data but is not in use, but cannot guarantee that it is zeroed. Much of the rest of what it does (stack protection and so on) seem to be a requirement of allocating the memory outside of Go, so it's basically attempting to add back things Go already gives you. I'd love to be wrong about this, but as long as the memory originated in Go, I don't see how this really makes a difference over our current best-effort attempts to zero out memory. |
This is not true anymore. Memguard now uses system calls to manage memory, thereby bypassing the Go runtime completely. Have a look at awnumar/memguard#3 for more information. |
As far as I can tell it is still true, and I'm not the only one -- see golang/go#21865 for instance -- any Go code that touches the memory that memguard is managing is an easy way to have said memory be exposed outside of memguard. Maybe I'm missing something, but this seems to be the case even in the example program at https://godoc.org/github.com/awnumar/memguard -- you're getting a key allocated by memguard, but now anything I do with said key that results in a copy -- say, base64 it to return across the wire, or send it to Vault's barrier to be encrypted before saving to disk -- means that the key is now in Go's memory space as well as memguard's. You're shifting the problem, but not eliminating it. As a defense-in-depth approach it has merit, and could maybe have higher impact in specific, key parts of Vault, but simply peppering memguard around is not sufficient for "secure memory" in Go; plus, it makes it difficult to find the memory, but not impossible (the value is still in plaintext in memory). A much higher impact is likely to come from something like SGX where the value is actually encrypted in memory. It'll still have the same problems as memguard w.r.t. interfacing with Go code, but it's less reliant on obfuscation as opposed to actual cryptography. |
Well you have shifted your original point to something else. Originally, you mentioned that memguard allocates memory which is managed by the Go runtime. I pointed out that it is not true. As far as I understand, this is correct. But it is also true that whenever you make a copy, now again you are back to square one. However, I do see a line mentioning how to get a pointer to the underlying buffer. |
@agnivade I've expanded on my original point, not shifted it. I still maintain that this call: https://godoc.org/github.com/awnumar/memguard#LockedBuffer.Move requires memory allocated by the Go runtime -- the parameter to the function (the data to move into the container) is a Go-allocated byte slice. As a result, the sensitive data still lives in memory over which you have no control (as well as memory over which you do have control). And in either case the memory is still plaintext, even if memguard tries to obfuscate where it lives. Copies of slices made by underlying Go stdlib calls or other such code simply exacerbate the problem. |
libgcrypt has a cross platform support for protecting memory pages => gcry_malloc_secure
If I remember correctly a libraries could be linked statically with go. A libgcrypt go C-binding is missing at the moment.
The text was updated successfully, but these errors were encountered: