7 #include <libtpms/tpm_error.h>
8 #include <libtpms/tpm_nvfilename.h>
10 #include "compiler_dependencies.h"
11 #include "sys_dependencies.h"
13 #include "swtpm_debug.h"
14 #include "swtpm_nvstore.h"
15 #include "swtpm_nvstore_linear.h"
22 struct nvram_linear_store_ops
*ops
;
26 struct nvram_linear_hdr
*hdr
; /* points into *data */
30 Attempts to flush the header of the linear state, if required by the store.
33 SWTPM_NVRAM_Linear_FlushHeader(const char* uri
)
35 if (state
.ops
->flush
) {
36 return state
.ops
->flush(uri
, 0, le16toh(state
.hdr
->hdrsize
));
42 Attempts a resize and ensures that state is updated correctly and the given
43 new_size could actually be reached.
46 SWTPM_NVRAM_Linear_SafeResize(const char* uri
, uint32_t new_size
)
51 if (!state
.ops
->resize
) {
52 return new_size
< state
.length
? 0 : TPM_SIZE
;
55 rc
= state
.ops
->resize(uri
, &state
.data
, &result
, new_size
);
60 /* base address might have changed, update pointers */
61 state
.hdr
= (struct nvram_linear_hdr
*)state
.data
;
62 state
.length
= result
;
64 if (result
< new_size
) {
71 #define FILE_NR_INVALID 0xffffffff
74 Returns the offset into the state.hdr.files array given a TPM state name and
75 number. Will be FILE_NR_INVALID if out of bounds or unknown name.
78 SWTPM_NVRAM_Linear_GetFileNr(const char *name
)
81 if (strcmp(name
, TPM_PERMANENT_ALL_NAME
) == 0) {
83 } else if (strcmp(name
, TPM_VOLATILESTATE_NAME
) == 0) {
85 } else if (strcmp(name
, TPM_SAVESTATE_NAME
) == 0) {
88 logprintf(STDERR_FILENO
,
89 "SWTPM_NVRAM_Linear_GetFileOffset: Unknown name '%s'\n",
91 return FILE_NR_INVALID
;
93 if (rc
>= SWTPM_NVSTORE_LINEAR_MAX_STATES
) {
94 logprintf(STDERR_FILENO
,
95 "SWTPM_NVRAM_Linear_GetFileOffset: File limit exceeded: %d\n",
97 return FILE_NR_INVALID
;
103 Allocate a new file entry in the linear address space of state.data.
104 The new file will be placed at the end.
106 Importantly, this may perform a resize, so pointers into state.data or
107 state.hdr must not be kept over this function call.
110 SWTPM_NVRAM_Linear_AllocFile(const char *uri
, uint32_t file_nr
, uint32_t size
)
113 struct nvram_linear_hdr_file
*file
;
114 uint32_t new_offset
= le16toh(state
.hdr
->hdrsize
);
118 uint32_t section_size
= size
;
119 ROUND_TO_NEXT_POWER_OF_2_32(section_size
);
121 /* find end of current last file */
122 for (i
= 0; i
< SWTPM_NVSTORE_LINEAR_MAX_STATES
; i
++) {
123 file
= &state
.hdr
->files
[i
];
128 cur_end
= le32toh(file
->offset
) + le32toh(file
->section_length
);
129 if (cur_end
> new_offset
) {
130 new_offset
= cur_end
;
134 new_size
= new_offset
+ section_size
;
135 rc
= SWTPM_NVRAM_Linear_SafeResize(uri
, new_size
);
140 file
= &state
.hdr
->files
[file_nr
];
141 file
->section_length
= htole32(section_size
);
142 file
->data_length
= htole32(size
);
143 file
->offset
= htole32(new_offset
);
145 TPM_DEBUG("SWTPM_NVRAM_Linear_AllocFile: allocated file %d @ %d "
146 "(len=%d section=%d)\n",
147 file_nr
, new_offset
, size
, section_size
);
153 Deallocate a file from state.data. It's entry in state.hdr will be zeroed,
154 and the file length adjusted accordingly (if 'resize' is TRUE).
155 If the file was not at the end, any following files will be moved forward,
156 as to not leave any holes. This simplifies the allocator strategy, since it
157 allows new files to always be placed at the end.
159 If resize is true, this may perform a resize, so pointers into state.data or
160 state.hdr must not be kept over this function call.
163 SWTPM_NVRAM_Linear_RemoveFile(const char *uri
,
168 uint32_t next_offset
= 0xffffffff;
169 uint32_t state_end
= 0;
171 uint32_t i
, cur_offset
, cur_end
;
172 struct nvram_linear_hdr_file
*file
;
173 struct nvram_linear_hdr_file old_file
= state
.hdr
->files
[file_nr
];
175 if (old_file
.offset
== 0) {
179 TPM_DEBUG("SWTPM_NVRAM_Linear_RemoveFile: removing filenr %d (resize=%d)\n",
182 state
.hdr
->files
[file_nr
].offset
= 0;
183 state
.hdr
->files
[file_nr
].data_length
= 0;
184 state
.hdr
->files
[file_nr
].section_length
= 0;
186 /* find offset of file right after the one we remove, and adjust offsets */
187 for (i
= 0; i
< SWTPM_NVSTORE_LINEAR_MAX_STATES
; i
++) {
188 file
= &state
.hdr
->files
[i
];
193 cur_offset
= le32toh(file
->offset
);
194 if (cur_offset
> le32toh(old_file
.offset
)) {
195 if (cur_offset
< next_offset
) {
196 next_offset
= cur_offset
;
198 cur_end
= cur_offset
+ le32toh(file
->section_length
);
199 if (cur_end
> state_end
) {
202 file
->offset
= htole32(cur_offset
-
203 le32toh(old_file
.section_length
));
207 if (next_offset
!= 0xffffffff) {
208 TPM_DEBUG("SWTPM_NVRAM_Linear_RemoveFile: compacting\n");
209 /* if we weren't the end, compact by moving following files forward */
210 memmove(state
.data
+ le32toh(old_file
.offset
),
211 state
.data
+ next_offset
,
212 state_end
- next_offset
);
216 new_len
= state
.length
- le32toh(old_file
.section_length
);
217 rc
= SWTPM_NVRAM_Linear_SafeResize(uri
, new_len
);
219 state
.length
= new_len
;
227 SWTPM_NVRAM_Prepare_Linear(const char *uri
)
231 TPM_DEBUG("SWTPM_NVRAM_Prepare_Linear: uri='%s'\n", uri
);
233 if (state
.initialized
) {
234 if (strcmp(state
.loaded_uri
, uri
) == 0) {
235 /* same URI loaded, this is okay, nothing to be done */
239 logprintf(STDERR_FILENO
,
240 "SWTPM_NVRAM_PrepareLinear: Cannot prepare twice\n");
244 state
.loaded_uri
= malloc(strlen(uri
) + 1);
245 strcpy(state
.loaded_uri
, uri
);
247 /* TODO: Parse URI prefixes ("iscsi://", "rbd://", etc...) */
248 state
.ops
= &nvram_linear_file_ops
;
250 if ((rc
= state
.ops
->open(uri
, &state
.data
, &state
.length
))) {
254 state
.hdr
= (struct nvram_linear_hdr
*)state
.data
;
256 if (le64toh(state
.hdr
->magic
) != SWTPM_NVSTORE_LINEAR_MAGIC
) {
257 logprintf(STDOUT_FILENO
,
258 "Formatting '%s' as new linear NVRAM store\n",
261 state
.hdr
->magic
= htole64(SWTPM_NVSTORE_LINEAR_MAGIC
);
262 state
.hdr
->version
= SWTPM_NVSTORE_LINEAR_VERSION
;
263 state
.hdr
->hdrsize
= htole16(sizeof(struct nvram_linear_hdr
));
264 memset(&state
.hdr
->files
, 0, sizeof(state
.hdr
->files
));
266 SWTPM_NVRAM_Linear_FlushHeader(uri
);
269 /* assume valid state found */
270 if (state
.hdr
->version
> SWTPM_NVSTORE_LINEAR_VERSION
) {
271 logprintf(STDERR_FILENO
,
272 "SWTPM_NVRAM_PrepareLinear: Unknown format version: %d\n",
278 state
.initialized
= TRUE
;
283 SWTPM_NVRAM_LoadData_Linear(unsigned char **data
,
285 uint32_t tpm_number SWTPM_ATTR_UNUSED
,
287 const char *uri SWTPM_ATTR_UNUSED
)
290 uint32_t file_offset
;
291 uint32_t file_data_len
;
292 struct nvram_linear_hdr_file
*file
;
294 TPM_DEBUG("SWTPM_NVRAM_LoadData_Linear: request for %s:%d\n",
297 file_nr
= SWTPM_NVRAM_Linear_GetFileNr(name
);
298 if (file_nr
== FILE_NR_INVALID
) {
302 file
= &state
.hdr
->files
[file_nr
];
303 file_offset
= le32toh(file
->offset
);
304 file_data_len
= le32toh(file
->data_length
);
310 if (file_offset
+ file_data_len
> state
.length
) {
311 /* shouldn't happen, but just to be safe */
320 TODO: at the moment, callers require a pointer that can be 'free'd, but
321 for efficiency, it would be better to return the mapped area directly
323 *length
= file_data_len
;
324 *data
= malloc(file_data_len
);
328 memcpy(*data
, state
.data
+ file_offset
, file_data_len
);
330 TPM_DEBUG("SWTPM_NVRAM_LoadData_Linear: loaded %dB from %s:%d\n",
331 file_data_len
, name
, tpm_number
);
337 SWTPM_NVRAM_StoreData_Linear(unsigned char *filedata
,
338 uint32_t filedata_length
,
339 uint32_t tpm_number SWTPM_ATTR_UNUSED
,
344 TPM_BOOL needs_hdr_flush
= FALSE
;
345 TPM_BOOL needs_full_flush
= FALSE
;
347 uint32_t file_offset
;
348 struct nvram_linear_hdr_file
*file
;
350 TPM_DEBUG("SWTPM_NVRAM_StoreData_Linear: request for %dB to %s:%d\n",
351 filedata_length
, name
, tpm_number
);
353 file_nr
= SWTPM_NVRAM_Linear_GetFileNr(name
);
354 if (file_nr
== FILE_NR_INVALID
) {
358 file
= &state
.hdr
->files
[file_nr
];
362 rc
= SWTPM_NVRAM_Linear_AllocFile(uri
, file_nr
, filedata_length
);
366 needs_hdr_flush
= TRUE
;
367 } else if (filedata_length
> le32toh(file
->section_length
)) {
368 /* realloc, resize will be done by AllocFile */
369 rc
= SWTPM_NVRAM_Linear_RemoveFile(uri
, file_nr
, FALSE
);
373 rc
= SWTPM_NVRAM_Linear_AllocFile(uri
, file_nr
, filedata_length
);
377 needs_full_flush
= TRUE
;
380 /* resize might have changed pointer */
381 file
= &state
.hdr
->files
[file_nr
];
382 file_offset
= le32toh(file
->offset
);
384 if (filedata_length
!= le32toh(file
->data_length
)) {
385 file
->data_length
= htole32(filedata_length
);
386 needs_hdr_flush
= TRUE
;
389 memcpy(state
.data
+ file_offset
, filedata
, filedata_length
);
391 TPM_DEBUG("SWTPM_NVRAM_StoreData_Linear: stored %dB to %s:%d\n",
392 filedata_length
, name
, tpm_number
);
394 if (needs_full_flush
) {
395 if (state
.ops
->flush
) {
396 rc
= state
.ops
->flush(uri
, 0, state
.length
);
401 if (needs_hdr_flush
) {
402 rc
= SWTPM_NVRAM_Linear_FlushHeader(uri
);
405 if (rc
== 0 && state
.ops
->flush
) {
406 rc
= state
.ops
->flush(uri
, file_offset
, filedata_length
);
413 SWTPM_NVRAM_DeleteName_Linear(uint32_t tpm_number SWTPM_ATTR_UNUSED
,
415 TPM_BOOL mustExist SWTPM_ATTR_UNUSED
,
421 file_nr
= SWTPM_NVRAM_Linear_GetFileNr(name
);
422 if (file_nr
== FILE_NR_INVALID
) {
427 rc
= SWTPM_NVRAM_Linear_RemoveFile(uri
, file_nr
, TRUE
);
430 if (rc
== 0 && state
.ops
->flush
) {
431 /* full flush, RemoveFile can move around data */
432 rc
= state
.ops
->flush(uri
, 0, state
.length
);
438 static void SWTPM_NVRAM_Cleanup_Linear(void) {
439 if (state
.ops
&& state
.ops
->cleanup
) {
440 state
.ops
->cleanup();
442 if (state
.loaded_uri
) {
443 free(state
.loaded_uri
);
448 SWTPM_NVRAM_CheckState_Linear(const char *uri SWTPM_ATTR_UNUSED
,
454 struct nvram_linear_hdr_file
*file
;
456 file_nr
= SWTPM_NVRAM_Linear_GetFileNr(name
);
457 if (file_nr
== FILE_NR_INVALID
) {
462 file
= &state
.hdr
->files
[file_nr
];
463 if (file
->offset
== 0) {
466 *blobsize
= le32toh(file
->data_length
);
473 struct nvram_backend_ops nvram_linear_ops
= {
474 .prepare
= SWTPM_NVRAM_Prepare_Linear
,
475 .load
= SWTPM_NVRAM_LoadData_Linear
,
476 .store
= SWTPM_NVRAM_StoreData_Linear
,
477 .delete = SWTPM_NVRAM_DeleteName_Linear
,
478 .cleanup
= SWTPM_NVRAM_Cleanup_Linear
,
479 .check_state
= SWTPM_NVRAM_CheckState_Linear
,