summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2023-09-02 09:35:15 +0300
committerLars Wirzenius <liw@liw.fi>2023-09-02 09:35:15 +0300
commit17eb20a3ed9f11e302a7af41dcd02655f51e80ec (patch)
tree6e8a3b81c383a7cb397cd300f4192a457b10213f
parent9b0d3fe877b8f0df38fd9b0f0245148474629540 (diff)
downloadambient-run-17eb20a3ed9f11e302a7af41dcd02655f51e80ec.tar.gz
feat: fail build if it produces an artifact that's too large
Sponsored-by: author
-rw-r--r--ambient-run.md31
-rw-r--r--src/bin/ambient-run.rs3
-rw-r--r--src/project.rs9
-rw-r--r--src/qemu.rs14
4 files changed, 55 insertions, 2 deletions
diff --git a/ambient-run.md b/ambient-run.md
index 7d3ab68..82eccab 100644
--- a/ambient-run.md
+++ b/ambient-run.md
@@ -166,6 +166,7 @@ shell: |
cargo test
image: /my/image.qcow2
artifact: null
+artifact_max_size: null
~~~
### Show per-build configuration
@@ -285,6 +286,36 @@ shell: |
image: image.qcow2
~~~
+### Fail build that tries to produce an oversize artifact
+
+_Requirement:_ If a build produces an artifact that is too large, the
+build should fail.
+
+_Justification:_ Without a limit, a malicious build could fill all
+available storage space, which is a denial-of-service attack.
+
+_Stakeholder:_ Lars.
+
+~~~scenario
+given an installed ambient-run
+given file small-artifact-project.yaml
+given file foo/README.md from foo-project.yaml
+given image file image.qcow2 specified for test suite
+when I run ambient-run build small-artifact-project.yaml --log foo.log
+then file foo.log contains "EXIT CODE: 2"
+~~~
+
+
+~~~{#small-artifact-project.yaml .file .yaml}
+source: foo
+shell: |
+ #!/bin/bash
+ tar -cf /dev/vdc .
+image: image.qcow2
+artifact: foo.tar
+artifact_max_size: 1
+~~~
+
### Build is given dependencies
### Cache is persistent between builds
### Build gets the resources is demands
diff --git a/src/bin/ambient-run.rs b/src/bin/ambient-run.rs
index 3dc778e..37054c2 100644
--- a/src/bin/ambient-run.rs
+++ b/src/bin/ambient-run.rs
@@ -216,7 +216,8 @@ impl BuildCommand {
let mut qemu = Qemu::new(&project.image())
.with_shell(project.shell())
.with_source(&project.source())
- .with_artifact(project.artifact());
+ .with_artifact(project.artifact())
+ .with_artifact_max_size(project.artifact_max_size());
if let Some(log) = &self.log {
qemu = qemu.with_log(log);
}
diff --git a/src/project.rs b/src/project.rs
index b381734..76f42dc 100644
--- a/src/project.rs
+++ b/src/project.rs
@@ -13,6 +13,7 @@ pub struct Project {
shell: String,
image: PathBuf,
artifact: Option<PathBuf>,
+ artifact_max_size: Option<u64>,
}
impl Project {
@@ -45,6 +46,7 @@ impl Project {
shell: "".into(),
image,
artifact: None,
+ artifact_max_size: None,
};
project.add_from(filename)?;
if project.shell.is_empty() {
@@ -71,6 +73,7 @@ impl Project {
self.image = x;
}
self.artifact = snippet.artifact;
+ self.artifact_max_size = snippet.artifact_max_size;
Ok(())
}
@@ -98,6 +101,11 @@ impl Project {
pub fn artifact(&self) -> &Option<PathBuf> {
&self.artifact
}
+
+ /// Artifact file max size.
+ pub fn artifact_max_size(&self) -> Option<u64> {
+ self.artifact_max_size.clone()
+ }
}
#[derive(Debug, Deserialize)]
@@ -107,6 +115,7 @@ struct ProjectSnippet {
shell: Option<String>,
image: Option<PathBuf>,
artifact: Option<PathBuf>,
+ artifact_max_size: Option<u64>,
}
/// Possible errors from configuration file handling.
diff --git a/src/qemu.rs b/src/qemu.rs
index 3450101..4c6efff 100644
--- a/src/qemu.rs
+++ b/src/qemu.rs
@@ -19,6 +19,7 @@ pub struct Qemu {
source: PathBuf,
shell: Option<String>,
artifact: Option<PathBuf>,
+ artifact_max_xize: u64,
}
impl Qemu {
@@ -27,6 +28,7 @@ impl Qemu {
Self {
image: image.into(),
source: PathBuf::from("."),
+ artifact_max_xize: MAX_OUTPUT_SIZE,
..Default::default()
}
}
@@ -55,6 +57,12 @@ impl Qemu {
self
}
+ /// Set maximum length of output artifact.
+ pub fn with_artifact_max_size(mut self, size: Option<u64>) -> Self {
+ self.artifact_max_xize = size.unwrap_or(MAX_OUTPUT_SIZE);
+ self
+ }
+
/// Run QEMU in the specified way.
pub fn run(&self) -> Result<(), QemuError> {
eprintln!("qemu run");
@@ -71,7 +79,11 @@ impl Qemu {
eprintln!("output drive");
let output_drive = if let Some(filename) = &self.artifact {
eprintln!("output to {}", filename.display());
- Self::create_tar_with_size(filename.to_path_buf(), empty.path(), MAX_OUTPUT_SIZE)?
+ Self::create_tar_with_size(
+ filename.to_path_buf(),
+ empty.path(),
+ self.artifact_max_xize,
+ )?
} else {
eprintln!("empty output drive");
Self::create_tar_with_size(tmp.path().join("output"), empty.path(), 0)?