mount-encrypted: expprt nvram contents to tmpfs

Export the NVRAM contents to tmpfs (/tmp) for use during boot without
incurring the cost of repeated trips through the TPM.

Signed-off-by: Will Drewry <wad@chromium.org>

BUG=chromium-os:37367
TEST=builds, boots, emits lockbox.nvram which validates using in-progress lockbox-cache
BRANCH=none
Change-Id: I8b1103f4bd22bd75e98a7617a571bdb3a06d2914
Previous-Reviewed-on: https://gerrit.chromium.org/gerrit/41433
Commit-Queue: Will Drewry <wad@chromium.org>
(cherry picked from commit 265e2f78dd46845253b683ca8367483c31ba3f4a)
Reviewed-on: https://gerrit.chromium.org/gerrit/42114
Commit-Queue: Mattias Nissler <mnissler@chromium.org>
Reviewed-by: Mattias Nissler <mnissler@chromium.org>
Tested-by: Mattias Nissler <mnissler@chromium.org>
diff --git a/utility/mount-encrypted.c b/utility/mount-encrypted.c
index a97db0c..98e63e7 100644
--- a/utility/mount-encrypted.c
+++ b/utility/mount-encrypted.c
@@ -41,6 +41,7 @@
 #define ENCRYPTED_MNT STATEFUL_MNT "/encrypted"
 #define BUF_SIZE 1024
 #define PROP_SIZE 64
+#define LOCKBOX_SIZE_MAX 0x45
 
 static const gchar * const kKernelCmdline = "/proc/cmdline";
 static const gchar * const kKernelCmdlineOption = " encrypted-stateful-key=";
@@ -48,11 +49,12 @@
 static const gchar * const kCryptDevName = "encstateful";
 static const gchar * const kTpmDev = "/dev/tpm0";
 static const gchar * const kNullDev = "/dev/null";
+static const gchar * const kNvramExport = "/tmp/lockbox.nvram";
 static const float kSizePercent = 0.3;
 static const float kMigrationSizeMultiplier = 1.1;
 static const uint32_t kLockboxIndex = 0x20000004;
 static const uint32_t kLockboxSizeV1 = 0x2c;
-static const uint32_t kLockboxSizeV2 = 0x45;
+static const uint32_t kLockboxSizeV2 = LOCKBOX_SIZE_MAX;
 static const uint32_t kLockboxSaltOffset = 0x5;
 static const uint64_t kSectorSize = 512;
 static const uint64_t kExt4BlockSize = 4096;
@@ -111,6 +113,8 @@
 static gchar *dmcrypt_dev = NULL;
 static int has_tpm = 0;
 static int tpm_init_called = 0;
+static uint8_t nvram_data[LOCKBOX_SIZE_MAX];
+static uint32_t nvram_size = 0;
 
 static void tpm_init(void)
 {
@@ -352,6 +356,12 @@
 		return 0;
 	}
 
+	/* "Export" nvram data for use after the helper. */
+	if (size <= sizeof(nvram_data)) {
+		nvram_size = size;
+		memcpy(nvram_data, value, size);
+	}
+
 	/* Choose random bytes to use based on NVRAM version. */
 	if (*migrate) {
 		rand_bytes = value;
@@ -1271,6 +1281,25 @@
 	exit(1);
 }
 
+/* Exports NVRAM contents to tmpfs for use by install attributes */
+void nvram_export(uint8_t *data, uint32_t size)
+{
+	int fd;
+	DEBUG("Export NVRAM contents");
+	if (!size || !data)
+		return;
+	fd = open(kNvramExport, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
+	if (fd < 0) {
+		perror("open(nvram_export)");
+		return;
+	}
+	if (write(fd, data, size) != size) {
+		/* Don't leave broken files around */
+		unlink(kNvramExport);
+	}
+	close(fd);
+}
+
 int main(int argc, char *argv[])
 {
 	int okay;
@@ -1301,6 +1330,9 @@
 	okay = setup_encrypted(mode);
 	/* If we fail, let chromeos_startup handle the stateful wipe. */
 
+	if (okay)
+		nvram_export(nvram_data, nvram_size);
+
 	INFO_DONE("Done.");
 
 	/* Continue boot. */