diff --git a/.vscode/settings.json b/.vscode/settings.json index 8e3a001..ffbea06 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,8 @@ "xtask", "actions", "rsjudge-rest", - "rsjudge-judger" + "rsjudge-judger", + "rsjudge-runner" ], "editor.defaultFormatter": "dprint.dprint", "[dockerfile]": { diff --git a/Cargo.lock b/Cargo.lock index 03c6d28..0d142a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1087,6 +1087,7 @@ name = "rsjudge-runner" version = "0.1.0" dependencies = [ "anyhow", + "caps", "nix", "once_cell", "uzers", diff --git a/crates/rsjudge-runner/Cargo.toml b/crates/rsjudge-runner/Cargo.toml index 6227961..4423698 100644 --- a/crates/rsjudge-runner/Cargo.toml +++ b/crates/rsjudge-runner/Cargo.toml @@ -9,6 +9,7 @@ description = "Command runner for rsjudge" [dependencies] anyhow = "1.0.79" +caps = "0.5.5" nix = { version = "0.28.0", features = ["user"] } once_cell = "1.19.0" uzers = "0.11.3" diff --git a/crates/rsjudge-runner/examples/exploit.rs b/crates/rsjudge-runner/examples/exploit.rs new file mode 100644 index 0000000..88c6102 --- /dev/null +++ b/crates/rsjudge-runner/examples/exploit.rs @@ -0,0 +1,31 @@ +use std::{path::PathBuf, process::Command}; + +use caps::{read, CapSet}; +use rsjudge_runner::{user::builder, RunAs}; + +fn main() -> anyhow::Result<()> { + dbg!(read(None, CapSet::Ambient).unwrap()); + dbg!(read(None, CapSet::Effective).unwrap()); + dbg!(read(None, CapSet::Inheritable).unwrap()); + dbg!(read(None, CapSet::Permitted).unwrap()); + let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .parent() + .and_then(|p| p.parent()) + .ok_or_else(|| anyhow::anyhow!("cannot find crate root"))? + .join("target/debug/examples"); + + let exploit_inner = examples.join("exploit-inner"); + + let status = Command::new(exploit_inner).run_as(builder()?).output()?; + assert!(status.status.success()); + println!("{}", String::from_utf8_lossy(&status.stdout)); + println!("{}", String::from_utf8_lossy(&status.stderr)); + + let normal = examples.join("normal"); + let status = Command::new(normal).run_as(builder()?).output()?; + assert!(status.status.success()); + println!("{}", String::from_utf8_lossy(&status.stdout)); + println!("{}", String::from_utf8_lossy(&status.stderr)); + + Ok(()) +} diff --git a/crates/rsjudge-runner/examples/exploit_inner.rs b/crates/rsjudge-runner/examples/exploit_inner.rs new file mode 100644 index 0000000..a1022ba --- /dev/null +++ b/crates/rsjudge-runner/examples/exploit_inner.rs @@ -0,0 +1,14 @@ +use caps::{read, CapSet}; +use nix::unistd::{setuid, Uid}; + +fn main() { + dbg!(read(None, CapSet::Ambient).unwrap()); + dbg!(read(None, CapSet::Effective).unwrap()); + dbg!(read(None, CapSet::Inheritable).unwrap()); + dbg!(read(None, CapSet::Permitted).unwrap()); + eprintln!("Starting setuid syscall."); + let result = setuid(Uid::from_raw(0)).expect_err("Should fail to set UID"); + dbg!(result.desc()); + dbg!(read(None, CapSet::Permitted).unwrap()); + eprintln!("Failed calling setuid, test pass."); +} diff --git a/crates/rsjudge-runner/examples/normal.rs b/crates/rsjudge-runner/examples/normal.rs new file mode 100644 index 0000000..216769e --- /dev/null +++ b/crates/rsjudge-runner/examples/normal.rs @@ -0,0 +1,9 @@ +use caps::{read, CapSet}; + +fn main() { + dbg!(read(None, CapSet::Ambient).unwrap()); + dbg!(read(None, CapSet::Effective).unwrap()); + dbg!(read(None, CapSet::Inheritable).unwrap()); + dbg!(read(None, CapSet::Permitted).unwrap()); + println!("Hello, world!"); +}