Module Name: src
Committed By: mlelstv
Date: Sun Oct 20 08:21:30 UTC 2024
Modified Files:
src/sbin/gpt: gpt.c gpt_private.h gpt_uuid.c uuid.c
Log Message:
When generating timestamp based GUIDs for reproducable builds
- increment timestamp by 100ns for each partition.
- use the standard time-based UUID format (type 1) and don't
pretend it's a random number (type 4).
- make the -T option actually work for the uuid command.
Random GUIDs:
start size index contents
34 1000 1 GPT part - d93ba067-a788-4ce0-99b8-0ead51f00215
1034 2000 2 GPT part - bebba77a-7fdc-4ca0-a1bf-7450aa871d41
d93ba067-a788-4ce0-99b8-0ead51f00215:
Version 4 Random
Variant 2 RFC 4122
Data D9 3B A0 67 A7 88 4C E0 99 B8 0E AD 51 F0 02 15
bebba77a-7fdc-4ca0-a1bf-7450aa871d41:
Version 4 Random
Variant 2 RFC 4122
Data BE BB A7 7A 7F DC 4C A0 A1 BF 74 50 AA 87 1D 41
Timestamp based GUIDs:
start size index contents
34 1000 1 GPT part - 0a524600-8eba-11ef-8000-000000000000
1034 2000 2 GPT part - 0a524601-8eba-11ef-8000-000000000000
0a524600-8eba-11ef-8000-000000000000:
Version 1 Time and MAC based
Variant 2 RFC 4122
Node 00:00:00:00:00:00
Clock 0
Time 2024-10-20T08:05:16.000000.0Z
0a524601-8eba-11ef-8000-000000000000:
Version 1 Time and MAC based
Variant 2 RFC 4122
Node 00:00:00:00:00:00
Clock 0
Time 2024-10-20T08:05:16.000000.1Z
Node (host MAC address) and clock (sequence number incremented whenever
the time went backwards) are left undefined (all zero) for our purpose.
To generate a diff of this commit:
cvs rdiff -u -r1.89 -r1.90 src/sbin/gpt/gpt.c
cvs rdiff -u -r1.3 -r1.4 src/sbin/gpt/gpt_private.h
cvs rdiff -u -r1.22 -r1.23 src/sbin/gpt/gpt_uuid.c
cvs rdiff -u -r1.2 -r1.3 src/sbin/gpt/uuid.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sbin/gpt/gpt.c
diff -u src/sbin/gpt/gpt.c:1.89 src/sbin/gpt/gpt.c:1.90
--- src/sbin/gpt/gpt.c:1.89 Mon Jun 10 09:17:29 2024
+++ src/sbin/gpt/gpt.c Sun Oct 20 08:21:30 2024
@@ -35,7 +35,7 @@
__FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $");
#endif
#ifdef __RCSID
-__RCSID("$NetBSD: gpt.c,v 1.89 2024/06/10 09:17:29 kre Exp $");
+__RCSID("$NetBSD: gpt.c,v 1.90 2024/10/20 08:21:30 mlelstv Exp $");
#endif
#include <sys/param.h>
@@ -495,6 +495,7 @@ gpt_open(const char *dev, int flags, int
gpt->mediasz = mediasz;
gpt->secsz = secsz;
gpt->timestamp = timestamp;
+ gpt->uuidgen = 0;
mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL;
Index: src/sbin/gpt/gpt_private.h
diff -u src/sbin/gpt/gpt_private.h:1.3 src/sbin/gpt/gpt_private.h:1.4
--- src/sbin/gpt/gpt_private.h:1.3 Sun Jun 30 11:38:16 2019
+++ src/sbin/gpt/gpt_private.h Sun Oct 20 08:21:30 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: gpt_private.h,v 1.3 2019/06/30 11:38:16 sevan Exp $ */
+/* $NetBSD: gpt_private.h,v 1.4 2024/10/20 08:21:30 mlelstv Exp $ */
/*-
* Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/time.h>
#include <sys/stat.h>
struct gpt {
@@ -44,5 +45,6 @@ struct gpt {
u_int secsz;
off_t mediasz;
time_t timestamp;
+ u_int uuidgen;
struct stat sb;
};
Index: src/sbin/gpt/gpt_uuid.c
diff -u src/sbin/gpt/gpt_uuid.c:1.22 src/sbin/gpt/gpt_uuid.c:1.23
--- src/sbin/gpt/gpt_uuid.c:1.22 Mon Aug 19 17:15:38 2024
+++ src/sbin/gpt/gpt_uuid.c Sun Oct 20 08:21:30 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: gpt_uuid.c,v 1.22 2024/08/19 17:15:38 christos Exp $ */
+/* $NetBSD: gpt_uuid.c,v 1.23 2024/10/20 08:21:30 mlelstv Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
#include <sys/cdefs.h>
#ifdef __RCSID
-__RCSID("$NetBSD: gpt_uuid.c,v 1.22 2024/08/19 17:15:38 christos Exp $");
+__RCSID("$NetBSD: gpt_uuid.c,v 1.23 2024/10/20 08:21:30 mlelstv Exp $");
#endif
#include <err.h>
@@ -272,7 +272,7 @@ gpt_uuid_create(gpt_type_t t, gpt_uuid_t
}
static int
-gpt_uuid_random(gpt_t gpt, void *v, size_t n)
+gpt_uuid_random(gpt_t gpt, struct dce_uuid *u, size_t n)
{
int fd;
uint8_t *p;
@@ -284,7 +284,7 @@ gpt_uuid_random(gpt_t gpt, void *v, size
gpt_warn(gpt, "Can't open `/dev/urandom'");
return -1;
}
- for (p = v; n > 0; p += nread, n -= (size_t)nread) {
+ for (p = (uint8_t *)u; n > 0; p += nread, n -= (size_t)nread) {
nread = read(fd, p, n);
if (nread < 0) {
gpt_warn(gpt, "Can't read `/dev/urandom'");
@@ -300,21 +300,59 @@ gpt_uuid_random(gpt_t gpt, void *v, size
}
}
(void)close(fd);
+
+ /* Set the version number to 4. */
+ u->time_hi_and_version &= (uint16_t)~0xf000;
+ u->time_hi_and_version |= 0x4000;
+
return 0;
out:
(void)close(fd);
return -1;
}
+/*
+ * For reproducable builds, we can base UUIDs on one external timestamp.
+ *
+ * Bump timestamp by one 100ns unit to make them unique within a GPT.
+ * Use zero clock sequence and node id, ideally these should also be
+ * passed as input.
+ */
static int
-gpt_uuid_tstamp(gpt_t gpt, void *v, size_t l)
+gpt_uuid_tstamp(gpt_t gpt, struct dce_uuid *u, size_t l)
{
- uint8_t *p;
- // Perhaps use SHA?
- uint32_t x = (uint32_t)gpt->timestamp;
+ uint64_t x;
- for (p = v; l > 0; p += sizeof(x), l -= sizeof(x))
- memcpy(p, &x, sizeof(x));
+ /* check for underflow/overflow of 60bit UUID time */
+ if (gpt->timestamp < -12219292800 ||
+ gpt->timestamp > 103072857660)
+ return -1;
+
+ /*
+ * Convert to UUID epoch (Gregorian)
+ * and 100ns units
+ */
+ x = (uint64_t)(gpt->timestamp + 12219292800) * 10000000;
+
+ /* Make UUID unique */
+ x += gpt->uuidgen++;
+
+ /* Set UUID fields for version 1 */
+ u->time_low = x & 0xffffffff;
+ u->time_mid = (x >> 32) & 0xffff;
+ u->time_hi_and_version = 0x1000 | ((x >> 48) & 0xfff);
+
+ /*
+ * The clock sequence should make UUIDs unique in case
+ * the clock went backwards.
+ */
+ u->clock_seq_hi_and_reserved = 0;
+ u->clock_seq_low = 0;
+
+ /*
+ * A unique system identifier (usually MAC address)
+ */
+ memset(u->node, 0, sizeof(u->node));
return 0;
}
@@ -324,6 +362,7 @@ gpt_uuid_generate(gpt_t gpt, gpt_uuid_t
{
int rv;
struct dce_uuid u;
+
if (gpt && (gpt->flags & GPT_TIMESTAMP))
rv = gpt_uuid_tstamp(gpt, &u, sizeof(u));
else
@@ -332,10 +371,6 @@ gpt_uuid_generate(gpt_t gpt, gpt_uuid_t
if (rv == -1)
return -1;
- /* Set the version number to 4. */
- u.time_hi_and_version &= (uint16_t)~0xf000;
- u.time_hi_and_version |= 0x4000;
-
/* Fix the reserved bits. */
u.clock_seq_hi_and_reserved &= (uint8_t)~0x40;
u.clock_seq_hi_and_reserved |= 0x80;
Index: src/sbin/gpt/uuid.c
diff -u src/sbin/gpt/uuid.c:1.2 src/sbin/gpt/uuid.c:1.3
--- src/sbin/gpt/uuid.c:1.2 Mon Aug 19 17:15:38 2024
+++ src/sbin/gpt/uuid.c Sun Oct 20 08:21:30 2024
@@ -33,7 +33,7 @@
__FBSDID("$FreeBSD: src/sbin/gpt/remove.c,v 1.10 2006/10/04 18:20:25 marcel Exp $");
#endif
#ifdef __RCSID
-__RCSID("$NetBSD: uuid.c,v 1.2 2024/08/19 17:15:38 christos Exp $");
+__RCSID("$NetBSD: uuid.c,v 1.3 2024/10/20 08:21:30 mlelstv Exp $");
#endif
#include <sys/types.h>
@@ -65,26 +65,34 @@ struct gpt_cmd c_uuid = {
#define usage() gpt_usage(NULL, &c_uuid)
+struct uuidctx {
+ gpt_t gpt;
+ gpt_uuid_t *uuid;
+};
+
static void
change_ent(struct gpt_ent *ent, void *v, int backup)
{
+ struct uuidctx *ctx = v;
static gpt_uuid_t uuidstore;
- if (v != NULL) {
- memcpy(uuidstore, v, sizeof(uuidstore));
+ if (!backup) {
+ if (ctx->uuid != NULL)
+ memcpy(uuidstore, ctx->uuid, sizeof(uuidstore));
+ else
+ gpt_uuid_generate(ctx->gpt, uuidstore);
}
- else if (!backup)
- gpt_uuid_generate(NULL, uuidstore);
memmove(ent->ent_guid, uuidstore, sizeof(ent->ent_guid));
}
static void
change_hdr(struct gpt_hdr *hdr, void *v, int backup)
{
+ struct uuidctx *ctx = v;
static gpt_uuid_t uuidstore;
if (!backup)
- gpt_uuid_generate(NULL, uuidstore);
+ gpt_uuid_generate(ctx->gpt, uuidstore);
memmove(hdr->hdr_guid, uuidstore, sizeof(hdr->hdr_guid));
}
@@ -94,7 +102,7 @@ cmd_uuid(gpt_t gpt, int argc, char *argv
int ch, rc;
struct gpt_find find;
gpt_uuid_t new_uuid;
- void *v;
+ struct uuidctx ctx;
if (gpt == NULL)
return usage();
@@ -103,13 +111,14 @@ cmd_uuid(gpt_t gpt, int argc, char *argv
find.msg = "UUID changed";
/* Get the uuid options */
- v = NULL;
+ ctx.gpt = gpt;
+ ctx.uuid = NULL;
while ((ch = getopt(argc, argv, GPT_FIND "U:")) != -1) {
switch (ch) {
case 'U':
if (gpt_uuid_parse(optarg, new_uuid) == -1)
return usage();
- v = new_uuid;
+ ctx.uuid = &new_uuid;
break;
default:
if (gpt_add_find(gpt, &find, ch) == -1)
@@ -121,12 +130,12 @@ cmd_uuid(gpt_t gpt, int argc, char *argv
if (argc != optind)
return usage();
- rc = gpt_change_ent(gpt, &find, change_ent, v);
+ rc = gpt_change_ent(gpt, &find, change_ent, &ctx);
if (rc != 0)
return rc;
if (find.all)
- return gpt_change_hdr(gpt, &find, change_hdr, NULL);
+ return gpt_change_hdr(gpt, &find, change_hdr, &ctx);
return 0;
}