mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 07:01:05 +00:00
PVF worker: switch on seccomp networking restrictions (#2221)
This commit is contained in:
@@ -33,7 +33,7 @@ use polkadot_node_core_pvf_common::{
|
||||
execute::{Handshake, WorkerResponse},
|
||||
worker_dir, SecurityStatus,
|
||||
};
|
||||
use polkadot_parachain_primitives::primitives::ValidationResult;
|
||||
use polkadot_parachain_primitives::primitives::{ValidationCodeHash, ValidationResult};
|
||||
use polkadot_primitives::ExecutorParams;
|
||||
use std::{path::Path, time::Duration};
|
||||
use tokio::{io, net::UnixStream};
|
||||
@@ -156,6 +156,16 @@ pub async fn start_work(
|
||||
let response = futures::select! {
|
||||
response = recv_response(&mut stream).fuse() => {
|
||||
match response {
|
||||
Ok(response) =>
|
||||
handle_response(
|
||||
response,
|
||||
pid,
|
||||
&artifact.id.code_hash,
|
||||
&artifact_path,
|
||||
execution_timeout,
|
||||
audit_log_file
|
||||
)
|
||||
.await,
|
||||
Err(error) => {
|
||||
gum::warn!(
|
||||
target: LOG_TARGET,
|
||||
@@ -164,56 +174,9 @@ pub async fn start_work(
|
||||
?error,
|
||||
"failed to recv an execute response",
|
||||
);
|
||||
// The worker died. Check if it was due to a seccomp violation.
|
||||
//
|
||||
// NOTE: Log, but don't change the outcome. Not all validators may have
|
||||
// auditing enabled, so we don't want attackers to abuse a non-deterministic
|
||||
// outcome.
|
||||
for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
worker_pid = %pid,
|
||||
%syscall,
|
||||
validation_code_hash = ?artifact.id.code_hash,
|
||||
?artifact_path,
|
||||
"A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!"
|
||||
);
|
||||
}
|
||||
|
||||
return Outcome::WorkerIntfErr
|
||||
},
|
||||
Ok(response) => {
|
||||
// Check if any syscall violations occurred during the job. For now this is
|
||||
// only informative, as we are not enforcing the seccomp policy yet.
|
||||
for syscall in security::check_seccomp_violations_for_worker(audit_log_file, pid).await {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
worker_pid = %pid,
|
||||
%syscall,
|
||||
validation_code_hash = ?artifact.id.code_hash,
|
||||
?artifact_path,
|
||||
"A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!"
|
||||
);
|
||||
}
|
||||
|
||||
if let WorkerResponse::Ok{duration, ..} = response {
|
||||
if duration > execution_timeout {
|
||||
// The job didn't complete within the timeout.
|
||||
gum::warn!(
|
||||
target: LOG_TARGET,
|
||||
worker_pid = %pid,
|
||||
"execute job took {}ms cpu time, exceeded execution timeout {}ms.",
|
||||
duration.as_millis(),
|
||||
execution_timeout.as_millis(),
|
||||
);
|
||||
|
||||
// Return a timeout error.
|
||||
return Outcome::HardTimeout
|
||||
}
|
||||
}
|
||||
|
||||
response
|
||||
},
|
||||
}
|
||||
},
|
||||
_ = Delay::new(timeout).fuse() => {
|
||||
@@ -238,7 +201,7 @@ pub async fn start_work(
|
||||
idle_worker: IdleWorker { stream, pid, worker_dir },
|
||||
},
|
||||
WorkerResponse::JobTimedOut => Outcome::HardTimeout,
|
||||
WorkerResponse::JobDied(err) => Outcome::JobDied { err },
|
||||
WorkerResponse::JobDied { err, job_pid: _ } => Outcome::JobDied { err },
|
||||
WorkerResponse::JobError(err) => Outcome::JobError { err },
|
||||
|
||||
WorkerResponse::InternalError(err) => Outcome::InternalError { err },
|
||||
@@ -247,6 +210,56 @@ pub async fn start_work(
|
||||
.await
|
||||
}
|
||||
|
||||
/// Handles the case where we successfully received response bytes on the host from the child.
|
||||
///
|
||||
/// Here we know the artifact exists, but is still located in a temporary file which will be cleared
|
||||
/// by [`with_worker_dir_setup`].
|
||||
async fn handle_response(
|
||||
response: WorkerResponse,
|
||||
worker_pid: u32,
|
||||
validation_code_hash: &ValidationCodeHash,
|
||||
artifact_path: &Path,
|
||||
execution_timeout: Duration,
|
||||
audit_log_file: Option<security::AuditLogFile>,
|
||||
) -> WorkerResponse {
|
||||
if let WorkerResponse::Ok { duration, .. } = response {
|
||||
if duration > execution_timeout {
|
||||
// The job didn't complete within the timeout.
|
||||
gum::warn!(
|
||||
target: LOG_TARGET,
|
||||
worker_pid,
|
||||
"execute job took {}ms cpu time, exceeded execution timeout {}ms.",
|
||||
duration.as_millis(),
|
||||
execution_timeout.as_millis(),
|
||||
);
|
||||
|
||||
// Return a timeout error.
|
||||
return WorkerResponse::JobTimedOut
|
||||
}
|
||||
}
|
||||
|
||||
if let WorkerResponse::JobDied { err: _, job_pid } = response {
|
||||
// The job died. Check if it was due to a seccomp violation.
|
||||
//
|
||||
// NOTE: Log, but don't change the outcome. Not all validators may have
|
||||
// auditing enabled, so we don't want attackers to abuse a non-deterministic
|
||||
// outcome.
|
||||
for syscall in security::check_seccomp_violations_for_job(audit_log_file, job_pid).await {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
%worker_pid,
|
||||
%job_pid,
|
||||
%syscall,
|
||||
?validation_code_hash,
|
||||
?artifact_path,
|
||||
"A forbidden syscall was attempted! This is a violation of our seccomp security policy. Report an issue ASAP!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
|
||||
/// Create a temporary file for an artifact in the worker cache, execute the given future/closure
|
||||
/// passing the file path in, and clean up the worker cache.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user