Merge pull request #12965 from keszybz/auto-erase
_cleanup_(erase_and_freep)
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <malloc.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
@@ -78,6 +79,16 @@ static inline void* explicit_bzero_safe(void *p, size_t l) {
|
||||
void *explicit_bzero_safe(void *p, size_t l);
|
||||
#endif
|
||||
|
||||
static inline void erase_and_freep(void *p) {
|
||||
void *ptr = *(void**) p;
|
||||
|
||||
if (ptr) {
|
||||
size_t l = malloc_usable_size(ptr);
|
||||
explicit_bzero_safe(ptr, l);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use with _cleanup_ to erase a single 'char' when leaving scope */
|
||||
static inline void erase_char(char *p) {
|
||||
explicit_bzero_safe(p, sizeof(char));
|
||||
|
||||
+13
-16
@@ -718,7 +718,7 @@ int config_parse_macsec_key(
|
||||
|
||||
_cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
|
||||
_cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
|
||||
_cleanup_free_ void *p;
|
||||
_cleanup_(erase_and_freep) void *p = NULL;
|
||||
MACsec *s = userdata;
|
||||
SecurityAssociation *dest;
|
||||
size_t l;
|
||||
@@ -743,18 +743,17 @@ int config_parse_macsec_key(
|
||||
|
||||
r = unhexmem_full(rvalue, strlen(rvalue), true, &p, &l);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse key. Ignoring assignment: %m");
|
||||
return 0;
|
||||
}
|
||||
if (l != 16) {
|
||||
/* See DEFAULT_SAK_LEN in drivers/net/macsec.c */
|
||||
explicit_bzero_safe(p, l);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid key length (%zu). Ignoring assignment", l);
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse key. Ignoring assignment: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (l != 16) {
|
||||
/* See DEFAULT_SAK_LEN in drivers/net/macsec.c */
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid key length (%zu). Ignoring assignment", l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
explicit_bzero_safe(dest->key, dest->key_len);
|
||||
free_and_replace(dest->key, p);
|
||||
dest->key_len = l;
|
||||
|
||||
@@ -972,7 +971,7 @@ int config_parse_macsec_use_for_encoding(
|
||||
}
|
||||
|
||||
static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
|
||||
_cleanup_free_ uint8_t *key = NULL;
|
||||
_cleanup_(erase_and_freep) uint8_t *key = NULL;
|
||||
size_t key_len;
|
||||
int r;
|
||||
|
||||
@@ -987,12 +986,10 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
|
||||
return log_netdev_error_errno(netdev, r,
|
||||
"Failed to read key from '%s', ignoring: %m",
|
||||
sa->key_file);
|
||||
if (key_len != 16) {
|
||||
explicit_bzero_safe(key, key_len);
|
||||
|
||||
if (key_len != 16)
|
||||
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid key length (%zu bytes), ignoring: %m",
|
||||
key_len);
|
||||
}
|
||||
"Invalid key length (%zu bytes), ignoring: %m", key_len);
|
||||
|
||||
explicit_bzero_safe(sa->key, sa->key_len);
|
||||
free_and_replace(sa->key, key);
|
||||
|
||||
@@ -480,7 +480,7 @@ static int wireguard_decode_key_and_warn(
|
||||
unsigned line,
|
||||
const char *lvalue) {
|
||||
|
||||
_cleanup_free_ void *key = NULL;
|
||||
_cleanup_(erase_and_freep) void *key = NULL;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
@@ -501,12 +501,10 @@ static int wireguard_decode_key_and_warn(
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue);
|
||||
if (len != WG_KEY_LEN) {
|
||||
explicit_bzero_safe(key, len);
|
||||
if (len != WG_KEY_LEN)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Wireguard key provided by %s= has invalid length (%zu bytes), ignoring assignment.",
|
||||
lvalue, len);
|
||||
}
|
||||
|
||||
memcpy(ret, key, WG_KEY_LEN);
|
||||
return 0;
|
||||
@@ -894,7 +892,7 @@ static void wireguard_done(NetDev *netdev) {
|
||||
}
|
||||
|
||||
static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_KEY_LEN]) {
|
||||
_cleanup_free_ char *key = NULL;
|
||||
_cleanup_(erase_and_freep) char *key = NULL;
|
||||
size_t key_len;
|
||||
int r;
|
||||
|
||||
@@ -905,17 +903,11 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (key_len != WG_KEY_LEN) {
|
||||
r = -EINVAL;
|
||||
goto finalize;
|
||||
}
|
||||
if (key_len != WG_KEY_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(dest, key, WG_KEY_LEN);
|
||||
r = 0;
|
||||
|
||||
finalize:
|
||||
explicit_bzero_safe(key, key_len);
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wireguard_peer_verify(WireguardPeer *peer) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "main-func.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "log.h"
|
||||
@@ -34,66 +35,49 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_free_ char *packet = NULL;
|
||||
static int run(int argc, char *argv[]) {
|
||||
_cleanup_(erase_and_freep) char *packet = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
size_t length = 0;
|
||||
int r;
|
||||
|
||||
log_setup_service();
|
||||
|
||||
if (argc != 3) {
|
||||
log_error("Wrong number of arguments.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc != 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Wrong number of arguments.");
|
||||
|
||||
if (streq(argv[1], "1")) {
|
||||
_cleanup_string_free_erase_ char *line = NULL;
|
||||
|
||||
r = read_line(stdin, LONG_LINE_MAX, &line);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to read password: %m");
|
||||
goto finish;
|
||||
}
|
||||
if (r == 0) {
|
||||
log_error("Got EOF while reading password.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read password: %m");
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||
"Got EOF while reading password.");
|
||||
|
||||
packet = strjoin("+", line);
|
||||
if (!packet) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
if (!packet)
|
||||
return log_oom();
|
||||
|
||||
length = 1 + strlen(line) + 1;
|
||||
|
||||
} else if (streq(argv[1], "0")) {
|
||||
packet = strdup("-");
|
||||
if (!packet) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
if (!packet)
|
||||
return log_oom();
|
||||
|
||||
length = 1;
|
||||
|
||||
} else {
|
||||
log_error("Invalid first argument %s", argv[1]);
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
} else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid first argument %s", argv[1]);
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (fd < 0) {
|
||||
r = log_error_errno(errno, "socket() failed: %m");
|
||||
goto finish;
|
||||
}
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "socket() failed: %m");
|
||||
|
||||
r = send_on_socket(fd, argv[2], packet, length);
|
||||
|
||||
finish:
|
||||
explicit_bzero_safe(packet, length);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
return send_on_socket(fd, argv[2], packet, length);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
|
||||
@@ -63,13 +63,16 @@ static int lookup_key(const char *keyname, key_serial_t *ret) {
|
||||
}
|
||||
|
||||
static int retrieve_key(key_serial_t serial, char ***ret) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
long m = 100, n;
|
||||
size_t nfinal, m = 100;
|
||||
char **l;
|
||||
_cleanup_(erase_and_freep) char *pfinal = NULL;
|
||||
|
||||
assert(ret);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_(erase_and_freep) char *p = NULL;
|
||||
long n;
|
||||
|
||||
p = new(char, m);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
@@ -77,33 +80,28 @@ static int retrieve_key(key_serial_t serial, char ***ret) {
|
||||
n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
if (n < m)
|
||||
if ((size_t) n < m) {
|
||||
nfinal = (size_t) n;
|
||||
pfinal = TAKE_PTR(p);
|
||||
break;
|
||||
|
||||
explicit_bzero_safe(p, m);
|
||||
}
|
||||
|
||||
if (m > LONG_MAX / 2) /* overflow check */
|
||||
return -ENOMEM;
|
||||
m *= 2;
|
||||
if ((long) (size_t) m != m) /* make sure that this still fits if converted to size_t */
|
||||
return -ENOMEM;
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
l = strv_parse_nulstr(p, n);
|
||||
l = strv_parse_nulstr(pfinal, nfinal);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
explicit_bzero_safe(p, n);
|
||||
|
||||
*ret = l;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
|
||||
_cleanup_strv_free_erase_ char **l = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
_cleanup_(erase_and_freep) char *p = NULL;
|
||||
key_serial_t serial;
|
||||
size_t n;
|
||||
int r;
|
||||
@@ -131,7 +129,6 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
|
||||
return r;
|
||||
|
||||
serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING);
|
||||
explicit_bzero_safe(p, n);
|
||||
if (serial == -1)
|
||||
return -errno;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "random-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
static void test_alloca(void) {
|
||||
@@ -132,6 +133,20 @@ static void test_cleanup_order(void) {
|
||||
log_debug("z: %p", &z);
|
||||
}
|
||||
|
||||
static void test_auto_erase_memory(void) {
|
||||
_cleanup_(erase_and_freep) uint8_t *p1, *p2;
|
||||
|
||||
assert_se(p1 = new(uint8_t, 1024));
|
||||
assert_se(p2 = new(uint8_t, 1024));
|
||||
|
||||
genuine_random_bytes(p1, 1024, RANDOM_BLOCK);
|
||||
|
||||
/* before we exit the scope, do something with this data, so that the compiler won't optimize this away */
|
||||
memcpy(p2, p1, 1024);
|
||||
for (size_t i = 0; i < 1024; i++)
|
||||
assert_se(p1[i] == p2[i]);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
@@ -140,6 +155,7 @@ int main(int argc, char *argv[]) {
|
||||
test_memdup_multiply_and_greedy_realloc();
|
||||
test_bool_assign();
|
||||
test_cleanup_order();
|
||||
test_auto_erase_memory();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -238,13 +238,13 @@ finish:
|
||||
}
|
||||
|
||||
static int send_passwords(const char *socket_name, char **passwords) {
|
||||
_cleanup_free_ char *packet = NULL;
|
||||
_cleanup_(erase_and_freep) char *packet = NULL;
|
||||
_cleanup_close_ int socket_fd = -1;
|
||||
union sockaddr_union sa = {};
|
||||
size_t packet_length = 1;
|
||||
char **p, *d;
|
||||
ssize_t n;
|
||||
int r, salen;
|
||||
int salen;
|
||||
|
||||
assert(socket_name);
|
||||
|
||||
@@ -266,22 +266,14 @@ static int send_passwords(const char *socket_name, char **passwords) {
|
||||
d = stpcpy(d, *p) + 1;
|
||||
|
||||
socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
||||
if (socket_fd < 0) {
|
||||
r = log_debug_errno(errno, "socket(): %m");
|
||||
goto finish;
|
||||
}
|
||||
if (socket_fd < 0)
|
||||
return log_debug_errno(errno, "socket(): %m");
|
||||
|
||||
n = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, salen);
|
||||
if (n < 0) {
|
||||
r = log_debug_errno(errno, "sendto(): %m");
|
||||
goto finish;
|
||||
}
|
||||
if (n < 0)
|
||||
return log_debug_errno(errno, "sendto(): %m");
|
||||
|
||||
r = (int) n;
|
||||
|
||||
finish:
|
||||
explicit_bzero_safe(packet, packet_length);
|
||||
return r;
|
||||
return (int) n;
|
||||
}
|
||||
|
||||
static int parse_password(const char *filename, char **wall) {
|
||||
|
||||
Reference in New Issue
Block a user