Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 89 additions & 1 deletion crates/nibrunnerd/src/adapters/vm/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ pub struct VmManager {

impl VmManager {
pub fn working_dir_for(&self, app_id: &AppId) -> PathBuf {
self.vm_dir.join(app_id.as_str())
self.processes
.read_record(app_id)
.and_then(|record| record.jail_root)
.unwrap_or_else(|| self.vm_dir.join(app_id.as_str()))
}

fn api(&self, app_id: &AppId) -> FirecrackerApi {
Expand Down Expand Up @@ -386,6 +389,21 @@ impl Vmm for VmManager {
self.logs.detach(app_id).await;
return Err(VmError::Host(error.to_string()));
}
if self
.processes
.read_record(app_id)
.is_some_and(|record| record.jail_root.is_some())
{
use std::os::unix::fs::MetadataExt;
let owner = std::fs::metadata(&working_dir).map_err(|error| VmError::Host(error.to_string()))?;
for socket in [
tenant_log_socket_path(&working_dir),
cron_registration_socket_path(&working_dir),
] {
crate::unix_socket::own(&socket, owner.uid(), owner.gid())
.map_err(|error| VmError::Host(error.to_string()))?;
}
}
Ok(())
}

Expand Down Expand Up @@ -776,6 +794,76 @@ mod tests {
);
}

#[tokio::test]
async fn a_running_legacy_vmm_keeps_its_existing_channels_until_it_is_redeployed() {
let fixture = fixture();
fixture.state.put_record(instance_record(|_| {})).await;
fixture
.manager
.processes
.write_record(&crate::adapters::vm::process::VmRecord {
app_id: app_id(),
pid: std::process::id() as i32,
host_boot_id: fixture.manager.processes.boot_id().into(),
started_at_ms: 0,
exit_code: None,
signal: None,
stop_requested: false,
jail_root: None,
jail_uid: None,
})
.unwrap();
let legacy_directory = fixture.manager.vm_dir.join(app_id().as_str());
assert_eq!(fixture.manager.working_dir_for(&app_id()), legacy_directory);
fixture.manager.readopt(&app_id()).await.unwrap();
assert!(
tokio::net::UnixStream::connect(tenant_log_socket_path(&legacy_directory))
.await
.is_ok()
);
assert!(
tokio::net::UnixStream::connect(cron_registration_socket_path(&legacy_directory))
.await
.is_ok()
);
}

#[tokio::test]
async fn a_recorded_jail_is_readopted_using_its_existing_identity() {
use std::os::unix::fs::MetadataExt;
let fixture = fixture();
let short_directory = tempfile::tempdir_in("/tmp").unwrap();
let root = short_directory.path().join("root");
make_directory(&root, VM_DIR_MODE).unwrap();
let identity = std::fs::metadata(&root).unwrap();
fixture.state.put_record(instance_record(|_| {})).await;
fixture
.manager
.processes
.write_record(&crate::adapters::vm::process::VmRecord {
app_id: app_id(),
pid: std::process::id() as i32,
host_boot_id: fixture.manager.processes.boot_id().into(),
started_at_ms: 0,
exit_code: None,
signal: None,
stop_requested: false,
jail_root: Some(root.clone()),
jail_uid: None,
})
.unwrap();
fixture.manager.readopt(&app_id()).await.unwrap();
assert_eq!(fixture.manager.working_dir_for(&app_id()), root);
for socket in [
tenant_log_socket_path(&root),
cron_registration_socket_path(&root),
] {
let owner = std::fs::metadata(&socket).unwrap();
assert_eq!((owner.uid(), owner.gid()), (identity.uid(), identity.gid()));
assert!(tokio::net::UnixStream::connect(socket).await.is_ok());
}
}

#[tokio::test]
async fn readopting_a_microvm_this_host_holds_no_record_of_is_a_no_op() {
let fixture = fixture();
Expand Down
18 changes: 18 additions & 0 deletions crates/nibrunnerd/src/adapters/vm/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ pub struct VmRecord {
pub signal: Option<i32>,
#[serde(default)]
pub stop_requested: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub jail_root: Option<PathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub jail_uid: Option<u32>,
}

impl VmRecord {
Expand Down Expand Up @@ -237,6 +241,8 @@ impl VmProcesses {
exit_code: None,
signal: None,
stop_requested: false,
jail_root: None,
jail_uid: None,
};
self.write_record(&record)?;

Expand Down Expand Up @@ -335,6 +341,8 @@ mod tests {
exit_code: None,
signal: None,
stop_requested: false,
jail_root: None,
jail_uid: None,
})
.unwrap();
let status = processes.status(&app_id());
Expand All @@ -357,6 +365,8 @@ mod tests {
exit_code: None,
signal: None,
stop_requested: false,
jail_root: None,
jail_uid: None,
})
.unwrap();
let status = processes.status(&app_id());
Expand All @@ -377,6 +387,8 @@ mod tests {
exit_code: Some(1),
signal: None,
stop_requested: false,
jail_root: None,
jail_uid: None,
};
processes.write_record(&record).unwrap();
let crashed = processes.status(&app_id());
Expand All @@ -386,6 +398,8 @@ mod tests {
processes
.write_record(&VmRecord {
stop_requested: true,
jail_root: None,
jail_uid: None,
..record.clone()
})
.unwrap();
Expand Down Expand Up @@ -461,6 +475,8 @@ mod tests {
exit_code: Some(0),
signal: None,
stop_requested: true,
jail_root: None,
jail_uid: None,
})
.unwrap();
std::fs::write(processes.console_path(&app_id()), b"[nibrun] gone\n").unwrap();
Expand Down Expand Up @@ -640,6 +656,8 @@ mod tests {
exit_code: None,
signal: None,
stop_requested: false,
jail_root: None,
jail_uid: None,
})
.unwrap();
processes.stop(&app_id()).await;
Expand Down
13 changes: 13 additions & 0 deletions crates/nibrunnerd/src/unix_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ pub(crate) fn bind(path: &Path) -> std::io::Result<UnixListener> {
Ok(listener)
}

#[allow(
unsafe_code,
reason = "a VMM may replace a socket with a symlink; ownership must never follow it"
)]
pub(crate) fn own(path: &Path, uid: u32, gid: u32) -> std::io::Result<()> {
use std::os::unix::ffi::OsStrExt;
let name = std::ffi::CString::new(path.as_os_str().as_bytes()).map_err(std::io::Error::other)?;
if unsafe { libc::lchown(name.as_ptr(), uid, gid) } < 0 {
return Err(std::io::Error::last_os_error());
}
Ok(())
}

pub(crate) async fn connect(path: &Path) -> std::io::Result<UnixStream> {
use std::os::unix::fs::MetadataExt;

Expand Down
Loading