mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 04:09:48 +00:00
devices: remove --software-tpm support
The software TPM backed by the libtpm2 simulator was only used for testing; now that we have the vTPM proxy device, the software TPM is no longer needed. This also allows removal of the tpm2 submodule (tpm2-sys/libtpm2). BUG=b:300673042 TEST=tools/dev_container tools/presubmit Change-Id: I3feb5f715f9f12f832450df712c0f63ed7b4fb13 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4875221 Reviewed-by: Dennis Kempin <denniskempin@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
d2e7bc77c6
commit
e10df59fd3
22 changed files with 4 additions and 561 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,6 +1,3 @@
|
|||
[submodule "tpm2-sys/libtpm2"]
|
||||
path = tpm2-sys/libtpm2
|
||||
url = https://chromium.googlesource.com/chromiumos/third_party/tpm2
|
||||
[submodule "third_party/minigbm"]
|
||||
path = third_party/minigbm
|
||||
url = https://chromium.googlesource.com/chromiumos/platform/minigbm
|
||||
|
|
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -924,7 +924,6 @@ dependencies = [
|
|||
"system_api",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tpm2",
|
||||
"tube_transporter",
|
||||
"usb_util",
|
||||
"vfio_sys",
|
||||
|
@ -2628,21 +2627,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tpm2"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"tpm2-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tpm2-sys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tube_transporter"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -80,8 +80,6 @@ members = [
|
|||
"system_api",
|
||||
"third_party/vmm_vhost",
|
||||
"tools/impl/catapult_converter",
|
||||
"tpm2-sys",
|
||||
"tpm2",
|
||||
"usb_sys",
|
||||
"usb_util",
|
||||
"vendor/generic/anti_tamper",
|
||||
|
@ -169,10 +167,6 @@ swap = ["aarch64/swap", "arch/swap", "devices/swap", "vm_control/swap", "x86_64/
|
|||
## Enables collection of VM statistics.
|
||||
stats = ["devices/stats"]
|
||||
|
||||
## Enables trusted platform module emulation for the guest. This relies on the software emulated
|
||||
## TPM implementation from libtpm2 which is suited only for testing purposes.
|
||||
tpm = ["devices/tpm"]
|
||||
|
||||
## Enables USB host device passthrough via an emulated XHCI controller.
|
||||
## USB is supported only on unix/linux. The feature is a no-op on windows.
|
||||
usb = ["devices/usb"]
|
||||
|
@ -332,7 +326,6 @@ all-default = [
|
|||
"slirp",
|
||||
"swap",
|
||||
"trace_marker",
|
||||
"tpm",
|
||||
"vaapi",
|
||||
"video-decoder",
|
||||
"video-encoder",
|
||||
|
@ -371,7 +364,6 @@ all-armhf = [
|
|||
"gdb",
|
||||
"libvda-stub",
|
||||
"net",
|
||||
"tpm",
|
||||
]
|
||||
|
||||
## All features that are compiled and tested for mingw64
|
||||
|
|
|
@ -15,7 +15,6 @@ gunyah = []
|
|||
libvda-stub = ["libvda/libvda-stub"]
|
||||
net = []
|
||||
geniezone = []
|
||||
tpm = ["tpm2"]
|
||||
usb = []
|
||||
vaapi = ["cros-codecs/vaapi", "downcast-rs", "crc32fast"]
|
||||
video-decoder = []
|
||||
|
@ -82,7 +81,6 @@ smallvec = "1.6.1"
|
|||
sync = { path = "../common/sync" }
|
||||
system_api = { path = "../system_api", optional = true }
|
||||
thiserror = "1.0.20"
|
||||
tpm2 = { path = "../tpm2", optional = true }
|
||||
cros_tracing = { path = "../cros_tracing" }
|
||||
swap = { path = "../swap" }
|
||||
vmm_vhost = { path = "../third_party/vmm_vhost", features = ["vmm", "device"] }
|
||||
|
|
|
@ -25,8 +25,6 @@ pub mod pl030;
|
|||
pub mod pmc_virt;
|
||||
mod serial;
|
||||
pub mod serial_device;
|
||||
#[cfg(feature = "tpm")]
|
||||
mod software_tpm;
|
||||
mod suspendable;
|
||||
mod sys;
|
||||
mod virtcpufreq;
|
||||
|
@ -127,8 +125,6 @@ pub use self::serial_device::SerialDevice;
|
|||
pub use self::serial_device::SerialHardware;
|
||||
pub use self::serial_device::SerialParameters;
|
||||
pub use self::serial_device::SerialType;
|
||||
#[cfg(feature = "tpm")]
|
||||
pub use self::software_tpm::SoftwareTpm;
|
||||
pub use self::suspendable::DeviceState;
|
||||
pub use self::suspendable::Suspendable;
|
||||
pub use self::virtcpufreq::VirtCpufreq;
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright 2022 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! Software TPM backend using the TPM2 simulator from the `tpm2` crate.
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Context;
|
||||
use tpm2::Simulator;
|
||||
|
||||
use super::virtio::TpmBackend;
|
||||
|
||||
pub struct SoftwareTpm {
|
||||
simulator: Simulator,
|
||||
}
|
||||
|
||||
impl SoftwareTpm {
|
||||
pub fn new<P: AsRef<Path>>(storage: P) -> anyhow::Result<Self> {
|
||||
fs::create_dir_all(storage.as_ref()).context("failed to create directory for simulator")?;
|
||||
env::set_current_dir(storage).context("failed to change into simulator directory")?;
|
||||
let simulator = Simulator::singleton_in_current_directory();
|
||||
Ok(SoftwareTpm { simulator })
|
||||
}
|
||||
}
|
||||
|
||||
impl TpmBackend for SoftwareTpm {
|
||||
fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
|
||||
self.simulator.execute_command(command)
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ pub mod net;
|
|||
pub mod pvclock;
|
||||
mod queue;
|
||||
mod rng;
|
||||
#[cfg(any(feature = "tpm", feature = "vtpm"))]
|
||||
#[cfg(feature = "vtpm")]
|
||||
mod tpm;
|
||||
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
|
||||
mod video;
|
||||
|
@ -88,9 +88,9 @@ pub use self::queue::Queue;
|
|||
pub use self::queue::QueueConfig;
|
||||
pub use self::rng::Rng;
|
||||
pub use self::scsi::Device as ScsiDevice;
|
||||
#[cfg(any(feature = "tpm", feature = "vtpm"))]
|
||||
#[cfg(feature = "vtpm")]
|
||||
pub use self::tpm::Tpm;
|
||||
#[cfg(any(feature = "tpm", feature = "vtpm"))]
|
||||
#[cfg(feature = "vtpm")]
|
||||
pub use self::tpm::TpmBackend;
|
||||
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
|
||||
pub use self::video::VideoDevice;
|
||||
|
|
|
@ -27,8 +27,7 @@ Here is a (non-comprehensive) list of emulated devices provided by crosvm.
|
|||
- [`pmem`] - Persistent memory.
|
||||
- [`rng`] - Entropy source used to seed guest OS's entropy pool.
|
||||
- [`snd`] - Encodes and decodes audio streams.
|
||||
- [`tpm`] - Creates a TPM (Trusted Platform Module) device backed by libtpm2 simulator or vTPM
|
||||
daemon.
|
||||
- [`tpm`] - Creates a TPM (Trusted Platform Module) device backed by vTPM daemon.
|
||||
- [`video`] - Allows the guest to leverage the host's video capabilities.
|
||||
- [`wayland`] - Allows the guest to use the host's Wayland socket.
|
||||
- [`vsock`] - Enables use of virtual sockets for the guest.
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# Copyright 2019 The ChromiumOS Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
@include /usr/share/policy/crosvm/common_device.policy
|
||||
|
||||
chdir: 1
|
||||
fstat: 1
|
||||
fsync: 1
|
||||
getrandom: 1
|
||||
getuid: 1
|
||||
mkdirat: 1
|
||||
newfstatat: 1
|
||||
openat: 1
|
||||
prctl: arg0 == PR_SET_NAME
|
||||
socket: return EACCES
|
||||
statx: 1
|
|
@ -1,18 +0,0 @@
|
|||
# Copyright 2018 The ChromiumOS Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
@include /usr/share/policy/crosvm/common_device.policy
|
||||
|
||||
chdir: 1
|
||||
fstat: 1
|
||||
fsync: 1
|
||||
getrandom: 1
|
||||
getuid: 1
|
||||
mkdir: 1
|
||||
open: 1
|
||||
openat: 1
|
||||
prctl: arg0 == PR_SET_NAME
|
||||
socket: return EACCES
|
||||
stat: 1
|
||||
statx: 1
|
|
@ -1,19 +0,0 @@
|
|||
# Copyright 2018 The ChromiumOS Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
@include /usr/share/policy/crosvm/common_device.policy
|
||||
|
||||
chdir: 1
|
||||
fstat: 1
|
||||
fsync: 1
|
||||
getrandom: 1
|
||||
getuid: 1
|
||||
mkdir: 1
|
||||
newfstatat: 1
|
||||
open: 1
|
||||
openat: 1
|
||||
prctl: arg0 == PR_SET_NAME
|
||||
socket: return EACCES
|
||||
stat: 1
|
||||
statx: 1
|
|
@ -2021,13 +2021,6 @@ pub struct RunCommand {
|
|||
/// path to put the control socket. If PATH is a directory, a name will be generated
|
||||
pub socket: Option<PathBuf>,
|
||||
|
||||
#[cfg(feature = "tpm")]
|
||||
#[argh(switch)]
|
||||
#[serde(skip)] // TODO(b/255223604)
|
||||
#[merge(strategy = overwrite_option)]
|
||||
/// enable a software emulated trusted platform module device
|
||||
pub software_tpm: Option<bool>,
|
||||
|
||||
#[cfg(feature = "audio")]
|
||||
#[argh(option, arg_name = "PATH")]
|
||||
#[serde(skip)] // TODO(b/255223604)
|
||||
|
@ -2818,11 +2811,6 @@ impl TryFrom<RunCommand> for super::config::Config {
|
|||
cfg.vhost_scmi = cmd.vhost_scmi.unwrap_or_default();
|
||||
}
|
||||
|
||||
#[cfg(feature = "tpm")]
|
||||
{
|
||||
cfg.software_tpm = cmd.software_tpm.unwrap_or_default();
|
||||
}
|
||||
|
||||
#[cfg(feature = "vtpm")]
|
||||
{
|
||||
cfg.vtpm_proxy = cmd.vtpm_proxy.unwrap_or_default();
|
||||
|
|
|
@ -864,8 +864,6 @@ pub struct Config {
|
|||
#[cfg(all(windows, feature = "audio"))]
|
||||
pub snd_split_config: Option<SndSplitConfig>,
|
||||
pub socket_path: Option<PathBuf>,
|
||||
#[cfg(feature = "tpm")]
|
||||
pub software_tpm: bool,
|
||||
#[cfg(feature = "audio")]
|
||||
pub sound: Option<PathBuf>,
|
||||
pub strict_balloon: bool,
|
||||
|
@ -1067,8 +1065,6 @@ impl Default for Config {
|
|||
#[cfg(all(windows, feature = "audio"))]
|
||||
snd_split_config: None,
|
||||
socket_path: None,
|
||||
#[cfg(feature = "tpm")]
|
||||
software_tpm: false,
|
||||
#[cfg(feature = "audio")]
|
||||
sound: None,
|
||||
strict_balloon: false,
|
||||
|
|
|
@ -383,16 +383,6 @@ fn create_virtio_devices(
|
|||
devs.push(create_rng_device(cfg.protection_type, &cfg.jail_config)?);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tpm")]
|
||||
{
|
||||
if cfg.software_tpm {
|
||||
devs.push(create_software_tpm_device(
|
||||
cfg.protection_type,
|
||||
&cfg.jail_config,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vtpm")]
|
||||
{
|
||||
if cfg.vtpm_proxy {
|
||||
|
|
|
@ -59,8 +59,6 @@ use devices::BusDeviceObj;
|
|||
use devices::IommuDevType;
|
||||
use devices::PciAddress;
|
||||
use devices::PciDevice;
|
||||
#[cfg(feature = "tpm")]
|
||||
use devices::SoftwareTpm;
|
||||
use devices::VfioDevice;
|
||||
use devices::VfioDeviceType;
|
||||
use devices::VfioPciDevice;
|
||||
|
@ -490,49 +488,6 @@ pub fn create_virtio_snd_device(
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "tpm")]
|
||||
pub fn create_software_tpm_device(
|
||||
protection_type: ProtectionType,
|
||||
jail_config: &Option<JailConfig>,
|
||||
) -> DeviceResult {
|
||||
use std::ffi::CString;
|
||||
use std::fs;
|
||||
use std::process;
|
||||
|
||||
let (jail, tpm_storage) = if let Some(jail_config) = jail_config {
|
||||
let mut config = SandboxConfig::new(jail_config, "tpm_device");
|
||||
config.bind_mounts = true;
|
||||
let mut jail =
|
||||
create_sandbox_minijail(&jail_config.pivot_root, MAX_OPEN_FILES_DEFAULT, &config)?;
|
||||
|
||||
let pid = process::id();
|
||||
let crosvm_uid = geteuid();
|
||||
let crosvm_gid = getegid();
|
||||
let tpm_pid_dir = format!("/run/vm/tpm.{}", pid);
|
||||
let tpm_storage = PathBuf::from(&tpm_pid_dir);
|
||||
fs::create_dir_all(&tpm_storage).with_context(|| {
|
||||
format!("failed to create tpm storage dir {}", tpm_storage.display())
|
||||
})?;
|
||||
let tpm_pid_dir_c = CString::new(tpm_pid_dir).expect("no nul bytes");
|
||||
chown(&tpm_pid_dir_c, crosvm_uid, crosvm_gid).context("failed to chown tpm storage")?;
|
||||
|
||||
jail.mount_bind(&tpm_storage, &tpm_storage, true)?;
|
||||
|
||||
(Some(jail), tpm_storage)
|
||||
} else {
|
||||
// Path used inside cros_sdk which does not have /run/vm.
|
||||
(None, PathBuf::from("/tmp/tpm-simulator"))
|
||||
};
|
||||
|
||||
let backend = SoftwareTpm::new(tpm_storage).context("failed to create SoftwareTpm")?;
|
||||
let dev = virtio::Tpm::new(Box::new(backend), virtio::base_features(protection_type));
|
||||
|
||||
Ok(VirtioDeviceStub {
|
||||
dev: Box::new(dev),
|
||||
jail,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "vtpm")]
|
||||
pub fn create_vtpm_proxy_device(
|
||||
protection_type: ProtectionType,
|
||||
|
|
|
@ -15,8 +15,6 @@ BUILD_FEATURES: Dict[str, str] = {
|
|||
# Do not build these on riscv64. They don't yet have riscv64 support of the backing libraries in the
|
||||
# dev container.
|
||||
DO_NOT_BUILD_RISCV64 = [
|
||||
"tpm2",
|
||||
"tpm2-sys",
|
||||
"libvda",
|
||||
"libva",
|
||||
"ffmpeg",
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
[package]
|
||||
name = "tpm2-sys"
|
||||
version = "0.1.0"
|
||||
authors = ["The Chromium OS Authors"]
|
||||
edition = "2021"
|
||||
links = "tpm2"
|
||||
|
||||
[build-dependencies]
|
||||
pkg-config = "*"
|
||||
anyhow = "*"
|
|
@ -1,91 +0,0 @@
|
|||
// Copyright 2019 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use anyhow::bail;
|
||||
use anyhow::Result;
|
||||
|
||||
/// Returns the target triplet prefix for gcc commands. No prefix is required
|
||||
/// for native builds.
|
||||
fn get_cross_compile_prefix() -> String {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if env::var("HOST").unwrap() == target {
|
||||
return String::from("");
|
||||
}
|
||||
|
||||
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
let env = if target.ends_with("-gnueabihf") {
|
||||
String::from("gnueabihf")
|
||||
} else {
|
||||
env::var("CARGO_CFG_TARGET_ENV").unwrap()
|
||||
};
|
||||
format!("{}-{}-{}-", arch, os, env)
|
||||
}
|
||||
|
||||
fn build_libtpm2(out_dir: &Path) -> Result<()> {
|
||||
let lib_path = out_dir.join("libtpm2.a");
|
||||
if lib_path.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if !Path::new("libtpm2/.git").exists() {
|
||||
bail!(
|
||||
"tpm2-sys/libtpm2 source does not exist, did you forget to \
|
||||
`git submodule update --init`?"
|
||||
);
|
||||
}
|
||||
|
||||
let make_flags = env::var("CARGO_MAKEFLAGS").unwrap();
|
||||
let prefix = get_cross_compile_prefix();
|
||||
let status = Command::new("make")
|
||||
.env("MAKEFLAGS", make_flags)
|
||||
.arg(format!("AR={}ar", prefix))
|
||||
.arg(format!("CC={}gcc", prefix))
|
||||
.arg(format!("OBJCOPY={}objcopy", prefix))
|
||||
.arg("CFLAGS=-Wno-error")
|
||||
.arg(format!("obj={}", out_dir.display()))
|
||||
.current_dir("libtpm2")
|
||||
.status()?;
|
||||
if !status.success() {
|
||||
bail!("make failed with status: {}", status);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Skip installing dependencies when generating documents.
|
||||
if std::env::var("CARGO_DOC").is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// libtpm2 is unix only
|
||||
if std::env::var("CARGO_CFG_UNIX").is_err() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Use tpm2 package from the standard system location if available.
|
||||
if pkg_config::Config::new()
|
||||
.statik(true)
|
||||
.probe("libtpm2")
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Otherwise build from source
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
build_libtpm2(&out_dir)?;
|
||||
|
||||
println!("cargo:rustc-link-search={}", out_dir.display());
|
||||
println!("cargo:rustc-link-lib=static=tpm2");
|
||||
println!("cargo:rustc-link-lib=ssl");
|
||||
println!("cargo:rustc-link-lib=crypto");
|
||||
Ok(())
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 96017dcdb1104099315b9e448c85d1489a41ae82
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2019 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! Bindings for the TPM2 simulator library.
|
||||
|
||||
#![cfg(unix)]
|
||||
|
||||
use std::os::raw::c_int;
|
||||
use std::os::raw::c_uchar;
|
||||
use std::os::raw::c_uint;
|
||||
|
||||
extern "C" {
|
||||
pub fn TPM_Manufacture(firstTime: c_int) -> c_int;
|
||||
pub fn _plat__SetNvAvail();
|
||||
pub fn _plat__Signal_PowerOn() -> c_int;
|
||||
pub fn _TPM_Init();
|
||||
pub fn ExecuteCommand(
|
||||
requestSize: c_uint,
|
||||
request: *mut c_uchar,
|
||||
responseSize: *mut c_uint,
|
||||
response: *mut *mut c_uchar,
|
||||
);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "tpm2"
|
||||
version = "0.1.0"
|
||||
authors = ["The Chromium OS Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tpm2-sys = { path = "../tpm2-sys" }
|
229
tpm2/src/lib.rs
229
tpm2/src/lib.rs
|
@ -1,229 +0,0 @@
|
|||
// Copyright 2019 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! TPM2 (Trusted Platform Module 2.0) simulator.
|
||||
|
||||
#![cfg(unix)]
|
||||
|
||||
use std::os::raw::c_int;
|
||||
use std::os::raw::c_uint;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
static SIMULATOR_EXISTS: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// A libtpm2-based TPM simulator.
|
||||
///
|
||||
/// At most one simulator may exist per process because libtpm2 uses a static
|
||||
/// global response buffer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// let mut simulator = tpm2::Simulator::singleton_in_current_directory();
|
||||
///
|
||||
/// let command = &[ /* ... */ ];
|
||||
/// let response = simulator.execute_command(command);
|
||||
/// println!("{:?}", response);
|
||||
/// ```
|
||||
pub struct Simulator {
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
impl Simulator {
|
||||
/// Initializes a TPM simulator in the current working directory.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if a TPM simulator has already been initialized by this process.
|
||||
pub fn singleton_in_current_directory() -> Self {
|
||||
let already_existed = SIMULATOR_EXISTS.swap(true, Ordering::SeqCst);
|
||||
if already_existed {
|
||||
panic!("libtpm2 simulator singleton already exists");
|
||||
}
|
||||
|
||||
// Based on trunks:
|
||||
// https://chromium.googlesource.com/chromiumos/platform2/+/e4cf13c05773f3446bd76a13c4e37f0b80728711/trunks/tpm_simulator_handle.cc
|
||||
tpm_manufacture(true);
|
||||
plat_set_nv_avail();
|
||||
plat_signal_power_on();
|
||||
tpm_init();
|
||||
|
||||
let mut simulator = Simulator { _priv: () };
|
||||
|
||||
// Send TPM2_Startup(TPM_SU_CLEAR), ignore the result. This is normally
|
||||
// done by firmware.
|
||||
let startup_command = &[
|
||||
0x80, 0x01, // TPM_ST_NO_SESSIONS
|
||||
0x00, 0x00, 0x00, 0x0c, // commandSize = 12
|
||||
0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup
|
||||
0x00, 0x00, // TPM_SU_CLEAR
|
||||
];
|
||||
let _ = simulator.execute_command(startup_command);
|
||||
|
||||
simulator
|
||||
}
|
||||
|
||||
/// Sends a TPM command to the TPM simulator, waits for the work to be
|
||||
/// performed, and receives back the TPM response.
|
||||
///
|
||||
/// Executing a command requires exclusive access to the TPM simulator
|
||||
/// because it mutates libtpm2 static state.
|
||||
///
|
||||
/// The returned response buffer remains valid until the next TPM command is
|
||||
/// executed.
|
||||
#[must_use]
|
||||
pub fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
|
||||
let request_size = command.len() as c_uint;
|
||||
let request = command.as_ptr() as *mut u8;
|
||||
let mut response_size: c_uint = 0;
|
||||
let mut response: *mut u8 = ptr::null_mut();
|
||||
|
||||
// We need to provide the following guarantees in order for this block
|
||||
// of code to be safe:
|
||||
//
|
||||
// - The TPM must have been initialized.
|
||||
//
|
||||
// - There must not be a concurrently executing call to
|
||||
// ExecuteCommand.
|
||||
//
|
||||
// - The `request` pointer must be a valid pointer to `request_size`
|
||||
// bytes of data that remain valid and constant for the full
|
||||
// duration of the call to ExecuteCommand. The implementation may
|
||||
// read up to `request_size` bytes of data from this address.
|
||||
//
|
||||
// - The `response_size` pointer must be a valid pointer to a mutable
|
||||
// unsigned int. The implementation will write the response buffer
|
||||
// size to this address.
|
||||
//
|
||||
// - The `response` pointer must be a valid pointer to a mutable
|
||||
// unsigned char pointer. The implementation will write a pointer to
|
||||
// the start of the response buffer to this address.
|
||||
//
|
||||
// - No more than `response_size` bytes may be read from the response
|
||||
// buffer after the call returns.
|
||||
//
|
||||
// - Data may be read from the response buffer only until the next
|
||||
// call to ExecuteCommand.
|
||||
//
|
||||
// The first guarantee is enforced by the public API of the Simulator
|
||||
// struct, and in particular the singleton_in_current_directory
|
||||
// constructor, which only makes a value of type Simulator available
|
||||
// outside of this module after TPM initialization has been performed.
|
||||
// Thus any Simulator on which the caller may be calling execute_command
|
||||
// from outside of this module is witness that initialization has taken
|
||||
// place.
|
||||
//
|
||||
// The second guarantee is made jointly by the &mut self reference in
|
||||
// execute_command and the singleton_in_current_directory constructor
|
||||
// which uses the SIMULATOR_EXISTS atomic flag to ensure that at most
|
||||
// one value of type Simulator is ever made available to code outside of
|
||||
// this module. Since at most one Simulator exists, and the caller is
|
||||
// holding an exclusive reference to a Simulator, we know that no other
|
||||
// code can be calling execute_command at the same time because they too
|
||||
// would need their own exclusive reference to the same Simulator. We
|
||||
// assume here that all use of libtpm2 within crosvm happens through the
|
||||
// safe bindings provided by this tpm2 crate, so that the codebase
|
||||
// contains no other unsafe calls to ExecuteCommand.
|
||||
//
|
||||
// The remaining guarantees are upheld by the signature and
|
||||
// implementation of execute_command. In particular, note the lifetime
|
||||
// 'a which ties the lifetime of the response slice we return to the
|
||||
// caller to the lifetime of their exclusively held reference to
|
||||
// Simulator. This signature looks the same to Rust as if the response
|
||||
// buffer were a field inside the Simulator struct, rather than a
|
||||
// statically allocated buffer inside libtpm2. As soon as the caller
|
||||
// "mutates" the Simulator by performing another call to
|
||||
// execute_command, the response buffer returned by the previous call is
|
||||
// assumed to be invalidated and is made inaccessible by the borrow
|
||||
// checker.
|
||||
//
|
||||
// Altogether we have guaranteed that execute_command is a safe
|
||||
// abstraction around unsafe code and is entirely safe to call from
|
||||
// outside of this module.
|
||||
//
|
||||
// Note additionally that the call to ExecuteCommand is over FFI so we
|
||||
// need to know that the signature declared by tpm2-sys is
|
||||
// ABI-compatible with the symbol provided by libtpm2.
|
||||
unsafe {
|
||||
tpm2_sys::ExecuteCommand(request_size, request, &mut response_size, &mut response);
|
||||
slice::from_raw_parts(response, response_size as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tpm_manufacture(first_time: bool) {
|
||||
// From libtpm2 documentation:
|
||||
//
|
||||
// This function initializes the TPM values in preparation for the TPM's
|
||||
// first use. This function will fail if previously called. The TPM can
|
||||
// be re-manufactured by calling TPM_Teardown() first and then calling
|
||||
// this function again.
|
||||
//
|
||||
// Arguments
|
||||
//
|
||||
// firstTime: indicates if this is the first call from main()
|
||||
//
|
||||
// Return value
|
||||
//
|
||||
// 0 = success
|
||||
// 1 = manufacturing process previously performed
|
||||
//
|
||||
// Unsafe only because this is over FFI and we need to know that the
|
||||
// signature declared by tpm2-sys is ABI-compatible with the symbol provided
|
||||
// by libtpm2. There are no other invariants to uphold.
|
||||
let ret: c_int = unsafe { tpm2_sys::TPM_Manufacture(first_time as c_int) };
|
||||
|
||||
// We expect that the TPM must not already have been manufactured. The
|
||||
// SIMULATOR_EXISTS atomic flag guards calls to this function such that only
|
||||
// one call can ever be performed by a process.
|
||||
assert!(ret == 0);
|
||||
}
|
||||
|
||||
fn plat_set_nv_avail() {
|
||||
// From libtpm2 documentation:
|
||||
//
|
||||
// Set the current NV state to available. This function is for testing
|
||||
// purpose only. It is not part of the platform NV logic.
|
||||
//
|
||||
// The "for testing purpose only" is unsettling but trunks performs the same
|
||||
// call during initialization so we trust that it is okay.
|
||||
//
|
||||
// Unsafe only because this is over FFI and we need to know that the
|
||||
// signature declared by tpm2-sys is ABI-compatible with the symbol provided
|
||||
// by libtpm2. There are no other invariants to uphold.
|
||||
unsafe {
|
||||
tpm2_sys::_plat__SetNvAvail();
|
||||
}
|
||||
}
|
||||
|
||||
fn plat_signal_power_on() {
|
||||
// From libtpm2 documentation:
|
||||
//
|
||||
// Signal platform power on.
|
||||
//
|
||||
// The libtpm2 implementation always returns 0 but does not document what
|
||||
// the return value means, so we aren't checking it.
|
||||
//
|
||||
// Unsafe only because this is over FFI and we need to know that the
|
||||
// signature declared by tpm2-sys is ABI-compatible with the symbol provided
|
||||
// by libtpm2. There are no other invariants to uphold.
|
||||
unsafe {
|
||||
let _: c_int = tpm2_sys::_plat__Signal_PowerOn();
|
||||
}
|
||||
}
|
||||
|
||||
fn tpm_init() {
|
||||
// This function is not documented in libtpm2. Trunks performs the same call
|
||||
// during initialization so we trust that it is okay.
|
||||
//
|
||||
// Unsafe only because this is over FFI and we need to know that the
|
||||
// signature declared by tpm2-sys is ABI-compatible with the symbol provided
|
||||
// by libtpm2. There are no other invariants to uphold.
|
||||
unsafe {
|
||||
tpm2_sys::_TPM_Init();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue