From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <aderumier@odiso.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 0316D76A78 for <pve-devel@lists.proxmox.com>; Fri, 16 Jul 2021 16:47:55 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id EE0BF12AF4 for <pve-devel@lists.proxmox.com>; Fri, 16 Jul 2021 16:47:24 +0200 (CEST) Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 7CA2512AEB for <pve-devel@lists.proxmox.com>; Fri, 16 Jul 2021 16:47:21 +0200 (CEST) Received: by mail-wm1-x32b.google.com with SMTP id a23-20020a05600c2257b0290236ec98bebaso3577891wmm.1 for <pve-devel@lists.proxmox.com>; Fri, 16 Jul 2021 07:47:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=odiso-com.20150623.gappssmtp.com; s=20150623; h=message-id:subject:from:to:date:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=wOUb6YfETTEKapuVjCZNReRaBT+CIcyBdpX2ZokKlsk=; b=I/TLcDqk2auXtXIZGMtxgmbEGyp7YQPs1QkUygBsPyZK2i6MOvaYKg5HSr7oBqXN9F BGIbpHMc5ZY6RvFNIgZt5YJJzKhiu0mShosBkM4MjIbYRK/QBu5IcMvXRmMMoxEzFjZn mEc9jRktcRX7N0ZwjVV1Dc9vSdxBRoZ2QqABDUuO1yiCET1nGecG/GUywpnwb1oWybGr 0nncQzhy0WD0+AaViB8AvG69ml4u199U8CMzyWYOTpV4CZLETzJcw4oSeWHWD8hHjCuf it9y2ju20LuIglQWW8dm4jkJbGLpyRk3dG5R2KHPriYrEMI6Jf4caqNinL76iHcMF7nH maIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:subject:from:to:date:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=wOUb6YfETTEKapuVjCZNReRaBT+CIcyBdpX2ZokKlsk=; b=cw6Swu12kh5ypHGJYEKhH1N5tXiytk54kGA4K7Cm+GLXmkGov8OFdOrgo4/9tae9xc RR5y80VtlNDQZHSQGTn4gojFDhP/5Gx0U84CE/JwP2hMWF/9QJuzD/UUyJmuhFQ0bn01 bKZMMO4RVHTwyFNcxWjXNUPefCmx+9iB6sTOy+3sGYIYwX2+JJg/mF8clJB3HvqlGC9X hdHvJq0se5SoUBa4OV1sWrO+AMLB3A8g4saIL4GZYl5Y8ZVeyTLeYg/hM5FLdUsGdc87 CVmfn1EaoU/NkVhEqIslQXu401nEEbtO2Dc24mDWOHJW+ApITHwrnb+KcyCrV6QU9BaI WGhw== X-Gm-Message-State: AOAM532QSC5yOCVjGzAbrbMCr+nwXy2cRcs4AGReHMWGQsMYyZIjyGNh koyy6y6I4VrbCDG60RoRWp7Uk+EdxAnbGoHw X-Google-Smtp-Source: ABdhPJwx0DMcMMNpEjSPpN/bsdBbSDCbsY4LowLIrSeYGVl2Owvtlrg4ULElg9zjFRkyhNe/UdaAkQ== X-Received: by 2002:a1c:7410:: with SMTP id p16mr6509906wmc.6.1626446835034; Fri, 16 Jul 2021 07:47:15 -0700 (PDT) Received: from [192.168.178.50] ([79.132.252.54]) by smtp.gmail.com with ESMTPSA id 12sm12017044wme.28.2021.07.16.07.47.14 for <pve-devel@lists.proxmox.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 Jul 2021 07:47:14 -0700 (PDT) Message-ID: <fd79b9f13f8d2fe59e0274cc6916b1a88c470926.camel@odiso.com> From: alexandre derumier <aderumier@odiso.com> To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> Date: Fri, 16 Jul 2021 16:47:14 +0200 In-Reply-To: <20210715142319.1457131-3-s.reiter@proxmox.com> References: <20210715142319.1457131-1-s.reiter@proxmox.com> <20210715142319.1457131-3-s.reiter@proxmox.com> Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.40.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.797 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature RCVD_IN_DNSWL_NONE -0.0001 Sender listed at https://www.dnswl.org/, no trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] [RFC qemu-server 2/2] fix #3075: add TPM v1.2 and v2.0 support via swtpm X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/> List-Post: <mailto:pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> X-List-Received-Date: Fri, 16 Jul 2021 14:47:55 -0000 Hi, I have found old post where a nvram device (using a qcow2 or raw file as backend) was used with tpm https://libvir-list.redhat.narkive.com/eOrJPdYX/libvirt-how-libvirt-address-qemu-command-line-args also dev doc from 2011 mention it https://wiki.qemu.org/Features/TPM (I don't have tested to verify) Le jeudi 15 juillet 2021 à 16:23 +0200, Stefan Reiter a écrit : > Starts an instance of swtpm per VM in it's systemd scope, it will > terminate by itself if the VM exits, or be terminated manually if > startup fails. > > Before first use, a TPM state is created via swtpm_setup. The state > lives in "/etc/pve/priv/tpm/<vmid>-<version>/". > > TPM state is cleared if the 'tpm' config option is removed or the > version changed, effectively clearing any stored keys/data. > > Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> > --- > PVE/QemuServer.pm | 134 > +++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 133 insertions(+), 1 deletion(-) > > diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm > index b0fe257..76a25ae 100644 > --- a/PVE/QemuServer.pm > +++ b/PVE/QemuServer.pm > @@ -686,6 +686,12 @@ EODESCR > description => "Configure a VirtIO-based Random Number > Generator.", > optional => 1, > }, > + tpm => { > + optional => 1, > + type => 'string', > + enum => [ qw(v1.2 v2.0) ], > + description => "Configure an emulated Trusted Platform > Module.", > + }, > }; > > my $cicustom_fmt = { > @@ -2945,6 +2951,116 @@ sub audio_devs { > return $devs; > } > > +sub get_tpm_paths { > + my ($vmid, $version) = @_; > + return { > + state => "/etc/pve/priv/tpm/$vmid-$version/", > + socket => "/var/run/qemu-server/$vmid.swtpm", > + pid => "/var/run/qemu-server/$vmid.swtpm.pid", > + filename => $version eq "v1.2" ? "tpm-00.permall" : "tpm2- > 00.permall", > + }; > +} > + > +sub print_tpm_device { > + my ($vmid, $version) = @_; > + my $paths = get_tpm_paths($vmid, $version); > + > + my $devs = []; > + > + push @$devs, "-chardev", "socket,id=tpmchar,path=$paths- > >{socket}"; > + push @$devs, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar"; > + push @$devs, "-device", "tpm-tis,tpmdev=tpmdev"; > + > + return $devs; > +} > + > +sub start_swtpm { > + my ($vmid, $version, $migration) = @_; > + my $paths = get_tpm_paths($vmid, $version); > + > + if ($migration) { > + # we will get migration state from remote, so remove any pre- > existing > + clear_tpm_states($vmid); > + File::Path::make_path($paths->{state}); > + } else { > + # run swtpm_setup to create a new TPM state if it doesn't > exist yet > + if (! -f "$paths->{state}/$paths->{filename}") { > + print "Creating new TPM state\n"; > + > + # swtpm_setup does not like /etc/pve/priv, so create in > tempdir > + my $tmppath = "/tmp/tpm-$vmid-$$"; > + File::Path::make_path($tmppath, mode => 0600); > + my $setup_cmd = [ > + "swtpm_setup", > + "--tpmstate", > + "$tmppath", > + "--createek", > + "--create-ek-cert", > + "--create-platform-cert", > + "--lock-nvram", > + "--config", > + "/etc/swtpm_setup.conf", # do not use XDG configs > + "--runas", > + "0", # force creation as root, error if not possible > + ]; > + > + push @$setup_cmd, "--tpm2" if $version eq 'v2.0'; > + # TPM 2.0 supports ECC crypto, use if possible > + push @$setup_cmd, "--ecc" if $version eq 'v2.0'; > + > + # produces a lot of verbose output, only show on error > + my $tpmout = ""; > + run_command($setup_cmd, outfunc => sub { > + $tpmout .= $1 . "\n"; > + }); > + > + File::Path::make_path($paths->{state}); > + my $res = File::Copy::move("$tmppath/$paths->{filename}", > + "$paths->{state}/$paths->{filename}"); > + File::Path::rmtree($tmppath); > + if (!$res) { > + my $err = $!; > + File::Path::rmtree($tmppath); > + print "swtpm_setup reported:\n$tpmout"; > + die "couldn't move TPM state into '$paths->{state}' - > $err\n"; > + } > + } > + } > + > + my $emulator_cmd = [ > + "swtpm", > + "socket", > + "--tpmstate", > + "dir=$paths->{state},mode=0600", > + "--ctrl", > + "type=unixio,path=$paths->{socket},mode=0600", > + "--pid", > + "file=$paths->{pid}", > + "--terminate", # terminate on QEMU disconnect > + "--daemon", > + ]; > + push @$emulator_cmd, "--tpm2" if $version eq 'v2.0'; > + run_command($emulator_cmd); > + > + # return untainted PID of swtpm daemon so it can be killed on > error > + file_read_firstline($paths->{pid}) =~ m/(\d+)/; > + return $1; > +} > + > +# clear any TPM states other than the ones relevant for $version > +sub clear_tpm_states { > + my ($vmid, $keep_version) = @_; > + > + my $clear = sub { > + my ($v) = @_; > + my $paths = get_tpm_paths($vmid, $v); > + rmtree $paths->{state}; > + }; > + > + &$clear("v1.2") if !$keep_version || $keep_version ne "v1.2"; > + &$clear("v2.0") if !$keep_version || $keep_version ne "v2.0"; > +} > + > sub vga_conf_has_spice { > my ($vga) = @_; > > @@ -3446,6 +3562,11 @@ sub config_to_command { > push @$devices, @$audio_devs; > } > > + if (my $tpmver = $conf->{tpm}) { > + my $tpmdev = print_tpm_device($vmid, $tpmver); > + push @$devices, @$tpmdev; > + } > + > my $sockets = 1; > $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer > iused > $sockets = $conf->{sockets} if $conf->{sockets}; > @@ -4829,6 +4950,8 @@ sub vmconfig_apply_pending { > } > } > > + PVE::QemuServer::clear_tpm_states($vmid, $conf->{tpm}); > + > # write all changes at once to avoid unnecessary i/o > PVE::QemuConfig->write_config($vmid, $conf); > } > @@ -5329,8 +5452,17 @@ sub vm_start_nolock { > PVE::Tools::run_fork sub { > PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM > $vmid", %properties); > > + my $tpmpid; > + if (my $tpmver = $conf->{tpm}) { > + # start the TPM emulator so QEMU can connect on start > + $tpmpid = start_swtpm($vmid, $tpmver, $migratedfrom); > + } > + > my $exitcode = run_command($cmd, %run_params); > - die "QEMU exited with code $exitcode\n" if $exitcode; > + if ($exitcode) { > + kill 'TERM', $tpmpid if $tpmpid; > + die "QEMU exited with code $exitcode\n"; > + } > }; > }; >