]> git.proxmox.com Git - swtpm.git/blobdiff - src/swtpm/cuse_tpm.c
swtpm: Rename disable_fips_mode() and move into tpmlib_start()
[swtpm.git] / src / swtpm / cuse_tpm.c
index 62274323dac59cba59ea9b8da0135381670056d5..e73b413cca8016cef5e70e2ec28701efcfa32059 100644 (file)
 #include "locality.h"
 #include "logging.h"
 #include "tpm_ioctl.h"
-#include "swtpm_nvfile.h"
+#include "swtpm_nvstore.h"
 #include "tpmlib.h"
 #include "main.h"
 #include "utils.h"
 #include "threadpool.h"
+#include "seccomp_profile.h"
+#include "options.h"
+#include "capabilities.h"
+#include "swtpm_utils.h"
 
 /* maximum size of request buffer */
 #define TPM_REQ_MAX 4096
@@ -88,6 +92,9 @@ static unsigned char *ptm_request;
 /* buffer containing the TPM response */
 static unsigned char *ptm_response;
 
+/* offset from where to read from; reset when ptm_response is set */
+static size_t ptm_read_offset;
+
 /* the sizes of the data in the buffers */
 static uint32_t ptm_req_len, ptm_res_len, ptm_res_tot;
 
@@ -106,12 +113,12 @@ static struct fuse_session *ptm_fuse_session;
 #if GLIB_MAJOR_VERSION >= 2
 # if GLIB_MINOR_VERSION >= 32
 
-GMutex file_ops_lock;
+static GMutex file_ops_lock;
 #  define FILE_OPS_LOCK &file_ops_lock
 
 # else
 
-GMutex *file_ops_lock;
+static GMutex *file_ops_lock;
 #  define FILE_OPS_LOCK file_ops_lock
 
 # endif
@@ -129,6 +136,10 @@ struct cuse_param {
     char *piddata;
     char *tpmstatedata;
     char *localitydata;
+    char *seccompdata;
+    unsigned int seccomp_action;
+    char *flagsdata;
+    uint16_t startupType;
 };
 
 /* single message to send to the worker thread */
@@ -150,6 +161,7 @@ typedef struct stateblob_desc {
 } stateblob_desc;
 
 typedef enum tx_state_type {
+    TX_STATE_CLOSED = 0,
     TX_STATE_RW_COMMAND = 1,
     TX_STATE_SET_STATE_BLOB = 2,
     TX_STATE_GET_STATE_BLOB = 3,
@@ -180,26 +192,26 @@ static const char *usage =
 "-n NAME|--name=NAME :  device name (mandatory)\n"
 "-M MAJ|--maj=MAJ    :  device major number\n"
 "-m MIN|--min=MIN    :  device minor number\n"
-"--key file=<path>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
+"--key file=<path>|fd=<fd>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
 "                    :  use an AES key for the encryption of the TPM's state\n"
 "                       files; use the given mode for the block encryption;\n"
 "                       the key is to be provided as a hex string or in binary\n"
 "                       format; the keyfile can be automatically removed using\n"
 "                       the remove parameter\n"
-"--key pwdfile=<path>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]]\n"
+"--key pwdfile=<path>|pwdfd=<fd>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]][,kdf=sha512|pbkdf2]\n"
 "                    :  provide a passphrase in a file; the AES key will be\n"
-"                       derived from this passphrase\n"
+"                       derived from this passphrase; default kdf is PBKDF2\n"
 "--locality [reject-locality-4][,allow-set-locality]\n"
 "                    :  reject-locality-4: reject any command in locality 4\n"
 "                       allow-set-locality: accept SetLocality command\n"
-"--migration-key file=<path>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
+"--migration-key file=<path>|fd=<fd>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
 "                    :  use an AES key for the encryption of the TPM's state\n"
 "                       when it is retrieved from the TPM via ioctls;\n"
 "                       Setting this key ensures that the TPM's state will always\n"
 "                       be encrypted when migrated\n"
-"--migration-key pwdfile=<path>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]]\n"
+"--migration-key pwdfile=<path>|pwdfd=<fd>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]][,kdf=sha512|pbkdf2]\n"
 "                    :  provide a passphrase in a file; the AES key will be\n"
-"                       derived from this passphrase\n"
+"                       derived from this passphrase; default kdf is PBKDF2\n"
 "--log file=<path>|fd=<filedescriptor>[,level=n][,prefix=<prefix>][,truncate]\n"
 "                    :  write the TPM's log into the given file rather than\n"
 "                       to the console; provide '-' for path to avoid logging\n"
@@ -208,20 +220,36 @@ static const char *usage =
 "                       the log file can be reset (truncate)\n"
 "--pid file=<path>|fd=<filedescriptor>\n"
 "                    :  write the process ID into the given file\n"
-"--tpmstate dir=<dir>[,mode=0...]\n"
-"                    :  set the directory where the TPM's state will be written\n"
+"--tpmstate dir=<dir>[,mode=0...]|backend-uri=<uri>\n"
+"                    :  set the directory or uri where the TPM's state will be written\n"
 "                       into; the TPM_PATH environment variable can be used\n"
-"                       instead;\n"
-"                       mode allows to set the file mode bits of the state\n"
+"                       instead of dir option;\n"
+"                       mode allows a user to set the file mode bits of the state\n"
 "                       files; the default mode is 0640;\n"
+"--flags [not-need-init][,startup-clear|startup-state|startup-deactivated|startup-none]\n"
+"                    :  not-need-init: commands can be sent without needing to\n"
+"                       send an INIT via control channel;\n"
+"                       startup-...: send Startup command with this type;\n"
 "-r|--runas <user>   :  after creating the CUSE device, change to the given\n"
 "                       user\n"
 "--tpm2              :  choose TPM2 functionality\n"
+#ifdef WITH_SECCOMP
+# ifndef SCMP_ACT_LOG
+"--seccomp action=none|kill\n"
+# else
+"--seccomp action=none|kill|log\n"
+# endif
+"                    :  Choose the action of the seccomp profile when a\n"
+"                       blacklisted syscall is executed; default is kill\n"
+#endif
+"--print-capabilites : print capabilities and terminate\n"
+"--print-states      : print existing TPM states and terminate\n"
 "-h|--help           :  display this help screen and terminate\n"
 "\n";
 
 static TPM_RESULT
-ptm_io_getlocality(TPM_MODIFIER_INDICATOR *loc, uint32_t tpmnum)
+ptm_io_getlocality(TPM_MODIFIER_INDICATOR *loc,
+                   uint32_t tpmnum SWTPM_ATTR_UNUSED)
 {
     *loc = locality;
     return TPM_SUCCESS;
@@ -372,7 +400,7 @@ static int cached_stateblob_copy(void *dest, size_t destlen,
 /*
  * worker_thread: the worker thread
  */
-static void worker_thread(gpointer data, gpointer user_data)
+static void worker_thread(gpointer data, gpointer user_data SWTPM_ATTR_UNUSED)
 {
     struct thread_message *msg = (struct thread_message *)data;
 
@@ -380,6 +408,7 @@ static void worker_thread(gpointer data, gpointer user_data)
     case MESSAGE_TPM_CMD:
         TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
                        ptm_request, ptm_req_len);
+        ptm_read_offset = 0;
         break;
     case MESSAGE_IOCTL:
         break;
@@ -399,11 +428,17 @@ static void worker_thread(gpointer data, gpointer user_data)
  * libtpms and allocate a global TPM request buffer.
  *
  * @flags: libtpms init flags
+ * @l_tpmversion: the version of the TPM
+ * @res: the result from starting the TPM
  */
-static int tpm_start(uint32_t flags, TPMLIB_TPMVersion l_tpmversion)
+static int tpm_start(uint32_t flags, TPMLIB_TPMVersion l_tpmversion,
+                     TPM_RESULT *res)
 {
     DIR *dir;
-    const char *tpmdir = tpmstate_get_dir();
+    const char *uri = tpmstate_get_backend_uri();
+    const char *tpmdir = uri + strlen("dir://");
+
+    *res = TPM_FAIL;
 
     dir = opendir(tpmdir);
     if (dir) {
@@ -436,7 +471,8 @@ static int tpm_start(uint32_t flags, TPMLIB_TPMVersion l_tpmversion)
         goto error_del_pool;
     }
 
-    if (tpmlib_start(flags, l_tpmversion) != TPM_SUCCESS)
+    *res = tpmlib_start(flags, l_tpmversion);
+    if (*res != TPM_SUCCESS)
         goto error_del_pool;
 
     logprintf(STDOUT_FILENO,
@@ -462,6 +498,39 @@ static void ptm_write_fatal_error_response(TPMLIB_TPMVersion l_tpmversion)
                                       &ptm_res_len,
                                       &ptm_res_tot,
                                       l_tpmversion);
+    ptm_read_offset = 0;
+}
+
+/*
+ * ptm_send_startup: Send a TPM/TPM2_Startup
+ */
+static int ptm_send_startup(uint16_t startupType,
+                            TPMLIB_TPMVersion l_tpmversion SWTPM_ATTR_UNUSED)
+{
+    uint32_t command_length;
+    unsigned char command[sizeof(struct tpm_startup)];
+    uint32_t max_command_length = sizeof(command);
+    int ret = 0;
+    TPM_RESULT rc = TPM_SUCCESS;
+
+    command_length = tpmlib_create_startup_cmd(
+                               startupType,
+                               tpmversion,
+                               command, max_command_length);
+    if (command_length > 0) {
+        rc = TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
+                           (unsigned char *)command, command_length);
+        ptm_read_offset = 0;
+    }
+
+    if (rc || command_length == 0) {
+        if (rc) {
+            logprintf(STDERR_FILENO, "Could not send Startup: 0x%x\n", rc);
+            ret = -1;
+        }
+    }
+
+    return ret;
 }
 
 /************************************ read() support ***************************/
@@ -474,23 +543,27 @@ static void ptm_write_fatal_error_response(TPMLIB_TPMVersion l_tpmversion)
  */
 static void ptm_read_result(fuse_req_t req, size_t size)
 {
-    int len;
+    size_t len = 0;
+
+    /* prevent other threads from reading or writing cmds or doing ioctls */
+    g_mutex_lock(FILE_OPS_LOCK);
 
     if (tpm_running) {
         /* wait until results are ready */
         worker_thread_wait_done();
     }
 
-    len = ptm_res_len;
-
-    if (ptm_res_len > size) {
-        len = size;
-        ptm_res_len -= size;
-    } else {
-        ptm_res_len = 0;
+    if (ptm_read_offset < ptm_res_len) {
+        len = ptm_res_len - ptm_read_offset;
+        if (size < len)
+            len = size;
     }
 
-    fuse_reply_buf(req, (const char *)ptm_response, len);
+    fuse_reply_buf(req, (const char *)&ptm_response[ptm_read_offset], len);
+
+    ptm_read_offset += len;
+
+    g_mutex_unlock(FILE_OPS_LOCK);
 }
 
 /*
@@ -535,8 +608,8 @@ static void ptm_read_stateblob(fuse_req_t req, size_t size)
  * Depending on the current state of the transfer interface (read/write)
  * return either the results of TPM commands or a data of a TPM state blob.
  */
-static void ptm_read(fuse_req_t req, size_t size, off_t off,
-                     struct fuse_file_info *fi)
+static void ptm_read(fuse_req_t req, size_t size, off_t off SWTPM_ATTR_UNUSED,
+                     struct fuse_file_info *fi SWTPM_ATTR_UNUSED)
 {
     switch (tx_state.state) {
     case TX_STATE_RW_COMMAND:
@@ -549,6 +622,9 @@ static void ptm_read(fuse_req_t req, size_t size, off_t off,
     case TX_STATE_GET_STATE_BLOB:
         ptm_read_stateblob(req, size);
         break;
+    case TX_STATE_CLOSED:
+        /* not possible */
+        break;
     }
 }
 
@@ -798,7 +874,7 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
     ptm_req_len = size;
     ptm_res_len = 0;
 
-    /* prevent other threads from writing or doing ioctls */
+    /* prevent other threads from reading or writing cmds or doing ioctls */
     g_mutex_lock(FILE_OPS_LOCK);
 
     if (tpm_running) {
@@ -815,8 +891,10 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
         tpmlib_process(&ptm_response, &ptm_res_len, &ptm_res_tot,
                        (unsigned char *)buf, ptm_req_len,
                        locality_flags, &locality, tpmversion);
-        if (ptm_res_len)
+        if (ptm_res_len) {
+            ptm_read_offset = 0;
             goto skip_process;
+        }
 
         if (tpmlib_is_request_cancelable(l_tpmversion,
                                          (const unsigned char*)buf,
@@ -833,6 +911,7 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
             /* direct processing */
             TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
                            (unsigned char *)buf, ptm_req_len);
+            ptm_read_offset = 0;
         }
     } else {
         /* TPM not initialized; return error */
@@ -853,7 +932,8 @@ cleanup:
  *            on what is being transferred using the write()
  */
 static void ptm_write(fuse_req_t req, const char *buf, size_t size,
-                      off_t off, struct fuse_file_info *fi)
+                      off_t off SWTPM_ATTR_UNUSED,
+                      struct fuse_file_info *fi SWTPM_ATTR_UNUSED)
 {
     switch (tx_state.state) {
     case TX_STATE_RW_COMMAND:
@@ -866,6 +946,9 @@ static void ptm_write(fuse_req_t req, const char *buf, size_t size,
     case TX_STATE_SET_STATE_BLOB:
         ptm_write_stateblob(req, buf, size);
         break;
+    case TX_STATE_CLOSED:
+        /* not possible */
+        break;
     }
 }
 
@@ -874,11 +957,26 @@ static void ptm_write(fuse_req_t req, const char *buf, size_t size,
  */
 static void ptm_open(fuse_req_t req, struct fuse_file_info *fi)
 {
+    if (tx_state.state != TX_STATE_CLOSED) {
+        fuse_reply_err(req, EBUSY);
+        return;
+    }
+
     tx_state.state = TX_STATE_RW_COMMAND;
 
     fuse_reply_open(req, fi);
 }
 
+/*
+ * ptm_release:
+ */
+static void ptm_release(fuse_req_t req, struct fuse_file_info *fi)
+{
+    tx_state.state = TX_STATE_CLOSED;
+
+    fuse_reply_err(req, 0);
+}
+
 /*
  * ptm_ioctl : ioctl execution
  *
@@ -894,7 +992,8 @@ static void ptm_open(fuse_req_t req, struct fuse_file_info *fi)
  *            needed buffer
  */
 static void ptm_ioctl(fuse_req_t req, int cmd, void *arg,
-                      struct fuse_file_info *fi, unsigned flags,
+                      struct fuse_file_info *fi SWTPM_ATTR_UNUSED,
+                      unsigned flags SWTPM_ATTR_UNUSED,
                       const void *in_buf, size_t in_bufsz, size_t out_bufsz)
 {
     TPM_RESULT res = TPM_FAIL;
@@ -949,7 +1048,8 @@ static void ptm_ioctl(fuse_req_t req, int cmd, void *arg,
                     | PTM_CAP_SET_STATEBLOB
                     | PTM_CAP_STOP
                     | PTM_CAP_GET_CONFIG
-                    | PTM_CAP_SET_BUFFERSIZE;
+                    | PTM_CAP_SET_BUFFERSIZE
+                    | PTM_CAP_GET_INFO;
                 break;
             case TPMLIB_TPM_VERSION_1_2:
                 ptm_caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN
@@ -963,7 +1063,8 @@ static void ptm_ioctl(fuse_req_t req, int cmd, void *arg,
                     | PTM_CAP_SET_STATEBLOB
                     | PTM_CAP_STOP
                     | PTM_CAP_GET_CONFIG
-                    | PTM_CAP_SET_BUFFERSIZE;
+                    | PTM_CAP_SET_BUFFERSIZE
+                    | PTM_CAP_GET_INFO;
                 break;
             }
             fuse_reply_ioctl(req, 0, &ptm_caps, sizeof(ptm_caps));
@@ -982,12 +1083,10 @@ static void ptm_ioctl(fuse_req_t req, int cmd, void *arg,
             TPMLIB_Terminate();
 
             tpm_running = false;
-            if (tpm_start(init_p->u.req.init_flags, tpmversion) < 0) {
-                res = TPM_FAIL;
+            if (tpm_start(init_p->u.req.init_flags, tpmversion, &res) < 0) {
                 logprintf(STDERR_FILENO,
                           "Error: Could not initialize the TPM.\n");
             } else {
-                res = TPM_SUCCESS;
                 tpm_running = true;
             }
             init_p->u.resp.tpm_result = res;
@@ -1285,17 +1384,27 @@ static void ptm_init_done(void *userdata)
 
     /* at this point the entry in /dev/ is available */
     if (pidfile_write(getpid()) < 0) {
-        ptm_cleanup();
-        exit(-13);
+        ret = -13;
+        goto error_exit;
     }
 
     if (param->runas) {
         ret = change_process_owner(param->runas);
-        if (ret) {
-            ptm_cleanup();
-            exit(ret);
-        }
+        if (ret)
+            goto error_exit;
     }
+
+    if (create_seccomp_profile(true, param->seccomp_action) < 0) {
+        ret = -14;
+        goto error_exit;
+    }
+
+    return;
+
+error_exit:
+    ptm_cleanup();
+
+    exit(ret);
 }
 
 static void ptm_cleanup(void)
@@ -1303,12 +1412,14 @@ static void ptm_cleanup(void)
     pidfile_remove();
     log_global_free();
     tpmstate_global_free();
+    SWTPM_NVRAM_Shutdown();
 }
 
 static const struct cuse_lowlevel_ops clops = {
     .open = ptm_open,
     .read = ptm_read,
     .write = ptm_write,
+    .release = ptm_release,
     .ioctl = ptm_ioctl,
     .init_done = ptm_init_done,
 };
@@ -1323,13 +1434,14 @@ ptm_cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
 {
     int mt;
     int ret;
+    struct cuse_param *param = userdata;
 
     ptm_fuse_session = cuse_lowlevel_setup(argc, argv, ci, clop, &mt,
                                            userdata);
     if (ptm_fuse_session == NULL)
         return 1;
 
-    if (mt)
+    if (param->seccomp_action == SWTPM_SECCOMP_ACTION_NONE && mt)
         ret = fuse_session_loop_mt(ptm_fuse_session);
     else
         ret = fuse_session_loop(ptm_fuse_session);
@@ -1362,21 +1474,34 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
         {"migration-key" , required_argument, 0, 'K'},
         {"pid"           , required_argument, 0, 'p'},
         {"tpmstate"      , required_argument, 0, 's'},
+        {"flags"         , required_argument, 0, 'F'},
         {"tpm2"          ,       no_argument, 0, '2'},
         {"help"          ,       no_argument, 0, 'h'},
         {"version"       ,       no_argument, 0, 'v'},
+#ifdef WITH_SECCOMP
+        {"seccomp"       , required_argument, 0, 'S'},
+#endif
+        {"print-capabilities"
+                         ,       no_argument, 0, 'a'},
+        {"print-states"  ,       no_argument, 0, 'e'},
         {NULL            , 0                , 0, 0  },
     };
     struct cuse_info cinfo;
-    struct cuse_param param;
+    struct cuse_param param = {
+        .startupType = _TPM_ST_NONE,
+    };
     const char *devname = NULL;
     char *cinfo_argv[1] = { 0 };
     unsigned int num;
     struct passwd *passwd;
-    const char *tpmdir;
+    const char *uri = NULL;
     int n, tpmfd;
     char path[PATH_MAX];
     int ret = 0;
+    bool printcapabilities = false;
+    bool printstates = false;
+    bool need_init_cmd = true;
+    TPM_RESULT res;
 
     memset(&cinfo, 0, sizeof(cinfo));
     memset(&param, 0, sizeof(param));
@@ -1458,12 +1583,24 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
         case 'L':
             param.localitydata = optarg;
             break;
+        case 'F':
+            param.flagsdata = optarg;
+            break;
         case '2':
             tpmversion = TPMLIB_TPM_VERSION_2;
             break;
+        case 'S':
+            param.seccompdata = optarg;
+            break;
         case 'h': /* help */
             fprintf(stdout, usage, prgname, iface);
             goto exit;
+        case 'a':
+            printcapabilities = true;
+            break;
+        case 'e':
+            printstates = true;
+            break;
         case 'v': /* version */
             fprintf(stdout, "TPM emulator CUSE interface version %d.%d.%d, "
                     "Copyright (c) 2014-2015 IBM Corp.\n",
@@ -1481,18 +1618,58 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
         goto exit;
     }
 
-    /*
-     * choose the TPM version early so that getting/setting
-     * buffer size works.
-     */
-    if (TPMLIB_ChooseTPMVersion(tpmversion) != TPM_SUCCESS) {
-        logprintf(STDERR_FILENO,
-                  "Error: Could not choose TPM version.\n");
+    if (setuid(0)) {
+        logprintf(STDERR_FILENO, "Error: Unable to setuid root. uid = %d, "
+                  "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
+        ret = -4;
+        goto exit;
+    }
+
+    if (param.runas) {
+        if (!(passwd = getpwnam(param.runas))) {
+            logprintf(STDERR_FILENO, "User '%s' does not exist\n",
+                      param.runas);
+            ret = -5;
+            goto exit;
+        }
+    }
+
+    if (handle_log_options(param.logging) < 0) {
+        ret = EXIT_FAILURE;
+        goto exit;
+    }
+
+    if (printcapabilities) {
+        /*
+         * Choose the TPM version so that getting/setting buffer size works.
+         * Ignore failure, for backward compatibility when TPM 1.2 is disabled.
+         */
+        ret = capabilities_print_json(true, tpmversion) ? EXIT_FAILURE : EXIT_SUCCESS;
+        goto exit;
+    }
+
+    if (tpmlib_choose_tpm_version(tpmversion) != TPM_SUCCESS) {
         ret = EXIT_FAILURE;
         goto exit;
     }
 
-    SWTPM_NVRAM_Set_TPMVersion(tpmversion);
+    tpmstate_set_version(tpmversion);
+
+    if (printstates) {
+        if (handle_tpmstate_options(param.tpmstatedata) < 0) {
+            ret = EXIT_FAILURE;
+            goto exit;
+        }
+        if (param.tpmstatedata == NULL) {
+            logprintf(STDERR_FILENO,
+                      "Error: --tpmstate option is required for --print-states\n");
+            ret = EXIT_FAILURE;
+            goto exit;
+        }
+        ret = SWTPM_NVRAM_PrintJson();
+        ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
+        goto exit;
+    }
 
     if (!cinfo.dev_info_argv) {
         logprintf(STDERR_FILENO, "Error: device name missing\n");
@@ -1500,34 +1677,20 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
         goto exit;
     }
 
-    if (handle_log_options(param.logging) < 0 ||
-        handle_key_options(param.keydata) < 0 ||
+    if (handle_key_options(param.keydata) < 0 ||
         handle_migration_key_options(param.migkeydata) < 0 ||
         handle_pid_options(param.piddata) < 0 ||
         handle_tpmstate_options(param.tpmstatedata) < 0 ||
-        handle_locality_options(param.localitydata, &locality_flags) < 0) {
+        handle_seccomp_options(param.seccompdata, &param.seccomp_action) < 0 ||
+        handle_locality_options(param.localitydata, &locality_flags) < 0 ||
+        handle_flags_options(param.flagsdata, &need_init_cmd,
+                             &param.startupType) < 0) {
         ret = -3;
         goto exit;
     }
 
-    if (setuid(0)) {
-        logprintf(STDERR_FILENO, "Error: Unable to setuid root. uid = %d, "
-                  "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
-        ret = -4;
-        goto exit;
-    }
-
-    if (param.runas) {
-        if (!(passwd = getpwnam(param.runas))) {
-            logprintf(STDERR_FILENO, "User '%s' does not exist\n",
-                      param.runas);
-            ret = -5;
-            goto exit;
-        }
-    }
-
-    tpmdir = tpmstate_get_dir();
-    if (tpmdir == NULL) {
+    uri = tpmstate_get_backend_uri();
+    if (uri == NULL) {
         logprintf(STDERR_FILENO,
                   "Error: No TPM state directory is defined; "
                   "TPM_PATH is not set\n");
@@ -1566,6 +1729,21 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
 
     worker_thread_init();
 
+    if (!need_init_cmd) {
+        if (tpm_start(0, tpmversion, &res) < 0) {
+            ret = -1;
+            goto exit;
+        }
+        tpm_running = true;
+    }
+
+    if (param.startupType != _TPM_ST_NONE) {
+        if (ptm_send_startup(param.startupType, tpmversion) < 0) {
+            ret = -1;
+            goto exit;
+        }
+    }
+
 #if GLIB_MINOR_VERSION >= 32
     g_mutex_init(FILE_OPS_LOCK);
 #else