summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-10-31 11:18:46 +0100
committerThomas Haller <thaller@redhat.com>2018-11-13 19:09:33 +0100
commit50121ee0286f00986406cd1b654c32dbed800946 (patch)
tree7b537687d73ef0a459f8f378a65d02c0a32e7a91
parentc51e63feb698447c5d91a06e0dcc3302845af452 (diff)
downloadNetworkManager-50121ee0286f00986406cd1b654c32dbed800946.tar.gz
core: cleanup generating DUID in nm-device.c
- use NMUuid type where appropriate. - no error handling for generate_duid_from_machine_id(). It cannot fail anymore. - add thread-safety to generate_duid_from_machine_id() with double-checked locking. - use unions for converting the sha256 digest to the target type.
-rw-r--r--src/devices/nm-device.c117
1 files changed, 60 insertions, 57 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index d30ab6ab8c..a0cdb3d235 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -7580,11 +7580,10 @@ dhcp4_get_client_id (NMDevice *self,
}
if (nm_streq (client_id, "stable")) {
+ nm_auto_free_checksum GChecksum *sum = NULL;
+ guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1];
NMUtilsStableType stable_type;
const char *stable_id;
- GChecksum *sum;
- guint8 buf[20];
- gsize buf_size;
guint32 salted_header;
const guint8 *secret_key;
gsize secret_key_len;
@@ -7598,20 +7597,14 @@ dhcp4_get_client_id (NMDevice *self,
nm_utils_secret_key_get (&secret_key, &secret_key_len);
sum = g_checksum_new (G_CHECKSUM_SHA1);
-
g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header));
g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1);
g_checksum_update (sum, (const guchar *) secret_key, secret_key_len);
-
- buf_size = sizeof (buf);
- g_checksum_get_digest (sum, buf, &buf_size);
- nm_assert (buf_size == sizeof (buf));
-
- g_checksum_free (sum);
+ nm_utils_checksum_get_digest (sum, digest);
client_id_buf = g_malloc (1 + 15);
client_id_buf[0] = 0;
- memcpy (&client_id_buf[1], buf, 15);
+ memcpy (&client_id_buf[1], digest, 15);
result = g_bytes_new_take (client_id_buf, 1 + 15);
goto out_good;
}
@@ -8232,6 +8225,8 @@ dhcp6_prefix_delegated (NMDhcpClient *client,
g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix);
}
+/*****************************************************************************/
+
/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */
#define EPOCH_DATETIME_200001010000 946684800
@@ -8271,14 +8266,12 @@ generate_duid_ll (const guint8 *hwaddr /* ETH_ALEN bytes */)
}
static GBytes *
-generate_duid_uuid (guint8 *data, gsize data_len)
+generate_duid_uuid (const NMUuid *uuid)
{
- const guint16 duid_type = g_htons (4);
- const int DUID_SIZE = 18;
+ const guint16 duid_type = htons (4);
guint8 *duid_buffer;
- nm_assert (data);
- nm_assert (data_len >= 16);
+ nm_assert (uuid);
/* Generate a DHCP Unique Identifier for DHCPv6 using the
* DUID-UUID method (see RFC 6355 section 4). Format is:
@@ -8286,41 +8279,47 @@ generate_duid_uuid (guint8 *data, gsize data_len)
* u16: type (DUID-UUID = 4)
* u8[16]: UUID bytes
*/
- duid_buffer = g_malloc (DUID_SIZE);
-
G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2);
+ G_STATIC_ASSERT_EXPR (sizeof (*uuid) == 16);
+ duid_buffer = g_malloc (18);
memcpy (&duid_buffer[0], &duid_type, 2);
-
- /* UUID is 128 bits, we just take the first 128 bits
- * (regardless of data size) as the DUID-UUID.
- */
- memcpy (&duid_buffer[2], data, 16);
-
- return g_bytes_new_take (duid_buffer, DUID_SIZE);
+ memcpy (&duid_buffer[2], uuid, 16);
+ return g_bytes_new_take (duid_buffer, 18);
}
static GBytes *
generate_duid_from_machine_id (void)
{
- const NMUuid *uuid;
- GChecksum *sum;
- guint8 sha256_digest[32];
- gsize len = sizeof (sha256_digest);
- static GBytes *global_duid = NULL;
+ static GBytes *volatile global_duid = NULL;
+ GBytes *p;
- if (global_duid)
- return g_bytes_ref (global_duid);
+again:
+ p = g_atomic_pointer_get (&global_duid);
+ if (G_UNLIKELY (!p)) {
+ nm_auto_free_checksum GChecksum *sum = NULL;
+ const NMUuid *machine_id;
+ union {
+ guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256];
+ NMUuid uuid;
+ } digest;
- uuid = nm_utils_machine_id_bin ();
+ machine_id = nm_utils_machine_id_bin ();
- /* Hash the machine ID so it's not leaked to the network */
- sum = g_checksum_new (G_CHECKSUM_SHA256);
- g_checksum_update (sum, (const guchar *) uuid, sizeof (*uuid));
- g_checksum_get_digest (sum, sha256_digest, &len);
- g_checksum_free (sum);
+ /* Hash the machine ID so it's not leaked to the network */
+ sum = g_checksum_new (G_CHECKSUM_SHA256);
+ g_checksum_update (sum, (const guchar *) machine_id, sizeof (*machine_id));
+ nm_utils_checksum_get_digest (sum, digest.sha256);
- global_duid = generate_duid_uuid (sha256_digest, len);
- return g_bytes_ref (global_duid);
+ G_STATIC_ASSERT_EXPR (sizeof (digest.sha256) > sizeof (digest.uuid));
+ p = generate_duid_uuid (&digest.uuid);
+
+ if (!g_atomic_pointer_compare_and_exchange (&global_duid, NULL, p)) {
+ g_bytes_unref (p);
+ goto again;
+ }
+ }
+
+ return g_bytes_ref (p);
}
static GBytes *
@@ -8331,8 +8330,6 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
gs_free char *duid_default = NULL;
const char *duid_error;
GBytes *duid_out;
- guint8 sha256_digest[32];
- gsize len = sizeof (sha256_digest);
gboolean duid_enforce = TRUE;
gs_free char *logstr1 = NULL;
@@ -8350,10 +8347,6 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
if (nm_streq (duid, "lease")) {
duid_enforce = FALSE;
duid_out = generate_duid_from_machine_id ();
- if (!duid_out) {
- duid_error = "failure to read machine-id";
- goto out_fail;
- }
goto out_good;
}
@@ -8393,12 +8386,21 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
}
if (NM_IN_STRSET (duid, "stable-ll", "stable-llt", "stable-uuid")) {
+ nm_auto_free_checksum GChecksum *sum = NULL;
NMUtilsStableType stable_type;
const char *stable_id = NULL;
guint32 salted_header;
- GChecksum *sum;
const guint8 *secret_key;
gsize secret_key_len;
+ union {
+ guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256];
+ guint8 hwaddr[ETH_ALEN];
+ NMUuid uuid;
+ struct _nm_packed {
+ guint8 hwaddr[ETH_ALEN];
+ guint32 timestamp;
+ } llt;
+ } digest;
stable_id = _get_stable_id (self, connection, &stable_type);
if (!stable_id)
@@ -8409,16 +8411,15 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
nm_utils_secret_key_get (&secret_key, &secret_key_len);
sum = g_checksum_new (G_CHECKSUM_SHA256);
-
g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header));
g_checksum_update (sum, (const guchar *) stable_id, -1);
g_checksum_update (sum, (const guchar *) secret_key, secret_key_len);
+ nm_utils_checksum_get_digest (sum, digest.sha256);
- g_checksum_get_digest (sum, sha256_digest, &len);
- g_checksum_free (sum);
+ G_STATIC_ASSERT_EXPR (sizeof (digest) == sizeof (digest.sha256));
if (nm_streq (duid, "stable-ll")) {
- duid_out = generate_duid_ll (sha256_digest);
+ duid_out = generate_duid_ll (digest.hwaddr);
} else if (nm_streq (duid, "stable-llt")) {
gint64 time;
@@ -8436,12 +8437,12 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
/* don't use too old timestamps. They cannot be expressed in DUID-LLT and
* would all be truncated to zero. */
time = NM_MAX (time, EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS);
- time -= (unaligned_read_be32 (&sha256_digest[ETH_ALEN]) % EPOCH_DATETIME_THREE_YEARS);
+ time -= unaligned_read_be32 (&digest.llt.timestamp) % EPOCH_DATETIME_THREE_YEARS;
- duid_out = generate_duid_llt (sha256_digest, time);
+ duid_out = generate_duid_llt (digest.llt.hwaddr, time);
} else {
nm_assert (nm_streq (duid, "stable-uuid"));
- duid_out = generate_duid_uuid (sha256_digest, len);
+ duid_out = generate_duid_uuid (&digest.uuid);
}
goto out_good;
@@ -8452,14 +8453,14 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
out_fail:
nm_assert (!duid_out && duid_error);
{
- guint8 uuid[16];
+ NMUuid uuid;
_LOGW (LOGD_IP6 | LOGD_DHCP6,
"ipv6.dhcp-duid: failure to generate %s DUID: %s. Fallback to random DUID-UUID.",
duid, duid_error);
- nm_utils_random_bytes (uuid, sizeof (uuid));
- duid_out = generate_duid_uuid (uuid, sizeof (uuid));
+ nm_utils_random_bytes (&uuid, sizeof (uuid));
+ duid_out = generate_duid_uuid (&uuid);
}
out_good:
@@ -8474,6 +8475,8 @@ out_good:
return duid_out;
}
+/*****************************************************************************/
+
static gboolean
dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
{