Skip to content

Commit

Permalink
Option to allow loopback network.
Browse files Browse the repository at this point in the history
  • Loading branch information
igankevich committed Apr 28, 2024
1 parent 8a18802 commit 842b8b0
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cijail"
version = "0.3.0"
version = "0.4.0"
edition = "2021"
publish = false

Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@ $ env CIJAIL_ENDPOINTS='one.one.one.one:53' \
[Sun Apr 04 17:28:22 2024] cijail: deny sendmmsg staex.io
```

Use `CIJAIL_DRY_RUN=1` to discover what is blocked by the current rules.
Specifying `CIJAIL_DRY_RUN=0` is not mandatory.
Dry run always fails.
- Use `CIJAIL_ENDPOINTS` to restrict which endpoints are allowed to be sent traffic to.
These can be DNS names (i.e. allow only name resolution, but not the traffic),
DNS names plus port, IP address plus port.
- Use `CIJAIL_DRY_RUN=1` to discover what is blocked by the current rules.
Specifying `CIJAIL_DRY_RUN=0` is not mandatory.
Dry run always fails.
- Use `CIJAIL_ALLOW_LOOPBACK=1` to allow sending any traffic to any address and port
in the loopback network
(`127.0.0.1/8` and `::1`).

## Use in Github Actions

Expand Down Expand Up @@ -101,3 +107,7 @@ To do that add the following lines to `/etc/gitlab-runner/config.toml`.
# Caveats

- You can not run `cijail` inside another `cijail`. We are investigating the issue.
- Cijail **must be** the first process that you run in the Docker container
because it controls only its descendants.
Usually this is not a problem in CI/CD,
but on the local computer something like [NSCD](https://man7.org/linux/man-pages/man8/nscd.8.html) can easily circumvent the jail.
31 changes: 24 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub(crate) use self::logger::*;

pub(crate) const CIJAIL_ENDPOINTS: &str = "CIJAIL_ENDPOINTS";
const CIJAIL_DRY_RUN: &str = "CIJAIL_DRY_RUN";
const CIJAIL_ALLOW_LOOPBACK: &str = "CIJAIL_ALLOW_LOOPBACK";
const CIJAIL_TRACER: &str = "CIJAIL_TRACER";

fn install_seccomp_notify_filter() -> Result<ScmpFd, Error> {
Expand Down Expand Up @@ -101,6 +102,7 @@ fn spawn_tracer_process(
socket: SocketpairStream,
allowed_endpoints: EndpointSet,
is_dry_run: bool,
allow_loopback: bool,
) -> Result<Child, Box<dyn std::error::Error>> {
let arg0 = std::env::args_os()
.next()
Expand All @@ -109,6 +111,7 @@ fn spawn_tracer_process(
child.env(CIJAIL_TRACER, "1");
child.env(CIJAIL_ENDPOINTS, allowed_endpoints.to_string());
child.env(CIJAIL_DRY_RUN, bool_to_str(is_dry_run));
child.env(CIJAIL_ALLOW_LOOPBACK, bool_to_str(allow_loopback));
unsafe {
let socket = socket.as_raw_fd();
child.pre_exec(move || {
Expand Down Expand Up @@ -136,9 +139,13 @@ struct Args {
/// Print version.
#[clap(long, action)]
version: bool,
/// Do not enforce restrictions, but print all decisions.
/// Do not enforce restrictions, but print all decisions (overrides CIJAIL_DRY_RUN environment variable).
#[clap(long, action)]
dry_run: bool,
/// Allow to connect to any address and port in the loopback network (overrides
/// CIJAIL_ALLOW_LOOPBACK environment variable).
#[clap(long, action)]
allow_loopback: bool,
/// Command to run.
#[arg(allow_hyphen_values = true)]
command: Vec<OsString>,
Expand All @@ -156,12 +163,10 @@ fn main() -> Result<ExitCode, Box<dyn std::error::Error>> {
}

fn do_main() -> Result<ExitCode, Box<dyn std::error::Error>> {
let is_dry_run: bool = match std::env::var(CIJAIL_DRY_RUN) {
Ok(value) => str_to_bool(value.as_str())?,
Err(_) => false,
};
let is_dry_run = env_to_bool(CIJAIL_DRY_RUN)?;
let allow_loopback = env_to_bool(CIJAIL_ALLOW_LOOPBACK)?;
if std::env::var_os(CIJAIL_TRACER).is_some() {
return tracer::main(0, is_dry_run);
return tracer::main(0, is_dry_run, allow_loopback);
}
let args = Args::parse();
if args.version {
Expand All @@ -176,7 +181,12 @@ fn do_main() -> Result<ExitCode, Box<dyn std::error::Error>> {
};
let (socket0, socket1) = socketpair_stream()?;
let mut tracee = spawn_tracee_process(socket0, args.command)?;
let mut tracer = spawn_tracer_process(socket1, allowed_endpoints, is_dry_run || args.dry_run)?;
let mut tracer = spawn_tracer_process(
socket1,
allowed_endpoints,
is_dry_run || args.dry_run,
allow_loopback || args.allow_loopback,
)?;
let status = tracee.wait()?;
tracer.kill()?;
tracer.wait()?;
Expand All @@ -197,6 +207,13 @@ fn check(ret: c_int) -> Result<c_int, std::io::Error> {
}
}

fn env_to_bool(name: &str) -> Result<bool, std::io::Error> {
match std::env::var(name) {
Ok(value) => str_to_bool(value.as_str()),
Err(_) => Ok(false),
}
}

fn str_to_bool(s: &str) -> Result<bool, std::io::Error> {
let s = s.trim();
match s {
Expand Down
4 changes: 4 additions & 0 deletions src/tracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::CIJAIL_ENDPOINTS;
pub(crate) fn main(
notify_fd: RawFd,
is_dry_run: bool,
allow_loopback: bool,
) -> Result<ExitCode, Box<dyn std::error::Error>> {
let allowed_endpoints: EndpointSet = match std::env::var(CIJAIL_ENDPOINTS) {
Ok(string) => EndpointSet::parse_no_dns_name_resolution(string.as_str())?,
Expand Down Expand Up @@ -70,6 +71,9 @@ pub(crate) fn main(
&mut denied_paths,
&prohibited_files,
)?;
if allow_loopback {
sockaddrs.retain(|sockaddr| !sockaddr.ip().is_loopback());
}
let response = if (sockaddrs.is_empty()
|| allowed_endpoints.contains_any_socket_address(sockaddrs.as_slice()))
&& (dns_names.is_empty()
Expand Down
6 changes: 6 additions & 0 deletions tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ fn dig() {
assert_success(
get_test_bin("cijail")
.env("CIJAIL_ENDPOINTS", format!("{} name.tld", socketaddr))
.args(dig_args.clone()),
);
assert_success(
get_test_bin("cijail")
.env("CIJAIL_ENDPOINTS", "name.tld")
.env("CIJAIL_ALLOW_LOOPBACK", "1")
.args(dig_args),
);
dns_server.stop();
Expand Down

0 comments on commit 842b8b0

Please sign in to comment.