Tomb icon indicating copy to clipboard operation
Tomb copied to clipboard

Protect sensitive variables in memory (kernel keyring)

Open unparagoned opened this issue 8 years ago • 8 comments

I notice you reassign and unset the sensitive values. From what I can tell from memory dumps:

  • Reassigning values does not overwrite the memory location the previous value was stored at but creates an entry at a new memory address.
  • Also unset doesn't clear the memory so you can still see the previous content.

Also depending on implementation and environment reassigning before performing unset might do more harm than good.

Is there a better way to clear these values from memory? I'm more of a C guy so it took me a while to even view the memory address and contents of shell script. Let alone come up with a solution.

unparagoned avatar Dec 22 '17 11:12 unparagoned

Hi! thanks for your concern, you are right the practice of reassigning and unset is not proven. I can immediately think of two possible solutions, that must be verified reading C code:

  1. implementing a Zsh module in C that effectively overwrites the same memory address before free()
  2. verify that the tmpfs implementation overwrites the same memory address and then use that for sensitive variables

So far I've tried to steer out of using filesystem operations for sensitive data, but it may be a strategy. I am also not sure if the ASSUAN interface to gpg-agent offers some better solution.

jaromil avatar Dec 22 '17 11:12 jaromil

Yeh coming from c this is almost a no brainier, and at first glace reassigning and unset could seem almost a mirror to overwriting memory with another value and then running free but they aren't. I wasn't sure and so only out of curiosity I checked.

Am I right in thinking that the variables would only be stored on the heap? If so could you do something crude, like when trying to securely erasing a file from a ntfs filesystem, where they fill all the free space up a massive file of random data. So in essence after performing unset on everything else you fill the heap up with random data? No idea how well this would work, maybe the system would just give you more memory rather than have you overwrite existing memory you'll need to play about and test it.

unparagoned avatar Dec 22 '17 14:12 unparagoned

Yes, the values are stored in the HEAP. I believe that what you suggest here is too undeterministic as it really depends from the kernel implementation of memory management. Another idea on how to proceed about this is verify the typeset -H aka hidden flag for variables declared in Zsh: what is their implementation about? I use them in tomb because of expected behavior of Zsh in keeping them somewhat more secure, but haven't inspected their actual implementation and the user documentation is very short and vague and perhaps not concerned on safe deletion. Here below the contents of the documentation found on http://zsh.sourceforge.net/Doc/Release/Shell-Builtin-Commands.html


-h
    Hide: only useful for special parameters (those marked ‘<S>’ in
    the table in Parameters Set By The Shell), and for local
    parameters with the same name as a special parameter, though
    harmless for others. A special parameter with this attribute will
    not retain its special effect when made local. Thus after ‘typeset
    -h PATH’, a function containing ‘typeset PATH’ will create an
    ordinary local parameter without the usual behaviour of
    PATH. Alternatively, the local parameter may itself be given this
    attribute; hence inside a function ‘typeset -h PATH’ creates an
    ordinary local parameter and the special PATH parameter is not
    altered in any way. It is also possible to create a local
    parameter using ‘typeset +h special’, where the local copy of
    special will retain its special properties regardless of having
    the -h attribute. Global special parameters loaded from shell
    modules (currently those in zsh/mapfile and zsh/parameter) are
    automatically given the -h attribute to avoid name clashes.

-H
    Hide value: specifies that typeset will not display the value of
    the parameter when listing parameters; the display for such
    parameters is always as if the ‘+’ flag had been given. Use of the
    parameter is in other respects normal, and the option does not
    apply if the parameter is specified by name, or by pattern with
    the -m option. This is on by default for the parameters in the
    zsh/parameter and zsh/mapfile modules. Note, however, that unlike
    the -h flag this is also useful for non-special parameters.

jaromil avatar Dec 24 '17 11:12 jaromil

Yep in practice If someone has access to your system memory there isn't really going to be much you can do. You could go out your way and store the keys on CPU only, split and obsore them, etc. And it wouldn't be full proof. Plus if cryptsetup isn't using anything too fancy then it might be pointless spending ages hiding the key when your housekeeper leave the door unlocked and open.

The only proper solution is use thermite filled devices connected to a deadman switch to destroy the device and leave a 10ft hole in the ground. Since this is the only realistic solution I'll close this for now. (I'm new to github so not sure if I should be closing things but...)

I was curious why you used Zsh. I use live cd for finance and sensitive work and all the dependencies such as Zsh sort of made tomb a no-goer. But if there are security advantages in using it them I might have another look.

unparagoned avatar Dec 31 '17 06:12 unparagoned

Thanks. I think this is an interesting discussion to keep around so will re-open this issue in case someone spots it and has ideas. Also in general Tomb's documentation should always make very visible any known vulnerability, so I will soon provide a brief roundup of this conversation in KNOWN_BUGS - or if you like, feel free to contribute to it yourself, a good occasion to see how github pull-reqs work perhaps ;^)

About Zsh for me its a mix of choice and habit. I use it since my NetBSD times in the '90s because is lighter and more modular (had a plugin system already) and later on used it to write all dyne:bolic liveCD scripts because it allows for a more readable syntax and has a better handling of variable scoping. I guess I'll just stick to it all my life as I cannot help but write idiomatic Zsh scripts whenever I approach shell. I'm sorry this causes troubles, but then having read a bit of Zsh and of Bash code I really dislike the latter implementation: it is much more messy... it feelt a bit like when I read more recently tmux code vs screen's, if you know what I mean.

jaromil avatar Jan 02 '18 11:01 jaromil

One last remark, when you write:

Yep in practice If someone has access to your system memory there isn't really going to be much you can do.

I of course agree with this, meaning if one has "admin" access to system memory (from a BIOS backdoor as well from root access on OS level) there is little that can be done. But then we should set the bar for a reasonably possible protection which I propose as a goal for this conversation:

Make it impossible for a process running as the same user who opened the tomb to access the memory where the keys are temporarily stored. Also make sure that the key storage is absolutely temporary and correctly overwritten.

This would protect users with open tombs from running malicious processes that are trying to steal their keys in memory.

I am not sure this is already the case in cryptsetup, but ok since also the 2.0 came out there are more incentives to go read its code and find out.

jaromil avatar Jan 02 '18 11:01 jaromil

Here an interesting bit about kernel keyring from cryptsetup's 2.0 RC0 changelog:

* Use of kernel keyring

  Kernel keyring is a storage for sensitive material (like cryptographic keys)
  inside Linux kernel.

  LUKS2 uses keyring for two major functions:

   - To store volume key for dm-crypt where it avoids sending volume key in
  every device-mapper ioctl structure. Volume key is also no longer directly
  visible in a dm-crypt mapping table. The key is not available for the user
  after dm-crypt configuration (obviously except direct memory scan).
  Use of kernel keyring can be disabled in runtime by --disable-keyring option.

   - As a tool to automatically unlock LUKS device if a passphrase is put into
  kernel keyring and proper keyring token is configured.

   This allows storing a secret (passphrase) to kernel per-user keyring by
  some external tool (for example some TPM handler) and LUKS2, if configured,
  will automatically search in the keyring and unlock the system.
  For more info see Tokens section below.

https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-rc0-ReleaseNotes

jaromil avatar Jan 02 '18 15:01 jaromil

Update: the upcoming Tomb 2.6 release fixes support for cryptsetup 2.0 which does support the kernel keyring feature so we inherit this feature let's say.

jaromil avatar May 22 '19 08:05 jaromil