-
Notifications
You must be signed in to change notification settings - Fork 699
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 worker: switch on seccomp networking restrictions #2221
Merged
mrcnski
merged 10 commits into
master
from
mrcnski/pvf-switch-on-networking-restrictions
Nov 21, 2023
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
1e068ed
PVF worker: switch on seccomp networking restrictions
mrcnski dddb8b8
Add back section in impl guide
mrcnski 2efc58d
Add retry case to impl guide
mrcnski 3687709
Merge branch 'master' into mrcnski/pvf-switch-on-networking-restrictions
mrcnski 7ffc8c4
Update doc
mrcnski 5cd5408
Add missing code
mrcnski 8bd4f58
Was checking seccomp logs when the worker died, not job process
mrcnski 8caea92
Silence some unnecessary output
mrcnski 3b1de08
Minor fixes
mrcnski 639557d
Fix syscall detection running for worker and not job
mrcnski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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!( | ||
Comment on lines
-186
to
-189
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We still do this check elsewhere in this file, but only if the worker died. |
||
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. | ||
/// | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was producing a bit too much noise in the log output.