tpm: Store TPM state under /run/vm
When running in multiprocess mode, such as on a device, TPM state gets
placed in /run/vm/tpm.{pid} (e.g. /run/vm/tpm.22726) where pid is the
pid of the original crosvm process. The TPM simulator will write a
single file called NVChip of size 16384 bytes into this directory. The
directory and NVChip file will have uid and pid set to crosvm.
When running without multiprocess mode / without minijail / probably in
cros_sdk, TPM state is placed in /tmp/tpm-simulator as before. The
/run/vm directory is not present under cros_sdk.
Will follow up with a separate CL to remove the TPM state directory at
crosvm exit.
Tested by running the following on a grunt board (Barla) in dev mode:
sudo crosvm run \
--root rootfs.ext4 \
--socket crosvm.sock \
--seccomp-policy-dir seccomp \
--software-tpm \
-p init=/bin/bash \
-p panic=-1 \
vmlinux.bin
and confirming that /dev/tpm0 and /dev/tpmrm0 are present in the VM.
BUG=chromium:921841
TEST=manual testing on grunt
Change-Id: I1868896b9eb6f510d8b97022ba950b3604d9d40b
Reviewed-on: https://chromium-review.googlesource.com/1496910
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
diff --git a/src/linux.rs b/src/linux.rs
index 6d09cbf..a8f7ae9 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -19,7 +19,7 @@
use std::thread::JoinHandle;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
-use libc::{self, c_int};
+use libc::{self, c_int, gid_t, uid_t};
use audio_streams::DummyStreamSource;
use byteorder::{ByteOrder, LittleEndian};
@@ -312,11 +312,48 @@
#[cfg(feature = "tpm")]
{
+ use std::ffi::CString;
+ use std::fs;
+ use std::process;
+ use sys_util::chown;
+
if cfg.software_tpm {
- let tpm_box = Box::new(devices::virtio::Tpm::new());
+ let tpm_storage: PathBuf;
+ let mut tpm_jail = simple_jail(&cfg, "tpm_device.policy")?;
+
+ match &mut tpm_jail {
+ Some(jail) => {
+ // Create a tmpfs in the device's root directory for tpm
+ // simulator storage. The size is 20*1024, or 20 KB.
+ jail.mount_with_data(
+ Path::new("none"),
+ Path::new("/"),
+ "tmpfs",
+ (libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC) as usize,
+ "size=20480",
+ )?;
+
+ let crosvm_ids = add_crosvm_user_to_jail(jail, "tpm")?;
+
+ let pid = process::id();
+ let tpm_pid_dir = format!("/run/vm/tpm.{}", pid);
+ tpm_storage = Path::new(&tpm_pid_dir).to_owned();
+ fs::create_dir_all(&tpm_storage)?;
+ let tpm_pid_dir_c = CString::new(tpm_pid_dir).expect("no nul bytes");
+ chown(&tpm_pid_dir_c, crosvm_ids.uid, crosvm_ids.gid)?;
+
+ jail.mount_bind(&tpm_storage, &tpm_storage, true)?;
+ }
+ None => {
+ // Path used inside cros_sdk which does not have /run/vm.
+ tpm_storage = Path::new("/tmp/tpm-simulator").to_owned();
+ }
+ }
+
+ let tpm = devices::virtio::Tpm::new(tpm_storage);
devs.push(VirtioDeviceStub {
- dev: tpm_box,
- jail: simple_jail(&cfg, "tpm_device.policy")?,
+ dev: Box::new(tpm),
+ jail: tpm_jail,
});
}
}
@@ -665,12 +702,17 @@
Ok(pci_devices)
}
+struct Ids {
+ uid: uid_t,
+ gid: gid_t,
+}
+
// Set the uid/gid for the jailed process and give a basic id map. This is
// required for bind mounts to work.
fn add_crosvm_user_to_jail(
jail: &mut Minijail,
feature: &str,
-) -> std::result::Result<(), Box<Error>> {
+) -> std::result::Result<Ids, Box<Error>> {
let crosvm_user_group = CStr::from_bytes_with_nul(b"crosvm\0").unwrap();
let crosvm_uid = match get_user_id(&crosvm_user_group) {
@@ -696,7 +738,10 @@
jail.gidmap(&format!("{0} {0} 1", crosvm_gid))
.map_err(Error::SettingGidMap)?;
- Ok(())
+ Ok(Ids {
+ uid: crosvm_uid,
+ gid: crosvm_gid,
+ })
}
fn raw_fd_from_path(path: &PathBuf) -> std::result::Result<RawFd, Box<Error>> {