From 0d6885c08737b60ceb3ca9bedbe44182e48536db Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Nov 2023 10:41:50 +0100 Subject: [PATCH 1/3] glib-aux: add NM_HASH_SEED_16_U64() macro c_siphash_init() requires a 16 bytes array. That is cumbersome to use. We have NM_HASH_SEED_16() macro for helping with that. It's still cumbersome. Most of the time, the caller just wants to pick an arbitrarily chosen, fixed number. Add NM_HASH_SEED_16_U64() which takes a number and gives a 16 seed array. The argument is in host endianness, but the resulting seed array has it encoded in big endianness, to be architecture independent. --- src/libnm-core-impl/tests/test-general.c | 15 ++++++++++++++ src/libnm-glib-aux/nm-hash-utils.h | 26 +++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index 485264fa1f..0603ea61e8 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -557,6 +557,21 @@ test_nm_hash(void) #endif NM_STATIC_ASSERT_EXPR_VOID(NM_HASH_COMBINE_BOOLS(int, 1, 0, 1) == 5); + + g_assert_cmpmem(NM_HASH_SEED_16(55, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), + 16, + ((guint8[16]){55, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}), + 16); + + g_assert_cmpmem(NM_HASH_SEED_16_U64(1), 16, ((guint8[16]){0, 0, 0, 0, 0, 0, 0, 1, 0}), 16); + g_assert_cmpmem(NM_HASH_SEED_16_U64(0x1234567890ABCDEFu), + 16, + ((guint8[16]){0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0}), + 16); + + g_assert_cmpint(c_siphash_hash(NM_HASH_SEED_16_U64(0x780E21E45489CC6Fu), (guint8 *) "foo", 3), + ==, + 0XA5A41E5C1B4153BFu); } /*****************************************************************************/ diff --git a/src/libnm-glib-aux/nm-hash-utils.h b/src/libnm-glib-aux/nm-hash-utils.h index c1306200b4..5a17af5bdb 100644 --- a/src/libnm-glib-aux/nm-hash-utils.h +++ b/src/libnm-glib-aux/nm-hash-utils.h @@ -14,6 +14,30 @@ #define NM_HASH_SEED_16(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \ ((const guint8[16]){a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af}) +struct _nm_packed _nm_hash_seed_16_u64_data { + guint64 s1; + guint64 s2; +}; + +G_STATIC_ASSERT(sizeof(struct _nm_hash_seed_16_u64_data) == 16); +G_STATIC_ASSERT(sizeof(struct _nm_hash_seed_16_u64_data) == sizeof(guint64) * 2); + +/* c_siphash_init() has a seed of 16 bytes (NM_HASH_SEED_16()). That is + * cumbersome to use, because we usually just hardcode an arbitrarily chosen, + * fixed number. + * + * This macro takes a u64 (in host-endianness) and returns a 16 byte seed + * buffer. The number will be big endian encoded, to be architecture + * independent. */ +#define NM_HASH_SEED_16_U64(u64) \ + ((const guint8 *) ((gpointer) \ + & ((struct _nm_hash_seed_16_u64_data){ \ + .s1 = htobe64((u64)), \ + .s2 = 0, \ + }))) + +/*****************************************************************************/ + void nm_hash_siphash42_init(CSipHash *h, guint static_seed); /* Siphash24 of binary buffer @arr and @len, using the randomized seed from @@ -22,7 +46,7 @@ void nm_hash_siphash42_init(CSipHash *h, guint static_seed); * Note, that this is guaranteed to use siphash42 under the hood (contrary to * all other NMHash API, which leave this undefined). That matters at the point, * where the caller needs to be sure that a reasonably strong hashing algorithm - * is used. (Yes, NMHash is all about siphash24, but otherwise that is not promised + * is used. (Yes, NMHash is all about siphash42, but otherwise that is not promised * anywhere). * * Another difference is, that this returns guint64 (not guint like other NMHash functions). From 27ae71b504c0b4c81ded939bc4bcd2bc7392af8c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Nov 2023 10:43:35 +0100 Subject: [PATCH 2/3] core: generate fixed fallback timestamp in _host_id_read_timestamp() nm_hash_siphash42() uses a randomized seed like nm_hash*(). In this case, we want to always generate the same fake timestamp, based on the host-id. In practice, it doesn't really matter, because this is only the fallback path for something gone horribly wrong already. --- src/core/nm-core-utils.c | 2 +- src/libnm-glib-aux/nm-hash-utils.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 822f138055..b12ca1b5e9 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -2711,7 +2711,7 @@ _host_id_read_timestamp(gboolean use_secret_key_file, #define EPOCH_TWO_YEARS (G_GINT64_CONSTANT(2 * 365 * 24 * 3600) * NM_UTILS_NSEC_PER_SEC) - v = nm_hash_siphash42(1156657133u, host_id, host_id_len); + v = c_siphash_hash(NM_HASH_SEED_16_U64(1156657133u), host_id, host_id_len); now = time(NULL); *out_timestamp_ns = diff --git a/src/libnm-glib-aux/nm-hash-utils.h b/src/libnm-glib-aux/nm-hash-utils.h index 5a17af5bdb..703c00a408 100644 --- a/src/libnm-glib-aux/nm-hash-utils.h +++ b/src/libnm-glib-aux/nm-hash-utils.h @@ -56,6 +56,9 @@ void nm_hash_siphash42_init(CSipHash *h, guint static_seed); * Then, why not use c_siphash_hash() directly? Because this also uses the randomized, * per-run hash-seed like nm_hash_init(). So, you get siphash24 with a random * seed (which is cached for the current run of the program). + * + * WARNING: the static_seed gets randomized like with nm_hash*(). If you want a reproducible + * siphash42, use instead `c_siphash_hash(NM_HASH_SEED_16_U64(number), ptr, len)`. */ static inline guint64 nm_hash_siphash42(guint static_seed, const void *ptr, gsize n) From 4f62600e21e55ef98d9b46c6e951a1cffe0b05bd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 Nov 2023 11:23:11 +0100 Subject: [PATCH 3/3] all: use NM_HASH_SEED_16() macro --- src/core/devices/wifi/nm-device-wifi.c | 35 ++++++------- src/core/nm-core-utils.c | 34 ++++++------- src/core/nm-l3-ipv4ll.c | 68 +++++++++++++------------- 3 files changed, 69 insertions(+), 68 deletions(-) diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 4377283458..2cd41b27f3 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -3191,27 +3191,28 @@ ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP GBytes *ssid; gsize ssid_len; const guint8 *ssid_data; - const guint8 random_seed[16] = {0x9a, - 0xdc, - 0x86, - 0x9a, - 0xa8, - 0xa2, - 0x07, - 0x97, - 0xbe, - 0x6d, - 0xe6, - 0x99, - 0x9f, - 0xa8, - 0x09, - 0x2b}; /* Calculate a stable "random" number based on the SSID. */ ssid = nm_setting_wireless_get_ssid(s_wifi); ssid_data = g_bytes_get_data(ssid, &ssid_len); - rnd = c_siphash_hash(random_seed, ssid_data, ssid_len); + rnd = c_siphash_hash(NM_HASH_SEED_16(0x9a, + 0xdc, + 0x86, + 0x9a, + 0xa8, + 0xa2, + 0x07, + 0x97, + 0xbe, + 0x6d, + 0xe6, + 0x99, + 0x9f, + 0xa8, + 0x09, + 0x2b), + ssid_data, + ssid_len); } if (nm_streq0(band, "a")) { diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index b12ca1b5e9..a6c20ad851 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -3819,23 +3819,23 @@ nm_utils_dhcp_client_id_mac(int arp_type, const guint8 *hwaddr, gsize hwaddr_len return g_bytes_new_take(client_id_buf, hwaddr_len + 1); } -#define HASH_KEY \ - ((const guint8[16]){0x80, \ - 0x11, \ - 0x8c, \ - 0xc2, \ - 0xfe, \ - 0x4a, \ - 0x03, \ - 0xee, \ - 0x3e, \ - 0xd6, \ - 0x0c, \ - 0x6f, \ - 0x36, \ - 0x39, \ - 0x14, \ - 0x09}) +#define HASH_KEY \ + NM_HASH_SEED_16(0x80, \ + 0x11, \ + 0x8c, \ + 0xc2, \ + 0xfe, \ + 0x4a, \ + 0x03, \ + 0xee, \ + 0x3e, \ + 0xd6, \ + 0x0c, \ + 0x6f, \ + 0x36, \ + 0x39, \ + 0x14, \ + 0x09) /** * nm_utils_create_dhcp_iaid: diff --git a/src/core/nm-l3-ipv4ll.c b/src/core/nm-l3-ipv4ll.c index ec871befc7..551a90fe36 100644 --- a/src/core/nm-l3-ipv4ll.c +++ b/src/core/nm-l3-ipv4ll.c @@ -390,23 +390,23 @@ _ipv4ll_addrgen(NML3IPv4LL *self, gboolean generate_new_addr) _ASSERT(self); /* MAC_HASH_KEY is the same as used by systemd. */ -#define MAC_HASH_KEY \ - ((const guint8[16]){0xdf, \ - 0x04, \ - 0x22, \ - 0x98, \ - 0x3f, \ - 0xad, \ - 0x14, \ - 0x52, \ - 0xf9, \ - 0x87, \ - 0x2e, \ - 0xd1, \ - 0x9c, \ - 0x70, \ - 0xe2, \ - 0xf2}) +#define MAC_HASH_KEY \ + NM_HASH_SEED_16(0xdf, \ + 0x04, \ + 0x22, \ + 0x98, \ + 0x3f, \ + 0xad, \ + 0x14, \ + 0x52, \ + 0xf9, \ + 0x87, \ + 0x2e, \ + 0xd1, \ + 0x9c, \ + 0x70, \ + 0xe2, \ + 0xf2) if (self->mac_set && (!self->seed_set || !nm_ether_addr_equal(&self->mac, &self->seed_mac))) { /* systemd's ipv4ll library by default only hashes the MAC address (as we do here). @@ -465,23 +465,23 @@ _ipv4ll_addrgen(NML3IPv4LL *self, gboolean generate_new_addr) gen_addr: -#define PICK_HASH_KEY \ - ((const guint8[16]){0x15, \ - 0xac, \ - 0x82, \ - 0xa6, \ - 0xd6, \ - 0x3f, \ - 0x49, \ - 0x78, \ - 0x98, \ - 0x77, \ - 0x5d, \ - 0x0c, \ - 0x69, \ - 0x02, \ - 0x94, \ - 0x0b}) +#define PICK_HASH_KEY \ + NM_HASH_SEED_16(0x15, \ + 0xac, \ + 0x82, \ + 0xa6, \ + 0xd6, \ + 0x3f, \ + 0x49, \ + 0x78, \ + 0x98, \ + 0x77, \ + 0x5d, \ + 0x0c, \ + 0x69, \ + 0x02, \ + 0x94, \ + 0x0b) h = c_siphash_hash(PICK_HASH_KEY, (const guint8 *) &self->seed, sizeof(self->seed));