Repository: cloudflare/boringtun (language: rust)

Issue:
Not dropping root privileges running on macOS 11.6.1
Good afternoon,

I've just been testing `boringtun` on macOS but noticed that when I run using the following command, that it does not drop root privileges.

sudo WG_QUICK_USERSPACE_IMPLEMENTATION=boringtun WG_SUDO=1 wg-quick down ~/wireguard/example.conf

The `boringtun` process is running as root.

Cheers,
-Chris


Discussion / hints:
Can you try with the latest version from the master branch?
Hey @Noah-Kennedy I tried installing but received the following dependency error:

```
❯ cargo install boringtun
    Updating crates.io index
  Downloaded boringtun v0.4.0
  Downloaded 1 crate (414.3 KB) in 0.65s
  Installing boringtun v0.4.0
  Downloaded itoa v1.0.1
  Downloaded num_threads v0.1.3
  Downloaded cfg-if v1.0.0
  Downloaded ip_network_table-deps-treebitmap v0.5.0
  Downloaded once_cell v1.9.0
  Downloaded pin-project-lite v0.2.8
  Downloaded parking_lot_core v0.9.1
  Downloaded scopeguard v1.1.0
  Downloaded libc v0.2.117
  Downloaded parking_lot v0.12.0
  Downloaded log v0.4.14
  Downloaded smallvec v1.8.0
  Downloaded tracing-attributes v0.1.19
  Downloaded unicode-xid v0.2.2
  Downloaded untrusted v0.9.0
  Downloaded tracing-subscriber v0.3.8
  Downloaded thread_local v1.1.4
  Downloaded tracing-appender v0.2.0
  Downloaded time v0.3.7
error: failed to compile `boringtun v0.4.0`, intermediate artifacts can be found at `/var/folders/hb/2mnxsd9x0bs4c6_2ldwz30km0000gq/T/cargo-installSDr0Oi`

Caused by:
  failed to parse manifest at `/Users/cjones/.cargo/registry/src/github.com-1ecc6299db9ec823/time-0.3.7/Cargo.toml`

Caused by:
  feature `resolver` is required

  this Cargo does not support nightly features, but if you
  switch to nightly channel you can add
  `cargo-features = ["resolver"]` to enable this feature
```

What OS?
Oh nvm this is still macos I presume
Correct
Gonna try an run this on an old macbook I've got. It ran fine on CI so this is kinda weird.
@autonomic what version of the rust toolchain are you running? This looks like an issue where you are running an older version of the compiler and it isn't detecting newer cargo features.
Also, it works on my macbook. Pretty sure that `rustup update` will fix this for you, but I'd like to know what version you are running as well.
I'm running the latest version from Homebrew.

```
❯ brew info rust
rust: stable 1.58.1 (bottled), HEAD
Safe, concurrent, practical language
https://www.rust-lang.org/
/usr/local/Cellar/rust/1.58.1 (33,798 files, 840.2MB) *
  Poured from bottle on 2022-01-24 at 08:01:42
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/rust.rb
License: Apache-2.0 or MIT
==> Dependencies
Build: cmake ✔, ninja ✘, python@3.9 ✔
Required: libssh2 ✔, openssl@1.1 ✔, pkg-config ✔
==> Options
--HEAD
        Install HEAD version
==> Caveats
zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==> Analytics
install: 39,436 (30 days), 90,085 (90 days), 348,169 (365 days)
install-on-request: 24,774 (30 days), 51,317 (90 days), 188,965 (365 days)
build-error: 463 (30 days)
```
Can you give me the output of `cargo --version`? I get the brew package, but there is something else I want to see.
That did the trick. After I ran `rustup update` it now compiles properly.
@autonomic In general I'd avoid any distro or other package mangager installs of the compiler or cargo, and would just use rustup, which is the more official way to do things.
After upgrading boringtun to 0.4.0 it's still not dropping root privileges.

```
root             16506   0.0  0.0  4327092   2236   ??  S    10:17PM   0:00.02 boringtun utun
```
Alright, I figured this might be the case. This can get fixed later in a point release, now that boringtun is going to be shipping regularly again (I released 0.4.0 today). PRs are welcome from anyone interested in this. I probably wouldn't be able to get to this for a while.
Okay no worries, appreciate the help.

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 8a65d4ae..6884900c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -22,6 +22,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
 [[package]]
 name = "base64"
 version = "0.13.0"
@@ -44,6 +50,7 @@ dependencies = [
  "ip_network_table",
  "jni",
  "libc",
+ "nix",
  "parking_lot",
  "ring",
  "tracing",
@@ -263,6 +270,28 @@ version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 
+[[package]]
+name = "memoffset"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "nix"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
+dependencies = [
+ "bitflags",
+ "cc",
+ "cfg-if",
+ "libc",
+ "memoffset",
+]
+
 [[package]]
 name = "num_threads"
 version = "0.1.3"
diff --git a/boringtun/Cargo.toml b/boringtun/Cargo.toml
index 6fa32bda..96078b6a 100644
--- a/boringtun/Cargo.toml
+++ b/boringtun/Cargo.toml
@@ -26,6 +26,9 @@ tracing-subscriber = "0.3"
 [target.'cfg(target_os="android")'.dependencies]
 jni = "0.19.0"
 
+[target.'cfg(target_os="macos")'.dependencies]
+nix = "0.23.1"
+
 [[example]]
 name = "benchmarks"
 path = "src/benchmarks_example.rs"
diff --git a/boringtun/src/device/drop_privileges.rs b/boringtun/src/device/drop_privileges.rs
index b454d528..7784623a 100644
--- a/boringtun/src/device/drop_privileges.rs
+++ b/boringtun/src/device/drop_privileges.rs
@@ -5,23 +5,35 @@ use crate::device::errno_str;
 use crate::device::Error;
 use libc::*;
 
+#[cfg(target_os = "macos")]
+use nix::unistd::User;
+
 pub fn get_saved_ids() -> Result<(uid_t, gid_t), Error> {
     // Get the user name of the sudoer
-    let uname = unsafe { getlogin() };
-    if uname.is_null() {
-        return Err(Error::DropPrivileges("NULL from getlogin".to_owned()));
+    #[cfg(target_os = "macos")]
+    {
+        let uname: &'static str = env!("USER");
+        let user = User::from_name(uname).unwrap().expect("a user");
+        return Ok((uid_t::from(user.uid), gid_t::from(user.gid)));
     }
-    let userinfo = unsafe { getpwnam(uname) };
-    if userinfo.is_null() {
-        return Err(Error::DropPrivileges("NULL from getpwnam".to_owned()));
+    #[cfg(not(target_os = "macos"))]
+    {
+        let uname = unsafe { getlogin() };
+        if uname.is_null() {
+            return Err(Error::DropPrivileges("NULL from getlogin".to_owned()));
+        }
+        let userinfo = unsafe { getpwnam(uname) };
+        if userinfo.is_null() {
+            return Err(Error::DropPrivileges("NULL from getpwnam".to_owned()));
+        }
+
+        // Saved group ID
+        let saved_gid = unsafe { (*userinfo).pw_gid };
+        // Saved user ID
+        let saved_uid = unsafe { (*userinfo).pw_uid };
+
+        return Ok((saved_uid, saved_gid));
     }
-
-    // Saved group ID
-    let saved_gid = unsafe { (*userinfo).pw_gid };
-    // Saved user ID
-    let saved_uid = unsafe { (*userinfo).pw_uid };
-
-    Ok((saved_uid, saved_gid))
 }
 
 pub fn drop_privileges() -> Result<(), Error> {


Test patch: