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;
 }

Reply via email to