From 9011c36da6e2394954986619058745b128180530 Mon Sep 17 00:00:00 2001 From: Ryan Gonzalez Date: Fri, 23 Jun 2023 20:16:48 -0500 Subject: [PATCH] hostsfile: Copy the SELinux context to the temp file before overwrite On SELinux-enabled systems, /etc/hosts has a different type `net_conf_t` than the other files in /etc, so the temporary file that overwrites it ends up with the wrong context, resulting in many system services becoming unable to access the file. To fix this, manually look up the context /etc/hosts has and copy it to the temporary file before the rename. In order to avoid depending on libselinux on systems that don't use it, this support is gated behind the new "selinux" feature. It *is* installed and enabled in the Dockerfile, however, in order to ensure that it still builds. --- Cargo.lock | 205 ++++++++++++++++++++++++++++++- client/Cargo.toml | 3 + docker-tests/Dockerfile.innernet | 4 +- hostsfile/Cargo.toml | 1 + hostsfile/src/lib.rs | 42 +++++++ 5 files changed, 249 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97eddba..5e323d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,29 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.5.0", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -150,9 +173,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "byteorder" @@ -172,12 +195,32 @@ version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.1" @@ -326,6 +369,18 @@ dependencies = [ "shell-words", ] +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "either" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -450,6 +505,12 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "hashbrown" version = "0.14.3" @@ -496,11 +557,21 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "hostsfile" version = "1.2.0" dependencies = [ "log", + "selinux", "tempfile", ] @@ -605,6 +676,15 @@ dependencies = [ "serde", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -617,12 +697,28 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.4", +] + [[package]] name = "libsqlite3-sys" version = "0.26.0" @@ -680,6 +776,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -814,6 +916,16 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -908,6 +1020,16 @@ dependencies = [ "log", ] +[[package]] +name = "prettyplease" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.78" @@ -954,6 +1076,12 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "reference-counted-singleton" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "242f841f006fa4f35979f74147f6d0be4402c19ca25b62b1c8e4c02e28288cb9" + [[package]] name = "regex" version = "1.10.3" @@ -989,7 +1117,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -1003,6 +1131,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1018,7 +1152,7 @@ version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -1031,12 +1165,47 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "selinux" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53371b1e9bbbfffd65e5ac3c895c786ec35b7695bdc4a67a8b08c29c8d057e0b" +dependencies = [ + "bitflags 2.5.0", + "libc", + "once_cell", + "reference-counted-singleton", + "selinux-sys", + "thiserror", +] + +[[package]] +name = "selinux-sys" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d45498373dc17ec8ebb72e1fd320c015647b0157fc81dddf678e2e00205fec" +dependencies = [ + "bindgen", + "cc", + "dunce", + "walkdir", +] + [[package]] name = "semver" version = "1.0.22" @@ -1151,6 +1320,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "smallvec" version = "1.13.1" @@ -1418,6 +1593,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1433,6 +1618,18 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/client/Cargo.toml b/client/Cargo.toml index 09ffb4e..32abf91 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -40,6 +40,9 @@ wireguard-control = { path = "../wireguard-control" } once_cell = "1.17.1" tempfile = "3" +[features] +selinux = ["hostsfile/selinux"] + [package.metadata.deb] assets = [ ["target/release/innernet", "usr/bin/", "755"], diff --git a/docker-tests/Dockerfile.innernet b/docker-tests/Dockerfile.innernet index 18baab1..d216582 100644 --- a/docker-tests/Dockerfile.innernet +++ b/docker-tests/Dockerfile.innernet @@ -16,13 +16,13 @@ RUN mkdir /repo \ #################################################################################################### FROM rust:slim-bookworm RUN apt-get update && \ - apt-get install -y --no-install-recommends libsqlite3-dev iproute2 iputils-ping build-essential clang libclang-dev && \ + apt-get install -y --no-install-recommends libsqlite3-dev iproute2 iputils-ping build-essential clang libclang-dev libselinux1-dev && \ rm -rf /var/lib/apt/lists/* WORKDIR /app COPY . . -RUN cargo build \ +RUN cargo build --features client/selinux \ && strip /app/target/debug/innernet /app/target/debug/innernet-server \ && cp /app/target/debug/innernet /app/target/debug/innernet-server /usr/bin/ \ && cargo clean diff --git a/hostsfile/Cargo.toml b/hostsfile/Cargo.toml index 77526c0..0fa8bb0 100644 --- a/hostsfile/Cargo.toml +++ b/hostsfile/Cargo.toml @@ -9,6 +9,7 @@ version = "1.2.0" [dependencies] log = "0.4" +selinux = { version = "0.4", optional = true } [dev-dependencies] tempfile = "3" diff --git a/hostsfile/src/lib.rs b/hostsfile/src/lib.rs index 514cc5c..b8844a2 100644 --- a/hostsfile/src/lib.rs +++ b/hostsfile/src/lib.rs @@ -285,6 +285,48 @@ impl HostsBuilder { fn write_and_swap(temp_path: &Path, hosts_path: &Path, contents: &[u8]) -> io::Result<()> { // Copy the file we plan on modifying so its permissions and metadata are preserved. std::fs::copy(hosts_path, temp_path)?; + + #[cfg(feature = "selinux")] + if selinux::current_mode() != selinux::SELinuxMode::NotRunning { + log::trace!("SELinux is running; copying context"); + use selinux::SecurityContext; + + const FOLLOW_SYMBOLIC_LINKS: bool = false; + const RAW_FORMAT: bool = false; + match SecurityContext::of_path(hosts_path, FOLLOW_SYMBOLIC_LINKS, RAW_FORMAT) { + Ok(Some(context)) => { + log::trace!( + "{} context is {:?}", + hosts_path.display(), + context.to_c_string() + ); + if let Err(err) = + context.set_for_path(temp_path, FOLLOW_SYMBOLIC_LINKS, RAW_FORMAT) + { + log::warn!( + "SELinux context of {} ({:?}) could not be set \ + ({} may become inaccessible due to permission errors): {:?}", + temp_path.display(), + context.to_c_string(), + hosts_path.display(), + err + ); + } + }, + Ok(None) => { + log::trace!("Hosts file {} had no SELinux context", hosts_path.display()); + }, + Err(err) => { + log::warn!( + "SELinux context of {} could not be retrieved \ + (file may become inaccessible due to permission errors): {:?}", + hosts_path.display(), + err + ); + }, + } + } + Self::write_clobber(temp_path, contents)?; std::fs::rename(temp_path, hosts_path)?; Ok(())