On Mon, Dec 12, 2022 at 09:12:15 +0000, Daniel P. Berrangé wrote:
On Fri, Dec 09, 2022 at 05:28:59PM +0100, Peter Krempa wrote:
> The contents of both 'secret' and 'base64secret' are part of
different
> buffers wich are not erased securely. Don't bother with virSecureErase*.
Again, just because other code isn't right, doesn't mean we should
delete this. Make the other buffer be erased securely instead.
In many cases such as this one the secret is formatted into a buffer
that may be realloc'd while it's being constructed while the secret is
inside.
Assume the following program, which "decrypts" a secret and writes it to
a file. The buffer used for the operation is reallocd() and cleared:
$ cat secret.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
char *buf;
const char *fragment1 = "STCSRNM";
const char *fragment2 = "EEATOOY";
char *buf2;
size_t i;
int b = atoi(argv[1]);
int fd = open("/dev/null", O_WRONLY);
char *r1;
char *r2;
buf = malloc(b);
buf2 = malloc(256);
memcpy(buf2, "somethingelse", strlen("somethingelse"));
for (i = 0; i < b; i++) {
if ((i % 2) == 0) {
buf[i] = fragment1[(i/2)%14];
} else {
buf[i] = fragment2[(i/2)%14];
}
}
write(fd, buf, b);
close(fd);
r1 = buf;
if (b != 1024)
buf = realloc(buf, 1024);
r2 = buf;
if (b != 666) {
for (i = 0; i < b; i++)
memcpy(buf + i, "X", 2);
}
memcpy(buf2, buf, 100);
getchar();
printf("r1: %p, r2: %p\n", r1, r2);
puts(buf);
puts(buf2);
}
Now see the following cases:
When I run it with a buffer > 1024 or the magic value 1024 when it's not
reallocated the result is:
$ ./a.out 1200 & sleep 1; gcore $! ; echo corestrings ; strings core.$! | grep SETE ;
rm core* ; fg
[1] 2832373
[1]+ Stopped ./a.out 1200
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Program received signal SIGTTIN, Stopped (tty input).
0x00007f6265553021 in read () from /lib64/libc.so.6
warning: target file /proc/2832373/cmdline contained unexpected null characters
warning: Memory read failed for corefile section, 4096 bytes at 0xffffffffff600000.
Saved corefile core.2832373
[Inferior 1 (process 2832373) detached]
[1]+ Stopped ./a.out 1200
corestrings
./a.out 1200
r1: 0x1a682a0, r2: 0x1a682a0
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
... but now if I run it with a smaller initial size:
$ ./a.out 150 & sleep 1; gcore $! ; echo corestrings ; strings core.$! | grep SETE ;
rm core* ; fg
[1] 2833245
[1]+ Stopped ./a.out 150
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Program received signal SIGTTIN, Stopped (tty input).
0x00007f8c366cd021 in read () from /lib64/libc.so.6
warning: target file /proc/2833245/cmdline contained unexpected null characters
warning: Memory read failed for corefile section, 4096 bytes at 0xffffffffff600000.
Saved corefile core.2833245
[Inferior 1 (process 2833245) detached]
[1]+ Stopped ./a.out 150
corestrings
jRE/EdAeTvO/OnSETECASTRONOMY
E/EdAeTvO/OnSETECASTRONOMY
E/EdAeTvO/OnSETECASTRONOMY
E/EdAeTvO/OnSETECASTRONOMY
E/EdAeTvO/OnSETECASTRO
E/EdSETECASTRONOMY
O/OnSETECASTRONO
E/EdSETECASTRONOMY
O/OnSETECASTRONO
E/EdSETECASTRONOMY
O/OnSETECASTRONO
./a.out 150
r1: 0xdbf2a0, r2: 0xdbf450
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Thus ... for buffers where realloc is in use, the attempt to clear it
afterwards is basically equivalent in not clearing the buffer before
freeing it.