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: Add Secure Validator Mode #2486

Merged
merged 28 commits into from
Dec 5, 2023
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4cb5913
PVF: Add Secure Validator Mode
mrcnski Nov 21, 2023
c3d512c
Merge branch 'master' into mrcnski/pvf-add-secure-validator-mode
mrcnski Nov 21, 2023
f44ca5f
Minor fix
mrcnski Nov 21, 2023
bd80771
Properly handle missing security features worker-side; big refactor
mrcnski Nov 22, 2023
69c117f
Merge branch 'master' into mrcnski/pvf-add-secure-validator-mode
mrcnski Nov 23, 2023
cb91ed1
Make only one FS security feature required
mrcnski Nov 24, 2023
61b80d8
Refactor secure mode code a bit
mrcnski Nov 24, 2023
ba03492
Fix check_seccomp and check_landlock errs not being logged to stderr
mrcnski Nov 24, 2023
0ce35ab
Merge branch 'master' into mrcnski/pvf-add-secure-validator-mode
mrcnski Nov 24, 2023
ec9bd4b
Fix unshare error (cannot run in multithreaded context)
mrcnski Nov 24, 2023
090d2d9
Update some comments
mrcnski Nov 24, 2023
dc7961d
Some fixes
mrcnski Nov 24, 2023
8a72556
Fix bench
mrcnski Nov 24, 2023
a4d173c
Merge branch 'master' into mrcnski/pvf-add-secure-validator-mode
mrcnski Nov 26, 2023
6520dd8
fix CI
mrcnski Nov 26, 2023
f5f11bd
Remove old TODO
mrcnski Nov 27, 2023
3aa8bd4
Merge remote-tracking branch 'origin/mrcnski/pvf-add-secure-validator…
mrcnski Nov 28, 2023
da7127c
Address some review comments
mrcnski Nov 29, 2023
13f5e92
Merge branch 'master' into mrcnski/pvf-add-secure-validator-mode
mrcnski Nov 29, 2023
26ca19c
Update doc
mrcnski Nov 29, 2023
fccc36a
Merge branch 'master' into mrcnski/pvf-add-secure-validator-mode
mrcnski Dec 1, 2023
0ffa527
Fix rustdoc warning
mrcnski Dec 1, 2023
8fa147f
bump zombienet version
pepoviola Dec 1, 2023
f1b3539
Baby's first prdoc
mrcnski Dec 1, 2023
5509b31
Zombienet, add script to update cmd and fix upgrade-node test
pepoviola Dec 4, 2023
2209855
bump zombienet version
pepoviola Dec 4, 2023
0469f56
Merge branch 'master' into mrcnski/pvf-add-secure-validator-mode
mrcnski Dec 5, 2023
27b45a0
Fix prdoc 😢
mrcnski Dec 5, 2023
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
107 changes: 68 additions & 39 deletions polkadot/node/core/pvf/src/security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,22 @@ use tokio::{
/// configuration.
pub async fn check_security_status(config: &Config) -> Result<SecurityStatus, String> {
let Config { prepare_worker_program_path, secure_validator_mode, cache_path, .. } = config;
// TODO: add check that syslog is available and that seccomp violations are logged?

let (landlock, seccomp, change_root) = join!(
check_landlock(prepare_worker_program_path),
check_seccomp(prepare_worker_program_path),
check_can_unshare_user_namespace_and_change_root(prepare_worker_program_path, cache_path)
);

let security_status = SecurityStatus {
secure_validator_mode: *secure_validator_mode,
can_enable_landlock: landlock.is_ok(),
can_enable_seccomp: seccomp.is_ok(),
can_unshare_user_namespace_and_change_root: change_root.is_ok(),
};
let full_security_status =
FullSecurityStatus::new(*secure_validator_mode, landlock, seccomp, change_root);
let security_status = full_security_status.as_partial();

let errs: Vec<SecureModeError> = [landlock, seccomp, change_root]
.into_iter()
.filter_map(|result| result.err())
.collect();
let err_occurred = print_secure_mode_message(&security_status, errs);
if err_occurred {
return Err("could not enable Secure Validator Mode; check logs".into())
if full_security_status.err_occurred() {
print_secure_mode_error_or_warning(&full_security_status);
if !full_security_status.all_errs_allowed() {
return Err("could not enable Secure Validator Mode; check logs".into())
}
}

if security_status.secure_validator_mode {
Expand All @@ -70,6 +65,60 @@ pub async fn check_security_status(config: &Config) -> Result<SecurityStatus, St
Ok(security_status)
}

/// Contains the full security status including error states.
struct FullSecurityStatus {
partial: SecurityStatus,
alindima marked this conversation as resolved.
Show resolved Hide resolved
errs: Vec<SecureModeError>,
}

impl FullSecurityStatus {
fn new(
secure_validator_mode: bool,
landlock: SecureModeResult,
seccomp: SecureModeResult,
change_root: SecureModeResult,
) -> Self {
Self {
partial: SecurityStatus {
secure_validator_mode,
can_enable_landlock: landlock.is_ok(),
can_enable_seccomp: seccomp.is_ok(),
can_unshare_user_namespace_and_change_root: change_root.is_ok(),
},
errs: [landlock, seccomp, change_root]
.into_iter()
.filter_map(|result| result.err())
.collect(),
}
}

fn as_partial(&self) -> SecurityStatus {
self.partial.clone()
}

fn err_occurred(&self) -> bool {
!self.errs.is_empty()
}

fn all_errs_allowed(&self) -> bool {
!self.partial.secure_validator_mode ||
self.errs.iter().all(|err| err.is_allowed_in_secure_mode(&self.partial))
}

fn errs_string(&self) -> String {
self.errs
.iter()
.map(|err| {
format!(
"\n - {}{}",
if err.is_allowed_in_secure_mode(&self.partial) { "Optional: " } else { "" },
err
)
})
.collect()
}
}

type SecureModeResult = std::result::Result<(), SecureModeError>;

/// Errors related to enabling Secure Validator Mode.
Expand Down Expand Up @@ -108,12 +157,8 @@ impl fmt::Display for SecureModeError {
}
}

/// Errors if Secure Validator Mode and some mandatory errors occurred, warn otherwise.
///
/// # Returns
///
/// `true` if an error was printed, `false` otherwise.
fn print_secure_mode_message(security_status: &SecurityStatus, errs: Vec<SecureModeError>) -> bool {
/// Print an error if Secure Validator Mode and some mandatory errors occurred, warn otherwise.
fn print_secure_mode_error_or_warning(security_status: &FullSecurityStatus) {
// Trying to run securely and some mandatory errors occurred.
const SECURE_MODE_ERROR: &'static str = "🚨 Your system cannot securely run a validator. \
\nRunning validation of malicious PVF code has a higher risk of compromising this machine.";
Expand All @@ -127,31 +172,16 @@ fn print_secure_mode_message(security_status: &SecurityStatus, errs: Vec<SecureM
command line argument if you understand and accept the risks of running insecurely. \
\nMore information: https://wiki.polkadot.network/docs/maintain-guides-secure-validator#secure-validator-mode";

if errs.is_empty() {
return false
}
let all_errs_allowed = security_status.all_errs_allowed();
let errs_string = security_status.errs_string();

let errs_allowed = !security_status.secure_validator_mode ||
errs.iter().all(|err| err.is_allowed_in_secure_mode(security_status));
let errs_string: String = errs
.iter()
.map(|err| {
format!(
"\n - {}{}",
if err.is_allowed_in_secure_mode(security_status) { "Optional: " } else { "" },
err
)
})
.collect();

if errs_allowed {
if all_errs_allowed {
gum::warn!(
target: LOG_TARGET,
"{}{}",
SECURE_MODE_WARNING,
errs_string,
);
false
} else {
gum::error!(
target: LOG_TARGET,
Expand All @@ -160,7 +190,6 @@ fn print_secure_mode_message(security_status: &SecurityStatus, errs: Vec<SecureM
errs_string,
IGNORE_SECURE_MODE_TIP
);
true
}
}

Expand Down