forked from wrenn/wrenn
feat: rewrite envd guest agent in Rust (envd-rs)
Complete Rust rewrite of the Go envd guest daemon that runs as PID 1 inside Firecracker microVMs. Feature-complete across all 8 phases: - Health, metrics, and env var endpoints - Crypto (SHA-256/512, HMAC), auth (secure token, signing), init/snapshot - Connect RPC via connectrpc + buffa (process + filesystem services) - File transfer (GET/POST /files) with gzip, multipart, chown, ENOSPC - Port subsystem (/proc/net/tcp scanner, socat forwarder) - Cgroup2 manager with noop fallback - Snapshot/restore lifecycle (conntracker, port subsystem stop/restart) - SIGTERM graceful shutdown, --cmd initial process spawn - MMDS metadata polling for Firecracker mode 42 source files, ~4200 LOC, 4.1MB stripped release binary. Makefile updated: build-envd now targets Rust (musl static), build-envd-go preserved for Go builds.
This commit is contained in:
2
envd-rs/src/permissions/mod.rs
Normal file
2
envd-rs/src/permissions/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod user;
|
||||
pub mod path;
|
||||
72
envd-rs/src/permissions/path.rs
Normal file
72
envd-rs/src/permissions/path.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use std::fs;
|
||||
use std::os::unix::fs::chown;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use nix::unistd::{Gid, Uid};
|
||||
|
||||
fn expand_tilde(path: &str, home_dir: &str) -> Result<String, String> {
|
||||
if path.is_empty() || !path.starts_with('~') {
|
||||
return Ok(path.to_string());
|
||||
}
|
||||
if path.len() > 1 && path.as_bytes()[1] != b'/' && path.as_bytes()[1] != b'\\' {
|
||||
return Err("cannot expand user-specific home dir".into());
|
||||
}
|
||||
Ok(format!("{}{}", home_dir, &path[1..]))
|
||||
}
|
||||
|
||||
pub fn expand_and_resolve(
|
||||
path: &str,
|
||||
home_dir: &str,
|
||||
default_path: Option<&str>,
|
||||
) -> Result<String, String> {
|
||||
let path = if path.is_empty() {
|
||||
default_path.unwrap_or("").to_string()
|
||||
} else {
|
||||
path.to_string()
|
||||
};
|
||||
|
||||
let path = expand_tilde(&path, home_dir)?;
|
||||
|
||||
if Path::new(&path).is_absolute() {
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
let joined = PathBuf::from(home_dir).join(&path);
|
||||
joined
|
||||
.canonicalize()
|
||||
.or_else(|_| Ok(joined))
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
}
|
||||
|
||||
pub fn ensure_dirs(path: &str, uid: Uid, gid: Gid) -> Result<(), String> {
|
||||
let path = Path::new(path);
|
||||
let mut current = PathBuf::new();
|
||||
|
||||
for component in path.components() {
|
||||
current.push(component);
|
||||
let current_str = current.to_string_lossy();
|
||||
|
||||
if current_str == "/" {
|
||||
continue;
|
||||
}
|
||||
|
||||
match fs::metadata(¤t) {
|
||||
Ok(meta) => {
|
||||
if !meta.is_dir() {
|
||||
return Err(format!("path is a file: {current_str}"));
|
||||
}
|
||||
}
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
fs::create_dir(¤t)
|
||||
.map_err(|e| format!("failed to create directory {current_str}: {e}"))?;
|
||||
chown(¤t, Some(uid.as_raw()), Some(gid.as_raw()))
|
||||
.map_err(|e| format!("failed to chown directory {current_str}: {e}"))?;
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format!("failed to stat directory {current_str}: {e}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
32
envd-rs/src/permissions/user.rs
Normal file
32
envd-rs/src/permissions/user.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use nix::unistd::{Gid, Group, Uid, User};
|
||||
|
||||
pub fn lookup_user(username: &str) -> Result<User, String> {
|
||||
User::from_name(username)
|
||||
.map_err(|e| format!("error looking up user '{username}': {e}"))?
|
||||
.ok_or_else(|| format!("user '{username}' not found"))
|
||||
}
|
||||
|
||||
pub fn get_uid_gid(user: &User) -> (Uid, Gid) {
|
||||
(user.uid, user.gid)
|
||||
}
|
||||
|
||||
pub fn get_user_groups(user: &User) -> Vec<Gid> {
|
||||
let c_name = std::ffi::CString::new(user.name.as_str()).unwrap();
|
||||
nix::unistd::getgrouplist(&c_name, user.gid).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn lookup_username_by_uid(uid: Uid) -> String {
|
||||
User::from_uid(uid)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|u| u.name)
|
||||
.unwrap_or_else(|| uid.to_string())
|
||||
}
|
||||
|
||||
pub fn lookup_groupname_by_gid(gid: Gid) -> String {
|
||||
Group::from_gid(gid)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|g| g.name)
|
||||
.unwrap_or_else(|| gid.to_string())
|
||||
}
|
||||
Reference in New Issue
Block a user