blob: 9442b7792c3004483475d9465f8ae01a4a4a264a [file] [log] [blame]
Randall Spanglerc324fbf2011-03-04 12:19:25 -08001/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved.
Gaurav Shahce0cc302010-03-24 13:48:55 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Functions for querying, manipulating and locking rollback indices
6 * stored in the TPM NVRAM.
7 */
8
9#include "rollback_index.h"
10
Gaurav Shahce0cc302010-03-24 13:48:55 -070011#include "tlcl.h"
Gaurav Shahb64faaa2011-03-15 16:36:29 -070012#include "tpm_bootmode.h"
Gaurav Shah887e3d42010-04-27 16:26:48 -070013#include "tss_constants.h"
Randall Spanglerf3029052010-06-16 13:42:58 -070014#include "utility.h"
Gaurav Shahce0cc302010-03-24 13:48:55 -070015
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -070016static int g_rollback_recovery_mode = 0;
Gaurav Shahce0cc302010-03-24 13:48:55 -070017
vbendeb3ecaf772010-06-24 16:19:53 -070018/* disable MSVC warning on const logical expression (as in } while(0);) */
19__pragma(warning (disable: 4127))
20
Luigi Semenzato4f11c362010-06-10 11:01:04 -070021#define RETURN_ON_FAILURE(tpm_command) do { \
22 uint32_t result; \
23 if ((result = (tpm_command)) != TPM_SUCCESS) { \
Randall Spangler7a786b72010-07-08 13:29:42 -070024 VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \
Luigi Semenzato4f11c362010-06-10 11:01:04 -070025 return result; \
26 } \
Luigi Semenzato59204c52010-06-09 13:37:15 -070027 } while (0)
28
Randall Spangler4abede32010-08-12 16:40:32 -070029
Luigi Semenzato416f6812010-07-08 12:12:12 -070030uint32_t TPMClearAndReenable(void) {
Randall Spangler3e1081f2010-07-19 10:04:21 -070031 VBDEBUG(("TPM: Clear and re-enable\n"));
Luigi Semenzato361049c2010-06-22 13:37:53 -070032 RETURN_ON_FAILURE(TlclForceClear());
33 RETURN_ON_FAILURE(TlclSetEnable());
34 RETURN_ON_FAILURE(TlclSetDeactivated(0));
Randall Spanglerada3fa92010-07-20 15:35:49 -070035
Luigi Semenzato361049c2010-06-22 13:37:53 -070036 return TPM_SUCCESS;
37}
38
Randall Spangler4abede32010-08-12 16:40:32 -070039
Luigi Semenzato361049c2010-06-22 13:37:53 -070040/* Like TlclWrite(), but checks for write errors due to hitting the 64-write
41 * limit and clears the TPM when that happens. This can only happen when the
42 * TPM is unowned, so it is OK to clear it (and we really have no choice).
43 * This is not expected to happen frequently, but it could happen.
44 */
Randall Spangler4abede32010-08-12 16:40:32 -070045static uint32_t SafeWrite(uint32_t index, const void* data, uint32_t length) {
Luigi Semenzato361049c2010-06-22 13:37:53 -070046 uint32_t result = TlclWrite(index, data, length);
47 if (result == TPM_E_MAXNVWRITES) {
48 RETURN_ON_FAILURE(TPMClearAndReenable());
49 return TlclWrite(index, data, length);
50 } else {
51 return result;
52 }
53}
54
Randall Spangler4abede32010-08-12 16:40:32 -070055
Luigi Semenzato8510d912010-07-08 15:40:30 -070056/* Similarly to SafeWrite(), this ensures we don't fail a DefineSpace because
57 * we hit the TPM write limit. This is even less likely to happen than with
58 * writes because we only define spaces once at initialization, but we'd rather
59 * be paranoid about this.
60 */
61static uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size) {
62 uint32_t result = TlclDefineSpace(index, perm, size);
63 if (result == TPM_E_MAXNVWRITES) {
64 RETURN_ON_FAILURE(TPMClearAndReenable());
65 return TlclDefineSpace(index, perm, size);
66 } else {
67 return result;
68 }
69}
70
Randall Spangler4abede32010-08-12 16:40:32 -070071
72/* Functions to read and write firmware and kernel spaces. */
73static uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf) {
74 return TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
Luigi Semenzato4f11c362010-06-10 11:01:04 -070075}
76
Randall Spangler4abede32010-08-12 16:40:32 -070077static uint32_t WriteSpaceFirmware(const RollbackSpaceFirmware* rsf) {
78 return SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
Luigi Semenzato4f11c362010-06-10 11:01:04 -070079}
80
Randall Spanglerbb5d9f12010-08-16 15:36:07 -070081#ifndef DISABLE_ROLLBACK_TPM
Randall Spangler4abede32010-08-12 16:40:32 -070082static uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) {
83 return TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
84}
Randall Spanglerbb5d9f12010-08-16 15:36:07 -070085#endif
Randall Spangler4abede32010-08-12 16:40:32 -070086
87static uint32_t WriteSpaceKernel(const RollbackSpaceKernel* rsk) {
88 return SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
89}
90
Luigi Semenzato377557f2010-08-31 13:20:53 -070091/* Performs one-time initializations. Creates the NVRAM spaces, and sets their
92 * initial values as needed. Sets the nvLocked bit and ensures the physical
93 * presence command is enabled and locked.
94 */
95static uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware* rsf,
96 RollbackSpaceKernel* rsk) {
Randall Spangler4abede32010-08-12 16:40:32 -070097 static const RollbackSpaceFirmware rsf_init = {
98 ROLLBACK_SPACE_FIRMWARE_VERSION, 0, 0, 0};
99 static const RollbackSpaceKernel rsk_init = {
100 ROLLBACK_SPACE_KERNEL_VERSION, ROLLBACK_SPACE_KERNEL_UID, 0, 0};
Randall Spangler6eee2202010-09-15 15:57:58 -0700101 TPM_PERMANENT_FLAGS pflags;
102 uint32_t result;
Gaurav Shahce0cc302010-03-24 13:48:55 -0700103
Luigi Semenzato377557f2010-08-31 13:20:53 -0700104 VBDEBUG(("TPM: One-time initialization\n"));
105
Luigi Semenzato83c37142011-03-17 10:33:41 -0700106 /* Do a full test. This only happens the first time the device is turned on
107 * in the factory, so performance is not an issue. This is almost certainly
108 * not necessary, but it gives us more confidence about some code paths below
109 * that are difficult to test---specifically the ones that set lifetime
110 * flags, and are only executed once per physical TPM. */
111 result = TlclSelfTestFull();
112 if (result != TPM_SUCCESS)
113 return result;
114
Randall Spangler6eee2202010-09-15 15:57:58 -0700115 result = TlclGetPermanentFlags(&pflags);
116 if (result != TPM_SUCCESS)
117 return result;
118
119 /* TPM may come from the factory without physical presence finalized. Fix
120 * if necessary. */
121 VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n",
122 pflags.physicalPresenceLifetimeLock));
123 if (!pflags.physicalPresenceLifetimeLock) {
124 VBDEBUG(("TPM: Finalizing physical presence\n"));
125 RETURN_ON_FAILURE(TlclFinalizePhysicalPresence());
126 }
Gaurav Shahce0cc302010-03-24 13:48:55 -0700127
Randall Spangler4abede32010-08-12 16:40:32 -0700128 /* The TPM will not enforce the NV authorization restrictions until the
Randall Spangler63dffcb2010-08-05 15:13:14 -0700129 * execution of a TPM_NV_DefineSpace with the handle of TPM_NV_INDEX_LOCK.
Luigi Semenzato377557f2010-08-31 13:20:53 -0700130 * Here we create that space if it doesn't already exist. */
Randall Spangler6eee2202010-09-15 15:57:58 -0700131 VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked));
132 if (!pflags.nvLocked) {
Randall Spangler3e1081f2010-07-19 10:04:21 -0700133 VBDEBUG(("TPM: Enabling NV locking\n"));
134 RETURN_ON_FAILURE(TlclSetNvLocked());
135 }
136
Randall Spangler6eee2202010-09-15 15:57:58 -0700137 /* Clear TPM owner, in case the TPM is already owned for some reason. */
138 VBDEBUG(("TPM: Clearing owner\n"));
Luigi Semenzato5be730c2010-09-23 17:05:12 -0700139 RETURN_ON_FAILURE(TPMClearAndReenable());
Randall Spangler6eee2202010-09-15 15:57:58 -0700140
Luigi Semenzato377557f2010-08-31 13:20:53 -0700141 /* Initializes the firmware and kernel spaces */
Randall Spangler4abede32010-08-12 16:40:32 -0700142 Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware));
Randall Spangler4abede32010-08-12 16:40:32 -0700143 Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel));
Gaurav Shahce0cc302010-03-24 13:48:55 -0700144
Luigi Semenzato377557f2010-08-31 13:20:53 -0700145 /* Defines and sets firmware and kernel spaces */
Randall Spangler4abede32010-08-12 16:40:32 -0700146 RETURN_ON_FAILURE(SafeDefineSpace(FIRMWARE_NV_INDEX,
147 TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE,
148 sizeof(RollbackSpaceFirmware)));
149 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
150 RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE,
151 sizeof(RollbackSpaceKernel)));
152 RETURN_ON_FAILURE(WriteSpaceKernel(rsk));
Luigi Semenzato59204c52010-06-09 13:37:15 -0700153 return TPM_SUCCESS;
Gaurav Shahce0cc302010-03-24 13:48:55 -0700154}
155
Luigi Semenzato2666f102010-06-15 08:12:32 -0700156
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700157/* SetupTPM starts the TPM and establishes the root of trust for the
158 * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
159 * TPM hardware failure. 3 An unexpected TPM state due to some attack. In
160 * general we cannot easily distinguish the kind of failure, so our strategy is
161 * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
162 * again, which executes (almost) the same sequence of operations. There is a
163 * good chance that, if recovery mode was entered because of a TPM failure, the
164 * failure will repeat itself. (In general this is impossible to guarantee
165 * because we have no way of creating the exact TPM initial state at the
166 * previous boot.) In recovery mode, we ignore the failure and continue, thus
167 * giving the recovery kernel a chance to fix things (that's why we don't set
168 * bGlobalLock). The choice is between a knowingly insecure device and a
169 * bricked device.
170 *
171 * As a side note, observe that we go through considerable hoops to avoid using
172 * the STCLEAR permissions for the index spaces. We do this to avoid writing
173 * to the TPM flashram at every reboot or wake-up, because of concerns about
174 * the durability of the NVRAM.
175 */
Randall Spangler4abede32010-08-12 16:40:32 -0700176uint32_t SetupTPM(int recovery_mode, int developer_mode,
177 RollbackSpaceFirmware* rsf) {
178
Randall Spangler4abede32010-08-12 16:40:32 -0700179 int rsf_dirty = 0;
180 uint8_t new_flags = 0;
Luigi Semenzato596b6402010-05-27 14:04:52 -0700181 uint8_t disable;
182 uint8_t deactivated;
Luigi Semenzato416f6812010-07-08 12:12:12 -0700183 uint32_t result;
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700184
Randall Spangler3e1081f2010-07-19 10:04:21 -0700185 VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode));
186
Luigi Semenzato26718ca2010-09-24 12:50:45 -0700187 if (recovery_mode)
188 g_rollback_recovery_mode = 1; /* Global variables are usable in
189 * recovery mode */
190
Che-Liang Chiou5d9509c2010-12-16 14:11:17 +0800191 RETURN_ON_FAILURE(TlclLibInit());
Randall Spangler3e1081f2010-07-19 10:04:21 -0700192
Luigi Semenzato59204c52010-06-09 13:37:15 -0700193 RETURN_ON_FAILURE(TlclStartup());
Luigi Semenzato06fbb162011-03-16 17:33:23 -0700194 /* Some TPMs start the self test automatically at power on. In that case we
195 * don't need to call ContinueSelfTest. On some (other) TPMs,
196 * ContinueSelfTest may block. In that case, we definitely don't want to
197 * call it here. For TPMs in the intersection of these two sets, we're
198 * screwed. (In other words: TPMs that require manually starting the
199 * self-test AND block will have poor performance until we split
200 * TlclSendReceive() into Send() and Receive(), and have a state machine to
201 * control setup.)
202 *
203 * This comment is likely to become obsolete in the near future, so don't
204 * trust it. It may have not been updated.
205 */
206#ifdef TPM_MANUAL_SELFTEST
207#ifdef TPM_BLOCKING_CONTINUESELFTEST
208#warning "lousy TPM!"
209#endif
Luigi Semenzato59204c52010-06-09 13:37:15 -0700210 RETURN_ON_FAILURE(TlclContinueSelfTest());
Luigi Semenzato06fbb162011-03-16 17:33:23 -0700211#endif
Luigi Semenzato377557f2010-08-31 13:20:53 -0700212 result = TlclAssertPhysicalPresence();
213 if (result != 0) {
214 /* It is possible that the TPM was delivered with the physical presence
215 * command disabled. This tries enabling it, then tries asserting PP
216 * again.
217 */
218 RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable());
219 RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
220 }
Randall Spangler4abede32010-08-12 16:40:32 -0700221
Luigi Semenzato377557f2010-08-31 13:20:53 -0700222 /* Checks that the TPM is enabled and activated. */
Randall Spangler3e1081f2010-07-19 10:04:21 -0700223 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL));
Luigi Semenzato596b6402010-05-27 14:04:52 -0700224 if (disable || deactivated) {
Randall Spangler4abede32010-08-12 16:40:32 -0700225 VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n",
226 disable, deactivated));
Luigi Semenzato59204c52010-06-09 13:37:15 -0700227 RETURN_ON_FAILURE(TlclSetEnable());
228 RETURN_ON_FAILURE(TlclSetDeactivated(0));
Randall Spangler3e1081f2010-07-19 10:04:21 -0700229 VBDEBUG(("TPM: Must reboot to re-enable\n"));
Luigi Semenzato2666f102010-06-15 08:12:32 -0700230 return TPM_E_MUST_REBOOT;
Luigi Semenzato596b6402010-05-27 14:04:52 -0700231 }
Randall Spangler4abede32010-08-12 16:40:32 -0700232
Luigi Semenzato377557f2010-08-31 13:20:53 -0700233 /* Reads the firmware space. */
Randall Spangler4abede32010-08-12 16:40:32 -0700234 result = ReadSpaceFirmware(rsf);
235 if (TPM_E_BADINDEX == result) {
Randall Spanglerbb5d9f12010-08-16 15:36:07 -0700236 RollbackSpaceKernel rsk;
237
Randall Spangler4abede32010-08-12 16:40:32 -0700238 /* This is the first time we've run, and the TPM has not been
Luigi Semenzato377557f2010-08-31 13:20:53 -0700239 * initialized. This initializes it. */
Randall Spangler4abede32010-08-12 16:40:32 -0700240 VBDEBUG(("TPM: Not initialized yet.\n"));
Luigi Semenzato377557f2010-08-31 13:20:53 -0700241 RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk));
Randall Spangler4abede32010-08-12 16:40:32 -0700242 } else if (TPM_SUCCESS != result) {
243 VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n"));
244 return TPM_E_CORRUPTED_STATE;
245 }
246 VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
247 rsf->struct_version, rsf->flags, rsf->fw_versions));
248
Luigi Semenzato377557f2010-08-31 13:20:53 -0700249 /* Clears ownership if developer flag has toggled */
Randall Spangler4abede32010-08-12 16:40:32 -0700250 if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
251 (rsf->flags & FLAG_LAST_BOOT_DEVELOPER)) {
252 VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
253 RETURN_ON_FAILURE(TPMClearAndReenable());
Luigi Semenzato2666f102010-06-15 08:12:32 -0700254 }
Randall Spangler4abede32010-08-12 16:40:32 -0700255
Luigi Semenzato377557f2010-08-31 13:20:53 -0700256 /* Updates flags */
Randall Spangler4abede32010-08-12 16:40:32 -0700257 if (developer_mode)
258 new_flags |= FLAG_LAST_BOOT_DEVELOPER;
Randall Spangler4abede32010-08-12 16:40:32 -0700259 if (rsf->flags != new_flags) {
260 rsf->flags = new_flags;
261 rsf_dirty = 1;
262 }
263
Luigi Semenzato377557f2010-08-31 13:20:53 -0700264 /* If firmware space is dirty, this flushes it back to the TPM */
Randall Spangler4abede32010-08-12 16:40:32 -0700265 if (rsf_dirty) {
266 VBDEBUG(("TPM: Updating firmware space.\n"));
267 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
268 }
269
Randall Spangler3e1081f2010-07-19 10:04:21 -0700270 VBDEBUG(("TPM: SetupTPM() succeeded\n"));
Luigi Semenzato59204c52010-06-09 13:37:15 -0700271 return TPM_SUCCESS;
Gaurav Shahce0cc302010-03-24 13:48:55 -0700272}
273
vbendeb3ecaf772010-06-24 16:19:53 -0700274/* disable MSVC warnings on unused arguments */
275__pragma(warning (disable: 4100))
Randall Spangler10788382010-06-23 15:35:31 -0700276
Randall Spangler39f66112010-07-14 09:10:23 -0700277
278#ifdef DISABLE_ROLLBACK_TPM
279
Randall Spanglerada3fa92010-07-20 15:35:49 -0700280/* Dummy implementations which don't support TPM rollback protection */
Randall Spangler39f66112010-07-14 09:10:23 -0700281
Randall Spangler1fe16072010-09-02 11:37:51 -0700282uint32_t RollbackS3Resume(void) {
283#ifndef CHROMEOS_ENVIRONMENT
284 /* Initialize the TPM, but ignore return codes. In ChromeOS
285 * environment, don't even talk to the TPM. */
286 TlclLibInit();
287 TlclResume();
Randall Spangler1fe16072010-09-02 11:37:51 -0700288#endif
289 return TPM_SUCCESS;
290}
291
Randall Spangler66680282010-08-16 12:33:44 -0700292uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) {
Randall Spanglerada3fa92010-07-20 15:35:49 -0700293#ifndef CHROMEOS_ENVIRONMENT
Luigi Semenzato377557f2010-08-31 13:20:53 -0700294 /* Initializes the TPM, but ignores return codes. In ChromeOS
295 * environment, doesn't even talk to the TPM. */
Randall Spanglerada3fa92010-07-20 15:35:49 -0700296 TlclLibInit();
297 TlclStartup();
Randall Spangler7c88d4c2010-09-09 11:14:59 -0700298 TlclContinueSelfTest();
Randall Spanglerada3fa92010-07-20 15:35:49 -0700299#endif
Randall Spangler66680282010-08-16 12:33:44 -0700300 *version = 0;
Randall Spangler39f66112010-07-14 09:10:23 -0700301 return TPM_SUCCESS;
302}
303
Randall Spangler66680282010-08-16 12:33:44 -0700304uint32_t RollbackFirmwareWrite(uint32_t version) {
Randall Spangler39f66112010-07-14 09:10:23 -0700305 return TPM_SUCCESS;
306}
307
308uint32_t RollbackFirmwareLock(void) {
309 return TPM_SUCCESS;
310}
311
312uint32_t RollbackKernelRecovery(int developer_mode) {
Randall Spanglerada3fa92010-07-20 15:35:49 -0700313#ifndef CHROMEOS_ENVIRONMENT
Luigi Semenzato377557f2010-08-31 13:20:53 -0700314 /* Initializes the TPM, but ignore return codes. In ChromeOS
315 * environment, doesn't even talk to the TPM. */
Randall Spanglerada3fa92010-07-20 15:35:49 -0700316 TlclLibInit();
317 TlclStartup();
Randall Spangler63dffcb2010-08-05 15:13:14 -0700318 TlclSelfTestFull();
Randall Spanglerada3fa92010-07-20 15:35:49 -0700319#endif
Randall Spangler39f66112010-07-14 09:10:23 -0700320 return TPM_SUCCESS;
321}
322
Randall Spangler66680282010-08-16 12:33:44 -0700323uint32_t RollbackKernelRead(uint32_t* version) {
324 *version = 0;
Randall Spangler39f66112010-07-14 09:10:23 -0700325 return TPM_SUCCESS;
326}
327
Randall Spangler66680282010-08-16 12:33:44 -0700328uint32_t RollbackKernelWrite(uint32_t version) {
Randall Spangler39f66112010-07-14 09:10:23 -0700329 return TPM_SUCCESS;
330}
331
332uint32_t RollbackKernelLock(void) {
333 return TPM_SUCCESS;
334}
335
336#else
Randall Spangler1fe16072010-09-02 11:37:51 -0700337
338uint32_t RollbackS3Resume(void) {
Luigi Semenzato98285942010-09-07 09:56:19 -0700339 uint32_t result;
Che-Liang Chiou5d9509c2010-12-16 14:11:17 +0800340 RETURN_ON_FAILURE(TlclLibInit());
Luigi Semenzato98285942010-09-07 09:56:19 -0700341 result = TlclResume();
342 if (result == TPM_E_INVALID_POSTINIT) {
Randall Spangler7c88d4c2010-09-09 11:14:59 -0700343 /* We're on a platform where the TPM maintains power in S3, so
Randall Spangler44f34b52010-11-23 14:17:21 -0800344 it's already initialized. */
Luigi Semenzato98285942010-09-07 09:56:19 -0700345 return TPM_SUCCESS;
346 }
Randall Spangler44f34b52010-11-23 14:17:21 -0800347 return result;
Randall Spangler1fe16072010-09-02 11:37:51 -0700348}
349
350
Randall Spangler66680282010-08-16 12:33:44 -0700351uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) {
Randall Spangler4abede32010-08-12 16:40:32 -0700352 RollbackSpaceFirmware rsf;
Randall Spangler10788382010-06-23 15:35:31 -0700353
Randall Spangler4abede32010-08-12 16:40:32 -0700354 RETURN_ON_FAILURE(SetupTPM(0, developer_mode, &rsf));
Randall Spangler66680282010-08-16 12:33:44 -0700355 *version = rsf.fw_versions;
Randall Spanglerbb5d9f12010-08-16 15:36:07 -0700356 VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions));
Randall Spangler10788382010-06-23 15:35:31 -0700357 return TPM_SUCCESS;
358}
359
Gaurav Shahb64faaa2011-03-15 16:36:29 -0700360
Randall Spangler66680282010-08-16 12:33:44 -0700361uint32_t RollbackFirmwareWrite(uint32_t version) {
Randall Spangler4abede32010-08-12 16:40:32 -0700362 RollbackSpaceFirmware rsf;
Randall Spangler4abede32010-08-12 16:40:32 -0700363
364 RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf));
Randall Spangler66680282010-08-16 12:33:44 -0700365 VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions,
366 (int)version));
367 rsf.fw_versions = version;
Randall Spangler4abede32010-08-12 16:40:32 -0700368 return WriteSpaceFirmware(&rsf);
Randall Spangler10788382010-06-23 15:35:31 -0700369}
370
371uint32_t RollbackFirmwareLock(void) {
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700372 return TlclSetGlobalLock();
Randall Spangler10788382010-06-23 15:35:31 -0700373}
374
375uint32_t RollbackKernelRecovery(int developer_mode) {
Gaurav Shah82602d72010-10-21 14:40:38 -0700376 uint32_t rvs, rve;
Randall Spangler4abede32010-08-12 16:40:32 -0700377 RollbackSpaceFirmware rsf;
Randall Spangler3e2c7422010-10-18 16:43:19 -0700378
379 /* In recovery mode we ignore TPM malfunctions or corruptions, and *
380 * leave the TPM complelely unlocked; we call neither
381 * TlclSetGlobalLock() nor TlclLockPhysicalPresence(). The recovery
382 * kernel will fix the TPM (if needed) and lock it ASAP. We leave
Randall Spangler4abede32010-08-12 16:40:32 -0700383 * Physical Presence on in either case. */
Gaurav Shah82602d72010-10-21 14:40:38 -0700384 rvs = SetupTPM(1, developer_mode, &rsf);
Gaurav Shahb64faaa2011-03-15 16:36:29 -0700385 rve = SetTPMBootModeState(developer_mode,
386 1, /* Recovery Mode Status. */
387 0); /* In recovery mode, there is no RW firmware
388 * keyblock flag. */
Gaurav Shah82602d72010-10-21 14:40:38 -0700389 return (TPM_SUCCESS == rvs) ? rve : rvs;
Randall Spangler10788382010-06-23 15:35:31 -0700390}
391
Randall Spangler66680282010-08-16 12:33:44 -0700392uint32_t RollbackKernelRead(uint32_t* version) {
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700393 if (g_rollback_recovery_mode) {
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700394 *version = 0;
395 } else {
Randall Spangler4abede32010-08-12 16:40:32 -0700396 RollbackSpaceKernel rsk;
Randall Spanglerbb5d9f12010-08-16 15:36:07 -0700397 uint32_t perms;
398
399 /* Read the kernel space and verify its permissions. If the kernel
400 * space has the wrong permission, or it doesn't contain the right
401 * identifier, we give up. This will need to be fixed by the
402 * recovery kernel. We have to worry about this because at any time
403 * (even with PP turned off) the TPM owner can remove and redefine a
404 * PP-protected space (but not write to it). */
Randall Spangler4abede32010-08-12 16:40:32 -0700405 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
Randall Spanglerbb5d9f12010-08-16 15:36:07 -0700406 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms));
407 if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != rsk.uid)
408 return TPM_E_CORRUPTED_STATE;
409
Randall Spangler66680282010-08-16 12:33:44 -0700410 *version = rsk.kernel_versions;
411 VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions));
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700412 }
Randall Spangler10788382010-06-23 15:35:31 -0700413 return TPM_SUCCESS;
414}
415
Randall Spangler66680282010-08-16 12:33:44 -0700416uint32_t RollbackKernelWrite(uint32_t version) {
Randall Spangler4abede32010-08-12 16:40:32 -0700417 if (g_rollback_recovery_mode) {
418 return TPM_SUCCESS;
419 } else {
420 RollbackSpaceKernel rsk;
Randall Spangler4abede32010-08-12 16:40:32 -0700421 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
422 VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", (int)rsk.kernel_versions,
Randall Spangler66680282010-08-16 12:33:44 -0700423 (int)version));
424 rsk.kernel_versions = version;
Randall Spangler4abede32010-08-12 16:40:32 -0700425 return WriteSpaceKernel(&rsk);
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700426 }
Randall Spangler10788382010-06-23 15:35:31 -0700427}
428
429uint32_t RollbackKernelLock(void) {
Randall Spangler4abede32010-08-12 16:40:32 -0700430 if (g_rollback_recovery_mode) {
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700431 return TPM_SUCCESS;
Randall Spangler4abede32010-08-12 16:40:32 -0700432 } else {
433 return TlclLockPhysicalPresence();
Luigi Semenzato2b9ddae2010-06-28 13:34:31 -0700434 }
Randall Spangler10788382010-06-23 15:35:31 -0700435}
Randall Spangler39f66112010-07-14 09:10:23 -0700436
437#endif // DISABLE_ROLLBACK_TPM