Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PVF host: Make unavailable security features print a warning #2244

Merged
merged 5 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions polkadot/node/core/pvf/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ pub async fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Fu
// Run checks for supported security features once per host startup. Warn here if not enabled.
let security_status = {
// TODO: add check that syslog is available and that seccomp violations are logged?
security::check_secure_mode_platform_requirement();
let (can_enable_landlock, can_enable_seccomp, can_unshare_user_namespace_and_change_root) = join!(
security::check_landlock(&config.prepare_worker_program_path),
security::check_seccomp(&config.prepare_worker_program_path),
Expand Down
133 changes: 82 additions & 51 deletions polkadot/node/core/pvf/src/security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,40 @@ use tokio::{
io::{AsyncReadExt, AsyncSeekExt, SeekFrom},
};

const SECURE_MODE_ANNOUNCEMENT: &'static str =
"In the next release this will be a hard error by default. More information: \
https://github.com/w3f/polkadot-wiki/issues/4881";

/// Warns if a secure validator cannot be built for the target OS and architecture.
pub fn check_secure_mode_platform_requirement() {
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
return ()
} else {
let msg = "Secure validators are only supported on CPUs from the x86_64 family (usually Intel or AMD).";
}
}
} else {
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
let msg = "Secure validators are only supported on Linux.";
} else {
let msg = "Secure validators are only supported on Linux and on CPUs from the x86_64 family (usually Intel or AMD).";
}
}
}
};

gum::warn!(
target: LOG_TARGET,
"{} {}",
msg,
SECURE_MODE_ANNOUNCEMENT
);
}

/// Check if we can sandbox the root and emit a warning if not.
///
/// We do this check by spawning a new process and trying to sandbox it. To get as close as possible
Expand All @@ -32,25 +66,20 @@ pub async fn check_can_unshare_user_namespace_and_change_root(
) -> bool {
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
match tokio::process::Command::new(prepare_worker_program_path)
let msg = match tokio::process::Command::new(prepare_worker_program_path)
.arg("--check-can-unshare-user-namespace-and-change-root")
.output()
.await
{
Ok(output) if output.status.success() => true,
Ok(output) if output.status.success() => return true,
Ok(output) => {
let stderr = std::str::from_utf8(&output.stderr)
.expect("child process writes a UTF-8 string to stderr; qed")
.trim();
gum::warn!(
target: LOG_TARGET,
?prepare_worker_program_path,
// Docs say to always print status using `Display` implementation.
status = %output.status,
%stderr,
"Cannot unshare user namespace and change root, which are Linux-specific kernel security features. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running with support for unsharing user namespaces for maximum security."
);
false
format!(
"Cannot unshare user namespace and change root, which are Linux-specific kernel security features. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running with support for unsharing user namespaces for maximum security. Error: {}",
stderr
)
},
Err(err) => {
gum::warn!(
Expand All @@ -59,17 +88,21 @@ pub async fn check_can_unshare_user_namespace_and_change_root(
"Could not start child process: {}",
err
);
false
return false
},
}
};
} else {
gum::warn!(
target: LOG_TARGET,
"Cannot unshare user namespace and change root, which are Linux-specific kernel security features. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with support for unsharing user namespaces for maximum security."
);
false
let msg = "Cannot unshare user namespace and change root, which are Linux-specific kernel security features. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with support for unsharing user namespaces for maximum security.";
}
}

gum::warn!(
target: LOG_TARGET,
"{} {}",
msg,
SECURE_MODE_ANNOUNCEMENT
);
false
}

/// Check if landlock is supported and emit a warning if not.
Expand All @@ -83,23 +116,19 @@ pub async fn check_landlock(
) -> bool {
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
match tokio::process::Command::new(prepare_worker_program_path)
let msg = match tokio::process::Command::new(prepare_worker_program_path)
.arg("--check-can-enable-landlock")
.status()
.await
{
Ok(status) if status.success() => true,
Ok(status) if status.success() => return true,
Ok(status) => {
let abi =
polkadot_node_core_pvf_common::worker::security::landlock::LANDLOCK_ABI as u8;
gum::warn!(
target: LOG_TARGET,
?prepare_worker_program_path,
?status,
%abi,
"Cannot fully enable landlock, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider upgrading the kernel version for maximum security."
);
false
format!(
"Cannot fully enable landlock, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider upgrading the kernel version for maximum security. Landlock ABI: {}",
abi
)
},
Err(err) => {
gum::warn!(
Expand All @@ -108,17 +137,21 @@ pub async fn check_landlock(
"Could not start child process: {}",
err
);
false
return false
},
}
};
} else {
gum::warn!(
target: LOG_TARGET,
"Cannot enable landlock, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with landlock support for maximum security."
);
false
let msg = "Cannot enable landlock, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with landlock support for maximum security.";
}
}

gum::warn!(
target: LOG_TARGET,
"{} {}",
msg,
SECURE_MODE_ANNOUNCEMENT
);
false
}

/// Check if seccomp is supported and emit a warning if not.
Expand All @@ -132,20 +165,14 @@ pub async fn check_seccomp(
) -> bool {
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
match tokio::process::Command::new(prepare_worker_program_path)
let msg = match tokio::process::Command::new(prepare_worker_program_path)
.arg("--check-can-enable-seccomp")
.status()
.await
{
Ok(status) if status.success() => true,
Ok(status) if status.success() => return true,
Ok(status) => {
gum::warn!(
target: LOG_TARGET,
?prepare_worker_program_path,
?status,
"Cannot fully enable seccomp, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider upgrading the kernel version for maximum security."
);
false
"Cannot fully enable seccomp, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider upgrading the kernel version for maximum security."
},
Err(err) => {
gum::warn!(
Expand All @@ -154,17 +181,21 @@ pub async fn check_seccomp(
"Could not start child process: {}",
err
);
false
return false
},
}
};
} else {
gum::warn!(
target: LOG_TARGET,
"Cannot enable seccomp, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with seccomp support for maximum security."
);
false
let msg = "Cannot enable seccomp, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with seccomp support for maximum security.";
}
}

gum::warn!(
target: LOG_TARGET,
"{} {}",
msg,
SECURE_MODE_ANNOUNCEMENT
);
false
}

const AUDIT_LOG_PATH: &'static str = "/var/log/audit/audit.log";
Expand Down
Loading