1 /********************************************************************************/
4 /* Written by Ken Goldman, Stefan Berger */
5 /* IBM Thomas J. Watson Research Center */
7 /* (c) Copyright IBM Corporation 2006, 2010, 2016, 2019. */
9 /* All rights reserved. */
11 /* Redistribution and use in source and binary forms, with or without */
12 /* modification, are permitted provided that the following conditions are */
15 /* Redistributions of source code must retain the above copyright notice, */
16 /* this list of conditions and the following disclaimer. */
18 /* Redistributions in binary form must reproduce the above copyright */
19 /* notice, this list of conditions and the following disclaimer in the */
20 /* documentation and/or other materials provided with the distribution. */
22 /* Neither the names of the IBM Corporation nor the names of its */
23 /* contributors may be used to endorse or promote products derived from */
24 /* this software without specific prior written permission. */
26 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
27 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
28 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
29 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
30 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
31 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
32 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
33 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
34 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
35 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
36 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
37 /********************************************************************************/
50 #include <sys/types.h>
51 #include <sys/socket.h>
53 #include <libtpms/tpm_error.h>
54 #include <libtpms/tpm_library.h>
55 #include <libtpms/tpm_memory.h>
58 #include "swtpm_debug.h"
60 #include "swtpm_nvstore.h"
68 #include "ctrlchannel.h"
70 #include "sys_dependencies.h"
71 #include "daemonize.h"
72 #include "seccomp_profile.h"
74 #include "capabilities.h"
77 static int notify_fd
[2] = {-1, -1};
79 static struct libtpms_callbacks callbacks
= {
80 .sizeOfStruct
= sizeof(struct libtpms_callbacks
),
81 .tpm_nvram_init
= SWTPM_NVRAM_Init
,
82 .tpm_nvram_loaddata
= SWTPM_NVRAM_LoadData
,
83 .tpm_nvram_storedata
= SWTPM_NVRAM_StoreData
,
84 .tpm_nvram_deletename
= SWTPM_NVRAM_DeleteName
,
85 .tpm_io_init
= SWTPM_IO_Init
,
86 .tpm_io_getlocality
= mainloop_cb_get_locality
,
89 static void sigterm_handler(int sig
__attribute__((unused
)))
91 TPM_DEBUG("Terminating...\n");
92 if (write(notify_fd
[1], "T", 1) < 0) {
93 logprintf(STDERR_FILENO
, "Error: sigterm notification failed: %s\n",
96 mainloop_terminate
= true;
99 static void usage(FILE *file
, const char *prgname
, const char *iface
)
102 "Usage: %s %s [options]\n"
104 "The following options are supported:\n"
106 "-p|--port <port> : use the given port\n"
107 "-f|--fd <fd> : use the given socket file descriptor\n"
108 "-t|--terminate : terminate the TPM once a connection has been lost\n"
109 "-d|--daemon : daemonize the TPM\n"
110 "--ctrl type=[unixio|tcp][,path=<path>][,port=<port>[,bindaddr=address[,ifname=ifname]]][,fd=<filedescriptor>|clientfd=<filedescriptor>][,mode=0...][,uid=uid][,gid=gid]\n"
111 " : TPM control channel using either UnixIO or TCP sockets;\n"
112 " the path is only valid for Unixio channels; the port must\n"
113 " be given in case the type is TCP; the TCP socket is bound\n"
114 " to 127.0.0.1 by default and other bind addresses can be\n"
115 " given with the bindaddr parameter; if fd is provided,\n"
116 " it will be treated as a server socket and used for \n"
117 " accepting client connections; if clientfd is provided,\n"
118 " it will be treaded as client connection;\n"
119 " NOTE: fd and clientfd are mutually exclusive and clientfd\n"
120 " is only valid for UnixIO channels\n"
121 " mode allows a user to set the file mode bits of a Unixio socket;\n"
122 " the value must be given in octal number format\n"
123 " uid and gid set the ownership of the Unixio socket's file;\n"
124 "--migration-key file=<path>|fd=<fd>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
125 " : use an AES key for the encryption of the TPM's state\n"
126 " when it is retrieved from the TPM via ioctls;\n"
127 " Setting this key ensures that the TPM's state will always\n"
128 " be encrypted when migrated\n"
129 "--migration-key pwdfile=<path>|pwdfd=<fd>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]][,kdf=sha512|pbkdf2]\n"
130 " : provide a passphrase in a file; the AES key will be\n"
131 " derived from this passphrase; default kdf is PBKDF2\n"
132 "--log file=<path>|fd=<filedescriptor>[,level=n][,prefix=<prefix>][,truncate]\n"
133 " : write the TPM's log into the given file rather than\n"
134 " to the console; provide '-' for path to avoid logging\n"
135 " log level 5 and higher will enable libtpms logging;\n"
136 " all logged output will be prefixed with prefix;\n"
137 " the log file can be reset (truncate)\n"
138 "--key file=<path>|fd=<fd>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
139 " : use an AES key for the encryption of the TPM's state\n"
140 " files; use the given mode for the block encryption;\n"
141 " the key is to be provided as a hex string or in binary\n"
142 " format; the keyfile can be automatically removed using\n"
143 " the remove parameter\n"
144 "--key pwdfile=<path>|pwdfd=<fd>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]][,kdf=sha512|pbkdf2]\n"
145 " : provide a passphrase in a file; the AES key will be\n"
146 " derived from this passphrase; default kdf is PBKDF2\n"
147 "--locality [reject-locality-4][,allow-set-locality]\n"
148 " : reject-locality-4: reject any command in locality 4\n"
149 " allow-set-locality: accept SetLocality command\n"
150 "--pid file=<path>|fd=<filedescriptor>\n"
151 " : write the process ID into the given file\n"
152 "--tpmstate dir=<dir>[,mode=0...]|backend-uri=<uri>\n"
153 " : set the directory or uri where the TPM's state will be written\n"
154 " into; the TPM_PATH environment variable can be used\n"
155 " instead dir option;\n"
156 " mode allows a user to set the file mode bits of the state files;\n"
157 " the default mode is 0640;\n"
158 "--server [type=tcp][,port=port[,bindaddr=address[,ifname=ifname]]][,fd=fd][,disconnect]\n"
159 " : Expect TCP connections on the given port;\n"
160 " if fd is provided, packets will be read from it directly;\n"
161 " the disconnect parameter closes the connection after\n"
162 " sending a response back to the client; the TCP socket is\n"
163 " bound to 127.0.0.1 by default and other bind addresses\n"
164 " can be given with the bindaddr parameter\n"
165 "--server type=unixio[,path=path][,fd=fd][,mode=0...][,uid=uid][,gid=gid]\n"
166 " : Expect UnixIO connections on the given path; if fd is\n"
167 " provided, packets will be read from it directly;\n"
168 " mode allows a user to set the file mode bits of the socket; the\n"
169 " value must be given in octal number format;\n"
170 " uid and gid set the ownership of the Unixio socket's file;\n"
171 "--flags [not-need-init][,startup-clear|startup-state|startup-deactivated|startup-none][,disable-auto-shutdown]\n"
172 " : not-need-init: commands can be sent without needing to\n"
173 " send an INIT via control channel;\n"
174 " startup-...: send Startup command with this type;\n"
175 " disable-auto-shutdown disables automatic sending of\n"
176 " TPM2_Shutdown before TPM 2 reset or swtpm termination;\n"
177 "-r|--runas <user>: change to the given user\n"
178 "-R|--chroot <path>\n"
179 " : chroot to the given directory at startup\n"
180 "--tpm2 : choose TPM2 functionality\n"
182 # ifndef SCMP_ACT_LOG
183 "--seccomp action=none|kill\n"
185 "--seccomp action=none|kill|log\n"
187 " : Choose the action of the seccomp profile when a\n"
188 " blacklisted syscall is executed; default is kill\n"
190 "--print-capabilites\n"
191 " : print capabilities and terminate\n"
193 " : print existing TPM states and terminate\n"
194 "-h|--help : display this help screen and terminate\n"
199 static void swtpm_cleanup(struct ctrlchannel
*cc
, struct server
*server
)
202 ctrlchannel_free(cc
);
205 tpmstate_global_free();
206 SWTPM_NVRAM_Shutdown();
209 int swtpm_main(int argc
, char **argv
, const char *prgname
, const char *iface
)
212 int daemonize
= FALSE
;
213 int opt
, longindex
, ret
;
215 struct mainLoopParams mlp
= {
220 .tpmversion
= TPMLIB_TPM_VERSION_1_2
,
221 .startupType
= _TPM_ST_NONE
,
222 .lastCommand
= TPM_ORDINAL_NONE
,
223 .disable_auto_shutdown
= false,
225 struct server
*server
= NULL
;
229 char *keydata
= NULL
;
230 char *migkeydata
= NULL
;
231 char *logdata
= NULL
;
232 char *piddata
= NULL
;
233 char *localitydata
= NULL
;
234 char *tpmstatedata
= NULL
;
235 char *ctrlchdata
= NULL
;
236 char *serverdata
= NULL
;
237 char *flagsdata
= NULL
;
238 char *seccompdata
= NULL
;
241 bool need_init_cmd
= true;
245 unsigned int seccomp_action
;
246 bool printcapabilities
= false;
247 bool printstates
= false;
248 static struct option longopts
[] = {
249 {"daemon" , no_argument
, 0, 'd'},
250 {"help" , no_argument
, 0, 'h'},
251 {"port" , required_argument
, 0, 'p'},
252 {"fd" , required_argument
, 0, 'f'},
253 {"server" , required_argument
, 0, 'c'},
254 {"runas" , required_argument
, 0, 'r'},
255 {"chroot" , required_argument
, 0, 'R'},
256 {"terminate" , no_argument
, 0, 't'},
257 {"locality" , required_argument
, 0, 'L'},
258 {"log" , required_argument
, 0, 'l'},
259 {"key" , required_argument
, 0, 'k'},
260 {"migration-key", required_argument
, 0, 'K'},
261 {"pid" , required_argument
, 0, 'P'},
262 {"tpmstate" , required_argument
, 0, 's'},
263 {"ctrl" , required_argument
, 0, 'C'},
264 {"flags" , required_argument
, 0, 'F'},
265 {"tpm2" , no_argument
, 0, '2'},
267 {"seccomp" , required_argument
, 0, 'S'},
269 {"print-capabilities"
270 , no_argument
, 0, 'a'},
271 {"print-states", no_argument
, 0, 'e'},
275 log_set_prefix("swtpm: ");
278 opt
= getopt_long(argc
, argv
, "dhp:f:tr:R:", longopts
, &longindex
);
286 if (daemonize_prep() == -1) {
287 logprintf(STDERR_FILENO
,
288 "Could not prepare to daemonize: %s\n", strerror(errno
));
295 val
= strtoul(optarg
, &end_ptr
, 0);
296 if (val
!= (unsigned int)val
|| errno
|| end_ptr
[0] != '\0') {
297 logprintf(STDERR_FILENO
,
298 "Cannot parse socket port number '%s'.\n",
302 if (val
>= 0x10000) {
303 logprintf(STDERR_FILENO
, "Port is outside valid range.\n");
306 snprintf(buf
, sizeof(buf
), "%lu", val
);
307 if (setenv("TPM_PORT", buf
, 1) != 0) {
308 logprintf(STDERR_FILENO
,
309 "Could not set port: %s\n", strerror(errno
));
312 serverdata
= "type=tcp,disconnect";
317 val
= strtoul(optarg
, &end_ptr
, 10);
318 if (val
!= (unsigned int)val
|| errno
|| end_ptr
[0] != '\0') {
319 logprintf(STDERR_FILENO
,
320 "Cannot parse socket file descriptor.\n");
324 if (fstat(mlp
.fd
, &statbuf
) != 0) {
325 logprintf(STDERR_FILENO
, "Cannot stat file descriptor: %s\n",
330 * test for wrong file types; anonymous fd's do not seem to be any of the wrong
331 * ones but are also not character devices
333 if (S_ISREG(statbuf
.st_mode
) || S_ISDIR(statbuf
.st_mode
) ||
334 S_ISBLK(statbuf
.st_mode
) || S_ISLNK(statbuf
.st_mode
)) {
335 logprintf(STDERR_FILENO
,
336 "Given file descriptor type is not supported.\n");
339 mlp
.flags
|= MAIN_LOOP_FLAG_TERMINATE
| MAIN_LOOP_FLAG_USE_FD
|
340 MAIN_LOOP_FLAG_KEEP_CONNECTION
;
342 SWTPM_IO_SetSocketFD(mlp
.fd
);
351 mlp
.flags
|= MAIN_LOOP_FLAG_TERMINATE
;
371 tpmstatedata
= optarg
;
379 localitydata
= optarg
;
387 mlp
.tpmversion
= TPMLIB_TPM_VERSION_2
;
391 usage(stdout
, prgname
, iface
);
395 printcapabilities
= true;
411 seccompdata
= optarg
;
415 usage(stderr
, prgname
, iface
);
421 logprintf(STDERR_FILENO
,
422 "Unknown parameter '%s'\n", argv
[optind
]);
427 if (do_chroot(chroot
) < 0)
431 /* change process ownership before accessing files */
433 if (change_process_owner(runas
) < 0)
437 if (handle_log_options(logdata
) < 0)
440 if (mlp
.fd
>= 0 && mlp
.fd
< 3) {
441 /* no std{in,out,err} */
442 logprintf(STDERR_FILENO
,
443 "Error: Cannot accept file descriptors with values 0, 1, or 2\n");
447 if (printcapabilities
) {
449 * Choose the TPM version so that getting/setting buffer size works.
450 * Ignore failure, for backward compatibility when TPM 1.2 is disabled.
452 ret
= capabilities_print_json(false, mlp
.tpmversion
);
453 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
456 if (tpmlib_choose_tpm_version(mlp
.tpmversion
) != TPM_SUCCESS
)
459 if (handle_ctrlchannel_options(ctrlchdata
, &mlp
.cc
) < 0 ||
460 handle_server_options(serverdata
, &server
) < 0) {
464 tpmstate_set_version(mlp
.tpmversion
);
467 if (handle_tpmstate_options(tpmstatedata
) < 0)
469 if (tpmstatedata
== NULL
) {
470 logprintf(STDERR_FILENO
,
471 "Error: --tpmstate option is required for --print-states\n");
474 ret
= SWTPM_NVRAM_PrintJson();
481 if (handle_key_options(keydata
) < 0 ||
482 handle_migration_key_options(migkeydata
) < 0 ||
483 handle_pid_options(piddata
) < 0 ||
484 handle_locality_options(localitydata
, &mlp
.locality_flags
) < 0 ||
485 handle_tpmstate_options(tpmstatedata
) < 0 ||
486 handle_seccomp_options(seccompdata
, &seccomp_action
) < 0 ||
487 handle_flags_options(flagsdata
, &need_init_cmd
,
488 &mlp
.startupType
, &mlp
.disable_auto_shutdown
) < 0) {
493 if (server_get_fd(server
) >= 0) {
494 mlp
.fd
= server_set_fd(server
, -1);
495 SWTPM_IO_SetSocketFD(mlp
.fd
);
498 mlp
.flags
|= MAIN_LOOP_FLAG_KEEP_CONNECTION
;
499 if ((server_get_flags(server
) & SERVER_FLAG_DISCONNECT
))
500 mlp
.flags
&= ~MAIN_LOOP_FLAG_KEEP_CONNECTION
;
502 if ((server_get_flags(server
) & SERVER_FLAG_FD_GIVEN
))
503 mlp
.flags
|= MAIN_LOOP_FLAG_TERMINATE
| MAIN_LOOP_FLAG_USE_FD
;
506 if (pidfile_write(getpid()) < 0) {
510 setvbuf(stdout
, 0, _IONBF
, 0); /* output may be going through pipe */
514 start_time
= time(NULL
);
517 TPM_DEBUG("main: Initializing TPM at %s", ctime(&start_time
));
519 tpmlib_debug_libtpms_parameters(mlp
.tpmversion
);
521 if ((rc
= tpmlib_register_callbacks(&callbacks
)))
524 if (!need_init_cmd
) {
525 if ((rc
= tpmlib_start(0, mlp
.tpmversion
)))
530 if (install_sighandlers(notify_fd
, sigterm_handler
) < 0)
531 goto error_no_sighandlers
;
533 if (create_seccomp_profile(false, seccomp_action
) < 0)
534 goto error_seccomp_profile
;
540 rc
= mainLoop(&mlp
, notify_fd
[0]);
542 error_seccomp_profile
:
543 uninstall_sighandlers();
545 error_no_sighandlers
:
554 swtpm_cleanup(mlp
.cc
, server
);
556 /* Fatal initialization errors cause the program to abort */
561 TPM_DEBUG("main: TPM initialization failure %08x, exiting\n", rc
);
566 swtpm_cleanup(mlp
.cc
, server
);
571 swtpm_cleanup(mlp
.cc
, server
);