summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2012-11-27 17:46:37 -0800
committerGerrit <chrome-bot@google.com>2012-11-28 21:35:49 -0800
commit00cc72894f3ce5c3b0d337e424f19da089140237 (patch)
tree50455728a1f7f662e1a7c69d4434d014213e108e
parentca44b077a889ea7ddb6d5de712ac6dd0d6a3d67e (diff)
downloadvboot-stabilize2.tar.gz
Tlcl: allow OS failures to bubble up to callerstabilize2
If there were any errors communicating with the TPM at the OS layer (open, read, write failures), the library would immediately exit, not allowing the caller to make any decisions about how to handle it. This introduces a way to initialize the library so that errors will get passed back up to the caller instead of unceremoniously exiting. Setting the environment variable "TPM_NO_EXIT=1" enables the feature. To avoid needing to implement supporting functions in all backends, the feature is currently limited to just the Tlcl stub implementation. In the case of mount-encrypted, it can now survive the kernel returning read/write failures. In the past it had only worked around having open fail, but that has now been replaced with more sensible logic instead of the environment variable trickiness. BUG=chrome-os-partner:15960 TEST=daisy built with an always-failing kernel driver, u-boot builds too BRANCH=None Change-Id: Ic7b217017537980f9c239d678067398613045676 Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/38791 Reviewed-by: Luigi Semenzato <semenzato@chromium.org>
-rw-r--r--firmware/include/tss_constants.h4
-rw-r--r--firmware/lib/tpm_lite/tlcl.c2
-rw-r--r--firmware/stub/tpm_lite_stub.c50
-rw-r--r--utility/mount-encrypted.c17
4 files changed, 49 insertions, 24 deletions
diff --git a/firmware/include/tss_constants.h b/firmware/include/tss_constants.h
index 39198f46..ef584007 100644
--- a/firmware/include/tss_constants.h
+++ b/firmware/include/tss_constants.h
@@ -38,6 +38,10 @@
#define TPM_E_COMMUNICATION_ERROR ((uint32_t)0x00005004) /* vboot local */
#define TPM_E_RESPONSE_TOO_LARGE ((uint32_t)0x00005005) /* vboot local */
#define TPM_E_NO_DEVICE ((uint32_t)0x00005006) /* vboot local */
+#define TPM_E_INPUT_TOO_SMALL ((uint32_t)0x00005007) /* vboot local */
+#define TPM_E_WRITE_FAILURE ((uint32_t)0x00005008) /* vboot local */
+#define TPM_E_READ_EMPTY ((uint32_t)0x00005009) /* vboot local */
+#define TPM_E_READ_FAILURE ((uint32_t)0x0000500a) /* vboot local */
#define TPM_NV_INDEX0 ((uint32_t)0x00000000)
#define TPM_NV_INDEX_LOCK ((uint32_t)0xffffffff)
diff --git a/firmware/lib/tpm_lite/tlcl.c b/firmware/lib/tpm_lite/tlcl.c
index 511a4fc6..9a0801f5 100644
--- a/firmware/lib/tpm_lite/tlcl.c
+++ b/firmware/lib/tpm_lite/tlcl.c
@@ -67,7 +67,7 @@ static uint32_t TlclSendReceiveNoRetry(const uint8_t* request,
/* Communication with TPM failed, so response is garbage */
VBDEBUG(("TPM: command 0x%x send/receive failed: 0x%x\n",
TpmCommandCode(request), result));
- return TPM_E_COMMUNICATION_ERROR;
+ return result;
}
/* Otherwise, use the result code from the response */
result = TpmReturnCode(response);
diff --git a/firmware/stub/tpm_lite_stub.c b/firmware/stub/tpm_lite_stub.c
index 1b498368..a60d6507 100644
--- a/firmware/stub/tpm_lite_stub.c
+++ b/firmware/stub/tpm_lite_stub.c
@@ -33,6 +33,22 @@
/* The file descriptor for the TPM device.
*/
static int tpm_fd = -1;
+/* If the library should exit during an OS-level TPM failure.
+ */
+static int exit_on_failure = 1;
+
+/* Similar to VbExError, only handle the non-exit case.
+ */
+static VbError_t DoError(VbError_t result, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ if (exit_on_failure)
+ exit(1);
+ return result;
+}
/* Print |n| bytes from array |a|, with newlines.
@@ -53,32 +69,40 @@ POSSIBLY_UNUSED static void PrintBytes(const uint8_t* a, int n) {
/* Executes a command on the TPM.
*/
-static void TpmExecute(const uint8_t *in, const uint32_t in_len,
+static VbError_t TpmExecute(const uint8_t *in, const uint32_t in_len,
uint8_t *out, uint32_t *pout_len) {
uint8_t response[TPM_MAX_COMMAND_SIZE];
if (in_len <= 0) {
- VbExError("invalid command length %d for command 0x%x\n", in_len, in[9]);
+ return DoError(TPM_E_INPUT_TOO_SMALL,
+ "invalid command length %d for command 0x%x\n",
+ in_len, in[9]);
} else if (tpm_fd < 0) {
- VbExError("the TPM device was not opened. Forgot to call TlclLibInit?\n");
+ return DoError(TPM_E_NO_DEVICE,
+ "the TPM device was not opened. " \
+ "Forgot to call TlclLibInit?\n");
} else {
int n = write(tpm_fd, in, in_len);
if (n != in_len) {
- VbExError("write failure to TPM device: %s\n", strerror(errno));
+ return DoError(TPM_E_WRITE_FAILURE,
+ "write failure to TPM device: %s\n", strerror(errno));
}
n = read(tpm_fd, response, sizeof(response));
if (n == 0) {
- VbExError("null read from TPM device\n");
+ return DoError(TPM_E_READ_EMPTY, "null read from TPM device\n");
} else if (n < 0) {
- VbExError("read failure from TPM device: %s\n", strerror(errno));
+ return DoError(TPM_E_READ_FAILURE, "read failure from TPM device: %s\n",
+ strerror(errno));
} else {
if (n > *pout_len) {
- VbExError("TPM response too long for output buffer\n");
+ return DoError(TPM_E_RESPONSE_TOO_LARGE,
+ "TPM response too long for output buffer\n");
} else {
*pout_len = n;
Memcpy(out, response, n);
}
}
}
+ return VBERROR_SUCCESS;
}
@@ -101,6 +125,9 @@ POSSIBLY_UNUSED static INLINE int TpmResponseSize(const uint8_t* buffer) {
VbError_t VbExTpmInit(void) {
+ char *no_exit = getenv("TPM_NO_EXIT");
+ if (no_exit)
+ exit_on_failure = !atoi(no_exit);
return VbExTpmOpen();
}
@@ -127,8 +154,8 @@ VbError_t VbExTpmOpen(void) {
tpm_fd = open(device_path, O_RDWR);
if (tpm_fd < 0) {
- VbExError("TPM: Cannot open TPM device %s: %s\n",
- device_path, strerror(errno));
+ return DoError(TPM_E_NO_DEVICE, "TPM: Cannot open TPM device %s: %s\n",
+ device_path, strerror(errno));
}
return VBERROR_SUCCESS;
@@ -157,10 +184,13 @@ VbError_t VbExTpmSendReceive(const uint8_t* request, uint32_t request_length,
#ifndef NDEBUG
int tag, response_tag;
#endif
+ VbError_t result;
struct timeval before, after;
gettimeofday(&before, NULL);
- TpmExecute(request, request_length, response, response_length);
+ result = TpmExecute(request, request_length, response, response_length);
+ if (result != VBERROR_SUCCESS)
+ return result;
gettimeofday(&after, NULL);
#ifdef VBOOT_DEBUG
diff --git a/utility/mount-encrypted.c b/utility/mount-encrypted.c
index 94f54d8a..2c975a39 100644
--- a/utility/mount-encrypted.c
+++ b/utility/mount-encrypted.c
@@ -113,21 +113,12 @@ static int has_tpm = 0;
static void tpm_init(void)
{
- int tpm;
+ uint32_t result;
DEBUG("Opening TPM");
- tpm = open(kTpmDev, O_RDWR);
- if (tpm >= 0) {
- has_tpm = 1;
- close(tpm);
- }
- else {
- /* TlclLibInit does not fail, it exits, so instead,
- * have it open /dev/null if the TPM is not available.
- */
- setenv("TPM_DEVICE_PATH", kNullDev, 1);
- }
- TlclLibInit();
+ setenv("TPM_NO_EXIT", "1", 1);
+ result = TlclLibInit();
+ has_tpm = (result == TPM_SUCCESS);
INFO("TPM %s", has_tpm ? "ready" : "not available");
}