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