1 /********************************************************************************/
3 /* NVRAM File Abstraction Layer */
4 /* Written by Ken Goldman */
5 /* Adapted to SWTPM by Stefan Berger */
6 /* IBM Thomas J. Watson Research Center */
8 /* (c) Copyright IBM Corporation 2006, 2010, 2014, 2015. */
10 /* All rights reserved. */
12 /* Redistribution and use in source and binary forms, with or without */
13 /* modification, are permitted provided that the following conditions are */
16 /* Redistributions of source code must retain the above copyright notice, */
17 /* this list of conditions and the following disclaimer. */
19 /* Redistributions in binary form must reproduce the above copyright */
20 /* notice, this list of conditions and the following disclaimer in the */
21 /* documentation and/or other materials provided with the distribution. */
23 /* Neither the names of the IBM Corporation nor the names of its */
24 /* contributors may be used to endorse or promote products derived from */
25 /* this software without specific prior written permission. */
27 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
28 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
29 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
30 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
31 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
32 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
33 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
34 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
35 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
36 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
37 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
38 /********************************************************************************/
50 #include <libtpms/tpm_error.h>
53 #include "swtpm_debug.h"
54 #include "swtpm_nvstore.h"
55 #include "swtpm_nvstore_dir.h"
61 struct nvram_backend_ops nvram_dir_ops
= {
62 .prepare
= SWTPM_NVRAM_Prepare_Dir
,
63 .load
= SWTPM_NVRAM_LoadData_Dir
,
64 .store
= SWTPM_NVRAM_StoreData_Dir
,
65 .delete = SWTPM_NVRAM_DeleteName_Dir
,
68 /* SWTPM_NVRAM_GetFilenameForName() constructs a rooted file name from the name.
70 The filename is of the form:
72 tpm_state_path/tpm_number.name
74 A temporary filename used to write to may be created. It should be rename()'d to
75 the non-temporary filename.
79 SWTPM_NVRAM_GetFilenameForName(char *filename
, /* output: rooted filename */
82 const char *name
, /* input: abstract name */
83 bool is_tempfile
, /* input: is temporary file? */
84 const char *tpm_state_path
)
86 TPM_RESULT res
= TPM_SUCCESS
;
88 const char *suffix
= "";
90 TPM_DEBUG(" SWTPM_NVRAM_GetFilenameForName: For name %s\n", name
);
92 switch (tpmstate_get_version()) {
93 case TPMLIB_TPM_VERSION_1_2
:
95 case TPMLIB_TPM_VERSION_2
:
101 n
= snprintf(filename
, bufsize
, "%s/TMP%s-%02lx.%s",
102 tpm_state_path
, suffix
, (unsigned long)tpm_number
, name
);
104 n
= snprintf(filename
, bufsize
, "%s/tpm%s-%02lx.%s",
105 tpm_state_path
, suffix
, (unsigned long)tpm_number
, name
);
107 if ((size_t)n
> bufsize
) {
111 TPM_DEBUG(" SWTPM_NVRAM_GetFilenameForName: File name %s\n", filename
);
117 SWTPM_NVRAM_Uri_to_Dir(const char *uri
)
119 return uri
+ strlen("dir://");
123 SWTPM_NVRAM_Validate_Dir(const char *tpm_state_path
)
128 /* TPM_NV_DISK TPM emulation stores in local directory determined by environment variable. */
130 if (tpm_state_path
== NULL
) {
131 logprintf(STDERR_FILENO
,
132 "SWTPM_NVRAM_Validate_Dir: Error (fatal), TPM_PATH environment "
133 "variable not set\n");
138 /* check that the directory name plus a file name will not overflow FILENAME_MAX */
140 length
= strlen(tpm_state_path
);
141 if ((length
+ TPM_FILENAME_MAX
) > FILENAME_MAX
) {
142 logprintf(STDERR_FILENO
,
143 "SWTPM_NVRAM_Validate_Dir: Error (fatal), TPM state path name "
144 "%s too large\n", tpm_state_path
);
149 TPM_DEBUG("SWTPM_NVRAM_Validate_Dir: Rooted state path %s\n", tpm_state_path
);
156 SWTPM_NVRAM_Lock_Dir(const char *tpm_state_path
)
160 char *lockfile
= NULL
;
161 struct flock flock
= {
163 .l_whence
= SEEK_SET
,
168 if (asprintf(&lockfile
, "%s/.lock", tpm_state_path
) < 0) {
169 logprintf(STDERR_FILENO
,
170 "SWTPM_NVRAM_Lock_Dir: Could not asprintf lock filename\n");
174 fd
= open(lockfile
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_NOFOLLOW
, 0660);
176 logprintf(STDERR_FILENO
,
177 "SWTPM_NVRAM_Lock_Dir: Could not open lockfile: %s\n",
183 if (fcntl(fd
, F_SETLK
, &flock
) < 0) {
184 logprintf(STDERR_FILENO
,
185 "SWTPM_NVRAM_Lock_Dir: Could not lock access to lockfile: %s\n",
197 SWTPM_NVRAM_Prepare_Dir(const char *uri
)
200 const char *tpm_state_path
= NULL
;
202 tpm_state_path
= SWTPM_NVRAM_Uri_to_Dir(uri
);
204 rc
= SWTPM_NVRAM_Validate_Dir(tpm_state_path
);
206 rc
= SWTPM_NVRAM_Lock_Dir(tpm_state_path
);
212 SWTPM_NVRAM_LoadData_Dir(unsigned char **data
,
222 char filename
[FILENAME_MAX
]; /* rooted file name from name */
224 const char *tpm_state_path
= NULL
;
226 tpm_state_path
= SWTPM_NVRAM_Uri_to_Dir(uri
);
230 /* map name to the rooted filename */
231 rc
= SWTPM_NVRAM_GetFilenameForName(filename
, sizeof(filename
),
232 tpm_number
, name
, false,
237 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Opening file %s\n", filename
);
238 fd
= open(filename
, O_RDONLY
); /* closed @1 */
239 if (fd
< 0) { /* if failure, determine cause */
240 if (errno
== ENOENT
) {
241 TPM_DEBUG("SWTPM_NVRAM_LoadData: No such file %s\n",
243 rc
= TPM_RETRY
; /* first time start up */
246 logprintf(STDERR_FILENO
,
247 "SWTPM_NVRAM_LoadData: Error (fatal) opening "
248 "%s for read, %s\n", filename
, strerror(errno
));
255 if (fchmod(fd
, tpmstate_get_mode()) < 0) {
256 logprintf(STDERR_FILENO
,
257 "SWTPM_NVRAM_LoadData: Could not fchmod %s : %s\n",
258 filename
, strerror(errno
));
263 /* determine the file length */
265 irc
= fstat(fd
, &statbuf
);
267 logprintf(STDERR_FILENO
,
268 "SWTPM_NVRAM_LoadData: Error (fatal) fstat'ing %s, %s\n",
269 filename
, strerror(errno
));
274 *length
= statbuf
.st_size
; /* save the length */
276 /* allocate a buffer for the actual data */
277 if ((rc
== 0) && *length
!= 0) {
278 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Reading %u bytes of data\n", *length
);
279 *data
= malloc(*length
);
281 logprintf(STDERR_FILENO
,
282 "SWTPM_NVRAM_LoadData: Error (fatal) allocating %u "
287 /* read the contents of the file into the data buffer */
288 if ((rc
== 0) && *length
!= 0) {
289 src
= read(fd
, *data
, *length
);
290 if (src
!= *length
) {
291 logprintf(STDERR_FILENO
,
292 "SWTPM_NVRAM_LoadData: Error (fatal), data read of %u "
293 "only read %lu\n", *length
, (unsigned long)src
);
299 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Closing file %s\n", filename
);
300 irc
= close(fd
); /* @1 */
302 logprintf(STDERR_FILENO
,
303 "SWTPM_NVRAM_LoadData: Error (fatal) closing file %s\n",
308 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Closed file %s\n", filename
);
316 SWTPM_NVRAM_StoreData_Dir(unsigned char *filedata
,
317 uint32_t filedata_length
,
327 char tmpfile
[FILENAME_MAX
]; /* rooted temporary file */
328 char filename
[FILENAME_MAX
]; /* rooted file name from name */
329 const char *tpm_state_path
= NULL
;
331 tpm_state_path
= SWTPM_NVRAM_Uri_to_Dir(uri
);
334 /* map name to the rooted filename */
335 rc
= SWTPM_NVRAM_GetFilenameForName(filename
, sizeof(filename
),
336 tpm_number
, name
, false,
341 /* map name to the rooted temporary file */
342 rc
= SWTPM_NVRAM_GetFilenameForName(tmpfile
, sizeof(tmpfile
),
343 tpm_number
, name
, true,
349 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Opening file %s\n", tmpfile
);
350 fd
= open(tmpfile
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_NOFOLLOW
,
351 tpmstate_get_mode()); /* closed @1 */
353 logprintf(STDERR_FILENO
,
354 "SWTPM_NVRAM_StoreData: Error (fatal) opening %s for "
355 "write failed, %s\n", tmpfile
, strerror(errno
));
360 /* write the data to the file */
362 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Writing %u bytes of data\n",
364 lrc
= write_full(fd
, filedata
, filedata_length
);
365 if (lrc
!= filedata_length
) {
366 logprintf(STDERR_FILENO
,
367 "SWTPM_NVRAM_StoreData: Error (fatal), data write "
368 "of %u only wrote %u\n", filedata_length
, lrc
);
372 if (rc
== 0 && fd
>= 0) {
373 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Syncing file %s\n", tmpfile
);
376 logprintf(STDERR_FILENO
,
377 "SWTPM_NVRAM_StoreData: Error (fatal) syncing file, %s\n",
381 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Synced file %s\n", tmpfile
);
385 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closing file %s\n", tmpfile
);
386 irc
= close(fd
); /* @1 */
388 logprintf(STDERR_FILENO
,
389 "SWTPM_NVRAM_StoreData: Error (fatal) closing file\n");
393 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closed file %s\n", tmpfile
);
397 if (rc
== 0 && fd
>= 0) {
398 irc
= rename(tmpfile
, filename
);
400 logprintf(STDERR_FILENO
,
401 "SWTPM_NVRAM_StoreData: Error (fatal) renaming file: %s\n",
405 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Renamed file to %s\n", filename
);
410 * Quote from linux man 2 fsync:
411 * Calling fsync() does not necessarily ensure that the entry in the
412 * directory containing the file has also reached disk. For that an
413 * explicit fsync() on a file descriptor for the directory is also needed.
415 if (rc
== 0 && fd
>= 0) {
416 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Opening dir %s\n", tpm_state_path
);
417 dir_fd
= open(tpm_state_path
, O_RDONLY
);
419 logprintf(STDERR_FILENO
,
420 "SWTPM_NVRAM_StoreData: Error (fatal) opening %s for "
421 "fsync failed, %s\n", tpm_state_path
, strerror(errno
));
425 if (rc
== 0 && dir_fd
>= 0) {
426 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Syncing dir %s\n", tpm_state_path
);
429 logprintf(STDERR_FILENO
,
430 "SWTPM_NVRAM_StoreData: Error (fatal) syncing dir, %s\n",
434 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Synced dir %s\n", tpm_state_path
);
438 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closing dir %s\n", tpm_state_path
);
441 logprintf(STDERR_FILENO
,
442 "SWTPM_NVRAM_StoreData: Error (fatal) closing dir\n");
445 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closed dir %s\n", tpm_state_path
);
449 if (rc
!= 0 && fd
>= 0) {
456 TPM_RESULT
SWTPM_NVRAM_DeleteName_Dir(uint32_t tpm_number
,
463 char filename
[FILENAME_MAX
]; /* rooted file name from name */
464 const char *tpm_state_path
= NULL
;
466 tpm_state_path
= SWTPM_NVRAM_Uri_to_Dir(uri
);
468 TPM_DEBUG(" SWTPM_NVRAM_DeleteName: Name %s\n", name
);
469 /* map name to the rooted filename */
470 rc
= SWTPM_NVRAM_GetFilenameForName(filename
, sizeof(filename
),
471 tpm_number
, name
, false,
474 irc
= remove(filename
);
475 if ((irc
!= 0) && /* if the remove failed */
476 (mustExist
|| /* if any error is a failure, or */
477 (errno
!= ENOENT
))) { /* if error other than no such file */
478 logprintf(STDERR_FILENO
,
479 "SWTPM_NVRAM_DeleteName: Error, (fatal) file "
480 "remove failed, errno %d\n", errno
);