From owner-svn-src-all@freebsd.org Mon Apr 27 22:29:25 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id B13612C8883; Mon, 27 Apr 2020 22:29:25 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 499zwP4CdDz3JFF; Mon, 27 Apr 2020 22:29:25 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 8B32E19E23; Mon, 27 Apr 2020 22:29:25 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 03RMTPvX025739; Mon, 27 Apr 2020 22:29:25 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 03RMTODh025735; Mon, 27 Apr 2020 22:29:24 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <202004272229.03RMTODh025735@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Mon, 27 Apr 2020 22:29:24 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r360401 - in stable/12: stand/defaults sys/kern sys/sys X-SVN-Group: stable-12 X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: in stable/12: stand/defaults sys/kern sys/sys X-SVN-Commit-Revision: 360401 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Apr 2020 22:29:25 -0000 Author: kevans Date: Mon Apr 27 22:29:24 2020 New Revision: 360401 URL: https://svnweb.freebsd.org/changeset/base/360401 Log: MFC r359953, r359980, r359999: hostuuid preload r359953: kern uuid: break format validation out into a separate KPI This new KPI, validate_uuid, strictly validates the formatting of the input UUID and, optionally, populates a given struct uuid. As noted in the header, the key differences are that the new KPI won't recognize an empty string as a nil UUID and it won't do any kind of semantic validation on it. Also key is that populating a struct uuid is optional, so the caller doesn't necessarily need to allocate a bogus one on the stack just to validate the string. This KPI has specifically been broken out in support of D24288, which will preload /etc/hostid in loader so that early boot hostuuid users (e.g. anything that calls ether_gen_addr) can have a valid hostuuid to work with once it's been stashed in /etc/hostid. r359980: validate_uuid: absorb the rest of parse_uuid with a flags arg This makes the naming annoyance (validate_uuid vs. parse_uuid) less of an issue and centralizes all of the functionality into the new KPI while still making the extra validation optional. The end-result is all the same as far as hostuuid validation-only goes. r359999: Preload hostuuid for early-boot use prison0's hostuuid will get set by the hostid rc script, either after generating it and saving it to /etc/hostid or by simply reading /etc/hostid. Some things (e.g. arbitrary MAC address generation) may use the hostuuid as a factor in early boot, so providing a way to read /etc/hostid (if it's available) and using it before userland starts up is desirable. The code is written such that the preload doesn't *have* to be /etc/hostid, thus not assuming that there will be newline at the end of the buffer or even the exact shape of the newline. White trailing whitespace/non-printables trimmed, the result will be validated as a valid uuid before it's used for early boot purposes. The preload can be turned off with hostuuid_load="NO" in /boot/loader.conf, just as other preloads; it's worth noting that this is a 37-byte file, the overhead is believed to be generally minimal. It doesn't seem necessary at this time to be concerned with kern.hostid. One does wonder if we should consider validating hostuuids coming in via jail_set(2); some bits seem to care about uuid form and we bother validating format of smbios-provided uuid and in-fact whatever uuid comes from /etc/hostid. Modified: stable/12/stand/defaults/loader.conf stable/12/sys/kern/kern_jail.c stable/12/sys/kern/kern_uuid.c stable/12/sys/sys/uuid.h Directory Properties: stable/12/ (props changed) Modified: stable/12/stand/defaults/loader.conf ============================================================================== --- stable/12/stand/defaults/loader.conf Mon Apr 27 22:27:46 2020 (r360400) +++ stable/12/stand/defaults/loader.conf Mon Apr 27 22:29:24 2020 (r360401) @@ -33,6 +33,11 @@ bitmap_type="splash_image_data" # and place it on the screensave_load="NO" # Set to YES to load a screensaver module screensave_name="green_saver" # Set to the name of the screensaver module +### Early hostid configuration ############################ +hostuuid_load="YES" +hostuuid_name="/etc/hostid" +hostuuid_type="hostuuid" + ### Random number generator configuration ################## # See rc.conf(5). The entropy_boot_file config variable must agree with the # settings below. Modified: stable/12/sys/kern/kern_jail.c ============================================================================== --- stable/12/sys/kern/kern_jail.c Mon Apr 27 22:27:46 2020 (r360400) +++ stable/12/sys/kern/kern_jail.c Mon Apr 27 22:29:24 2020 (r360401) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -61,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -75,6 +77,7 @@ __FBSDID("$FreeBSD$"); #include #define DEFAULT_HOSTUUID "00000000-0000-0000-0000-000000000000" +#define PRISON0_HOSTUUID_MODULE "hostuuid" MALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); static MALLOC_DEFINE(M_PRISON_RACCT, "prison_racct", "Prison racct structures"); @@ -214,10 +217,38 @@ static unsigned jail_max_af_ips = 255; void prison0_init(void) { + uint8_t *file, *data; + size_t size; prison0.pr_cpuset = cpuset_ref(thread0.td_cpuset); prison0.pr_osreldate = osreldate; strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease)); + + /* If we have a preloaded hostuuid, use it. */ + file = preload_search_by_type(PRISON0_HOSTUUID_MODULE); + if (file != NULL) { + data = preload_fetch_addr(file); + size = preload_fetch_size(file); + if (data != NULL) { + /* + * The preloaded data may include trailing whitespace, almost + * certainly a newline; skip over any whitespace or + * non-printable characters to be safe. + */ + while (size > 0 && data[size - 1] <= 0x20) { + data[size--] = '\0'; + } + if (validate_uuid(data, size, NULL, 0) == 0) { + (void)strlcpy(prison0.pr_hostuuid, data, + size + 1); + } else if (bootverbose) { + printf("hostuuid: preload data malformed: '%s'", + data); + } + } + } + if (bootverbose) + printf("hostuuid: using %s\n", prison0.pr_hostuuid); } /* Modified: stable/12/sys/kern/kern_uuid.c ============================================================================== --- stable/12/sys/kern/kern_uuid.c Mon Apr 27 22:27:46 2020 (r360400) +++ stable/12/sys/kern/kern_uuid.c Mon Apr 27 22:29:24 2020 (r360401) @@ -382,19 +382,24 @@ be_uuid_dec(void const *buf, struct uuid *uuid) } int -parse_uuid(const char *str, struct uuid *uuid) +validate_uuid(const char *str, size_t size, struct uuid *uuid, int flags) { u_int c[11]; int n; - /* An empty string represents a nil UUID. */ - if (*str == '\0') { - bzero(uuid, sizeof(*uuid)); - return (0); + if (size == 0 || *str == '\0') { + /* An empty string may represent a nil UUID. */ + if ((flags & VUUIDF_EMPTYOK) != 0) { + if (uuid != NULL) + bzero(uuid, sizeof(*uuid)); + return (0); + } + + return (EINVAL); } /* The UUID string representation has a fixed length. */ - if (strlen(str) != 36) + if (size != 36) return (EINVAL); /* @@ -406,25 +411,39 @@ parse_uuid(const char *str, struct uuid *uuid) if (str[8] != '-') return (EINVAL); + /* Now check the format. */ n = sscanf(str, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", c + 0, c + 1, c + 2, c + 3, c + 4, c + 5, c + 6, c + 7, c + 8, c + 9, c + 10); /* Make sure we have all conversions. */ if (n != 11) return (EINVAL); - /* Successful scan. Build the UUID. */ - uuid->time_low = c[0]; - uuid->time_mid = c[1]; - uuid->time_hi_and_version = c[2]; - uuid->clock_seq_hi_and_reserved = c[3]; - uuid->clock_seq_low = c[4]; - for (n = 0; n < 6; n++) - uuid->node[n] = c[n + 5]; + /* Successful scan. Build the UUID if requested. */ + if (uuid != NULL) { + uuid->time_low = c[0]; + uuid->time_mid = c[1]; + uuid->time_hi_and_version = c[2]; + uuid->clock_seq_hi_and_reserved = c[3]; + uuid->clock_seq_low = c[4]; + for (n = 0; n < 6; n++) + uuid->node[n] = c[n + 5]; + } - /* Check semantics... */ + if ((flags & VUUIDF_CHECKSEMANTICS) == 0) + return (0); + return (((c[3] & 0x80) != 0x00 && /* variant 0? */ (c[3] & 0xc0) != 0x80 && /* variant 1? */ (c[3] & 0xe0) != 0xc0) ? EINVAL : 0); /* variant 2? */ +} + +#define VUUIDF_PARSEFLAGS (VUUIDF_EMPTYOK | VUUIDF_CHECKSEMANTICS) + +int +parse_uuid(const char *str, struct uuid *uuid) +{ + + return (validate_uuid(str, strlen(str), uuid, VUUIDF_PARSEFLAGS)); } int Modified: stable/12/sys/sys/uuid.h ============================================================================== --- stable/12/sys/sys/uuid.h Mon Apr 27 22:27:46 2020 (r360400) +++ stable/12/sys/sys/uuid.h Mon Apr 27 22:29:24 2020 (r360401) @@ -66,7 +66,20 @@ int uuid_ether_del(const uint8_t *); int snprintf_uuid(char *, size_t, struct uuid *); int printf_uuid(struct uuid *); int sbuf_printf_uuid(struct sbuf *, struct uuid *); + +/* + * validate_uuid will, with no flags passed, validate only the format of the + * passed in UUID. Flags below are available to give it part of or all of the + * functionality that parse_uuid has traditionally had: acknowledging an empty + * string as valid, and checking the semantics of the UUID as well. + */ +int validate_uuid(const char *, size_t, struct uuid *, int); int parse_uuid(const char *, struct uuid *); + +/* Flags to validate_uuid(). */ +#define VUUIDF_EMPTYOK 0x0001 +#define VUUIDF_CHECKSEMANTICS 0x0002 + int uuidcmp(const struct uuid *, const struct uuid *); void be_uuid_dec(void const *buf, struct uuid *uuid);