Is it possible to use Ruby to specifically write to the kernel buffer?
I want to manage passwords securely. Here is what I have so far:
require “io/console”
require “stringio”
loop do
print “Please enter your passphrase:”
@password = “”
$stdin.noecho {$stdin.sysread(512, @password)}
puts @password
memstore = Thread.new {
start = Time.now.to_i
loop do
if Time.now.to_i == (start + 2) then
wipe = StringIO.new("\0" * @password.bytesize)
wipe.read(@password.bytesize, @password)
puts “password cleared”
break
end
end
}
end
It takes the password as input from the user, holds it in memory for
some period of time, and then overwrites it. It also doesn’t
echo when the password is typed in. This is great but I also want to
make sure the password is overwritten in the kernel buffer. Does anyone
have any suggestions? Really I would just like to be pointed in the
right direction :).
ruby rub [email protected] wrote:
It takes the password as input from the user, holds it in memory for
some period of time, and then overwrites it. It also doesn’t
echo when the password is typed in. This is great but I also want to
make sure the password is overwritten in the kernel buffer. Does anyone
have any suggestions? Really I would just like to be pointed in the
right direction :).
I don’t think there’s a good way to force this from userspace (in any
programming language).
Kernels will zero any memory it gives to userspace (via brk(2)/mmap(2)),
but kernels will internally reuse buffers any way it sees fit. Even if
you could clear the kernel memory right away (via custom kernel
module/syscall), you can’t guarantee hardware buffers
(keyboard/network/console/video card/etc…) are cleared.
ruby rub [email protected] wrote:
It isn’t possible to clear keyboard buffers? Wow this + lack of ability
to clear kernel buffers makes secure wipes of password from memory
impossible, how unfortunate. Are there bad ways to try to force it from
userspace?
Maybe there’s some ioctls, but hardly standardized. On the other hand,
if your kernel is buggy/compromised and not wiping memory when new
apps need it, I think you’re screwed anyways.
Machines for large financial institutions and businesses process
countless logins every day without explicitly wiping kernel/hardware
buffers.
I think your use of StringIO to wipe a buffer is secure enough ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
ruby rub [email protected] wrote:
It isn’t possible to clear keyboard buffers? Wow this + lack of ability
to clear kernel buffers makes secure wipes of password from memory
impossible, how unfortunate. Are there bad ways to try to force it from
userspace?
You need to define your goal rather precisely. Kernel code is trusted
code. You cannot protect kernel information from other kernel
consumers.
Whatever protection you can do can be subverted.
Freed pages are never assigned to user-mode processes without being
cleared, so that’s not an issue.
For USB keyboards, there is no “keyboard buffer” in the kernel. The
keystrokes come in one at a time in buffers that get reused, so you
won’t
get the whole password at one time.
The password might be stored in a lot of places in your process,
especially
if you use something like fgets to read it.
My goal is to remove all traces of the password from all memory, after a
certain period of time. I want it to be so removed from memory that even
if someone does a cold boot attack they will not be able to recover
traces of the password from the frozen physical memory, after the wipe
process. The password itself is used for the decryption of a private
asymmetric RSA key, which I also would like to make sure has no traces
left in memory, but I think and hope that OpenSSL takes care of this
itself…
Also is it possible to set the buffer to not be swapped out?
ruby rub [email protected] wrote:
Also is it possible to set the buffer to not be swapped out?
Kernel memory is unswappable (at least on Linux). You can probably hook
up mlockall() pretty easily via DL/FFI/Fiddle/C extension.
Using the finer-grained mlock() probably requires a C extension (and
mlock() probably won’t work with Rubinius, only MRI).
Eric W. wrote in post #1053030:
ruby rub [email protected] wrote:
It takes the password as input from the user, holds it in memory for
some period of time, and then overwrites it. It also doesn’t
echo when the password is typed in. This is great but I also want to
make sure the password is overwritten in the kernel buffer. Does anyone
have any suggestions? Really I would just like to be pointed in the
right direction :).
I don’t think there’s a good way to force this from userspace (in any
programming language).
Kernels will zero any memory it gives to userspace (via brk(2)/mmap(2)),
but kernels will internally reuse buffers any way it sees fit. Even if
you could clear the kernel memory right away (via custom kernel
module/syscall), you can’t guarantee hardware buffers
(keyboard/network/console/video card/etc…) are cleared.
It isn’t possible to clear keyboard buffers? Wow this + lack of ability
to clear kernel buffers makes secure wipes of password from memory
impossible, how unfortunate. Are there bad ways to try to force it from
userspace?
I have my password input and storage program all nice now (I think I
actually learned how to wipe the password from you when I was
researching it, although on a different forum!)…but if I can’t make
sure it isn’t in a kernel buffer or keyboard buffer then it seems almost
pointless to try to remove it from memory at all. And keeping sensitive
things floating around in memory indefinitely sure does not seem secure
to me ! :<
#######################################################
require “io/console”
require “stringio”
loop do
#Securely (noecho + stdin.sysread) obtains the password from the user
print “Please enter your passphrase:”
@password = “”
$stdin.noecho {$stdin.sysread(512, @password)}
print “\n”
#Wipe password from memory after user defined amount of time.
memwipe = Thread.new {
sleep(1)
wipe = StringIO.new(“\0” * @password.bytesize)
wipe.read(@password.bytesize, @password)
Thread.exit
}
end
Tim R. wrote in post #1053689:
Robert K. [email protected] wrote:
end
In a garbage collecting system, how could you possibly assume that the
location of “password” will not have changed in the interim?
I am not sure I understand what you mean by that. Do you mean that copy
on write might have the effect to keep the string still in memory
referenced through some other String instance? That could be. But that
is true for the original approach with StringIO - which is more
complicated - and suffers the same deficiencies. ![:slight_smile: :slight_smile:](https://www.ruby-forum.com/images/emoji/apple/slight_smile.png?v=12)
You don’t
have enough visibility into the “innards” to assume that.
Yes, that’s certainly true as long as you stay in Ruby land.
Indeed, I believe this is an unsolvable problem in a language like Ruby.
You’d have to do this all in C.
Probably so, yes.
Kind regards
robert
Robert K. [email protected] wrote:
end
In a garbage collecting system, how could you possibly assume that the
location of “password” will not have changed in the interim? You don’t
have enough visibility into the “innards” to assume that.
Indeed, I believe this is an unsolvable problem in a language like Ruby.
You’d have to do this all in C.
ruby rub wrote in post #1053018:
memstore = Thread.new {
start = Time.now.to_i
loop do
if Time.now.to_i == (start + 2) then
wipe = StringIO.new("\0" * @password.bytesize)
wipe.read(@password.bytesize, @password)
puts “password cleared”
break
end
end
}
I think there’s a simpler way to achieve wiping:
read
@password = …
wipe after 2 secs
Thread.new do
sleep 2
@password.replace("#" * @password.length)
end
Note though that for both approaches you need proper synchronization.
Kind regards
robert