Mercurial > illumos > illumos-gate
changeset 13897:6a8c59d9c8cf
3359 hostid generation should be more "predictable"
Reviewed by: Andy Giles <andy.giles@dey-sys.com>
Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
Reviewed by: Richard Elling <richard.elling@dey-sys.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
author | Garrett D'Amore <garrett@dey-sys.com> |
---|---|
date | Sat, 17 Nov 2012 00:50:53 -0800 |
parents | 902fa9d81a3d |
children | 7f822b09519b |
files | usr/src/uts/i86pc/os/startup.c |
diffstat | 1 files changed, 106 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/i86pc/os/startup.c Tue Dec 04 14:37:21 2012 -0500 +++ b/usr/src/uts/i86pc/os/startup.c Sat Nov 17 00:50:53 2012 -0800 @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. */ /* * Copyright (c) 2010, Intel Corporation. @@ -1586,23 +1587,6 @@ dispinit(); - /* - * This is needed here to initialize hw_serial[] for cluster booting. - */ - if ((h = set_soft_hostid()) == HW_INVALID_HOSTID) { - cmn_err(CE_WARN, "Unable to set hostid"); - } else { - for (v = h, cnt = 0; cnt < 10; cnt++) { - d[cnt] = (char)(v % 10); - v /= 10; - if (v == 0) - break; - } - for (cp = hw_serial; cnt >= 0; cnt--) - *cp++ = d[cnt] + '0'; - *cp = 0; - } - /* Read cluster configuration data. */ clconf_init(); @@ -1631,6 +1615,26 @@ /* + * Originally clconf_init() apparently needed the hostid. But + * this no longer appears to be true - it uses its own nodeid. + * By placing the hostid logic here, we are able to make use of + * the SMBIOS UUID. + */ + if ((h = set_soft_hostid()) == HW_INVALID_HOSTID) { + cmn_err(CE_WARN, "Unable to set hostid"); + } else { + for (v = h, cnt = 0; cnt < 10; cnt++) { + d[cnt] = (char)(v % 10); + v /= 10; + if (v == 0) + break; + } + for (cp = hw_serial; cnt >= 0; cnt--) + *cp++ = d[cnt] + '0'; + *cp = 0; + } + + /* * Set up the CPU module subsystem for the boot cpu in the native * case, and all physical cpu resource in the xpv dom0 case. * Modifies the device tree, so this must be done after @@ -2721,6 +2725,11 @@ * /etc/hostid does not exist, we will attempt to get a serial number * using the legacy method (/kernel/misc/sysinit). * + * If that isn't present, we attempt to use an SMBIOS UUID, which is + * a hardware serial number. Note that we don't automatically trust + * all SMBIOS UUIDs (some older platforms are defective and ship duplicate + * UUIDs in violation of the standard), we check against a blacklist. + * * In an attempt to make the hostid less prone to abuse * (for license circumvention, etc), we store it in /etc/hostid * in rot47 format. @@ -2728,6 +2737,67 @@ extern volatile unsigned long tenmicrodata; static int atoi(char *); +/* + * Set this to non-zero in /etc/system if you think your SMBIOS returns a + * UUID that is not unique. (Also report it so that the smbios_uuid_blacklist + * array can be updated.) + */ +int smbios_broken_uuid = 0; + +/* + * List of known bad UUIDs. This is just the lower 32-bit values, since + * that's what we use for the host id. If your hostid falls here, you need + * to contact your hardware OEM for a fix for your BIOS. + */ +static unsigned char +smbios_uuid_blacklist[][16] = { + + { /* Reported bad UUID (Google search) */ + 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, + }, + { /* Known bad DELL UUID */ + 0x4C, 0x4C, 0x45, 0x44, 0x00, 0x00, 0x20, 0x10, + 0x80, 0x20, 0x80, 0xC0, 0x4F, 0x20, 0x20, 0x20, + }, + { /* Uninitialized flash */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }, + { /* All zeros */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, +}; + +static int32_t +uuid_to_hostid(const uint8_t *uuid) +{ + /* + * Although the UUIDs are 128-bits, they may not distribute entropy + * evenly. We would like to use SHA or MD5, but those are located + * in loadable modules and not available this early in boot. As we + * don't need the values to be cryptographically strong, we just + * generate 32-bit vaue by xor'ing the various sequences together, + * which ensures that the enire UUID contributes to the hostid. + */ + int32_t id = 0; + + /* first check against the blacklist */ + for (int i = 0; i < (sizeof (smbios_uuid_blacklist) / 16); i++) { + if (bcmp(smbios_uuid_blacklist[0], uuid, 16) == 0) { + cmn_err(CE_CONT, "?Broken SMBIOS UUID. " + "Contact BIOS manufacturer for repair.\n"); + return ((int32_t)HW_INVALID_HOSTID); + } + } + + for (int i = 0; i < 16; i++) + id ^= ((uuid[i]) << (8 * (i % sizeof (id)))); + + return (id); +} + static int32_t set_soft_hostid(void) { @@ -2740,6 +2810,7 @@ int32_t hostid = (int32_t)HW_INVALID_HOSTID; unsigned char *c; hrtime_t tsc; + smbios_system_t smsys; /* * If /etc/hostid file not found, we'd like to get a pseudo @@ -2763,6 +2834,24 @@ hostid = (int32_t)atoi(hw_serial); (void) modunload(i); } + + /* + * We try to use the SMBIOS UUID. But not if it is blacklisted + * in /etc/system. + */ + if ((hostid == HW_INVALID_HOSTID) && + (smbios_broken_uuid == 0) && + (ksmbios != NULL) && + (smbios_info_system(ksmbios, &smsys) != SMB_ERR) && + (smsys.smbs_uuidlen >= 16)) { + hostid = uuid_to_hostid(smsys.smbs_uuid); + } + + /* + * Generate a "random" hostid using the clock. These + * hostids will change on each boot if the value is not + * saved to a persistent /etc/hostid file. + */ if (hostid == HW_INVALID_HOSTID) { tsc = tsc_read(); if (tsc == 0) /* tsc_read can return zero sometimes */