Disallow running CLI with root privileges (#32583)

Yaroslav Pietukhov created

In #31331, I made a change that prevents Zed from running with root
privileges, but I forgot about the CLI.
So if you run the CLI without the `--foreground` flag, it just freezes
without any messages. This PR fixes that.

Release Notes:

- N/A

Change summary

Cargo.lock              |  1 +
crates/cli/src/main.rs  |  3 +++
crates/util/Cargo.toml  |  1 +
crates/util/src/util.rs | 22 ++++++++++++++++++++++
crates/zed/Cargo.toml   |  2 +-
crates/zed/src/main.rs  | 17 +----------------
6 files changed, 29 insertions(+), 17 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -17348,6 +17348,7 @@ dependencies = [
  "itertools 0.14.0",
  "libc",
  "log",
+ "nix 0.29.0",
  "rand 0.8.5",
  "regex",
  "rust-embed",

crates/cli/src/main.rs 🔗

@@ -127,6 +127,9 @@ fn parse_path_with_position(argument_str: &str) -> anyhow::Result<String> {
 }
 
 fn main() -> Result<()> {
+    #[cfg(unix)]
+    util::prevent_root_execution();
+
     // Exit flatpak sandbox if needed
     #[cfg(any(target_os = "linux", target_os = "freebsd"))]
     {

crates/util/Cargo.toml 🔗

@@ -45,6 +45,7 @@ workspace-hack.workspace = true
 [target.'cfg(unix)'.dependencies]
 command-fds = "0.3.1"
 libc.workspace = true
+nix = { workspace = true, features = ["user"] }
 
 [target.'cfg(windows)'.dependencies]
 tendril = "0.4.3"

crates/util/src/util.rs 🔗

@@ -213,6 +213,28 @@ where
     items.sort_by(compare);
 }
 
+/// Prevents execution of the application with root privileges on Unix systems.
+///
+/// This function checks if the current process is running with root privileges
+/// and terminates the program with an error message unless explicitly allowed via the
+/// `ZED_ALLOW_ROOT` environment variable.
+#[cfg(unix)]
+pub fn prevent_root_execution() {
+    let is_root = nix::unistd::geteuid().is_root();
+    let allow_root = std::env::var("ZED_ALLOW_ROOT").is_ok_and(|val| val == "true");
+
+    if is_root && !allow_root {
+        eprintln!(
+            "\
+Error: Running Zed as root or via sudo is unsupported.
+       Doing so (even once) may subtly break things for all subsequent non-root usage of Zed.
+       It is untested and not recommended, don't complain when things break.
+       If you wish to proceed anyways, set `ZED_ALLOW_ROOT=true` in your environment."
+        );
+        std::process::exit(1);
+    }
+}
+
 #[cfg(unix)]
 fn load_shell_from_passwd() -> Result<()> {
     let buflen = match unsafe { libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) } {

crates/zed/Cargo.toml 🔗

@@ -88,7 +88,7 @@ markdown_preview.workspace = true
 menu.workspace = true
 migrator.workspace = true
 mimalloc = { version = "0.1", optional = true }
-nix = { workspace = true, features = ["pthread", "signal", "user"] }
+nix = { workspace = true, features = ["pthread", "signal"] }
 node_runtime.workspace = true
 notifications.workspace = true
 outline.workspace = true

crates/zed/src/main.rs 🔗

@@ -162,22 +162,7 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut App) {
 
 pub fn main() {
     #[cfg(unix)]
-    {
-        let is_root = nix::unistd::geteuid().is_root();
-        let allow_root = env::var("ZED_ALLOW_ROOT").is_ok_and(|val| val == "true");
-
-        // Prevent running Zed with root privileges on Unix systems unless explicitly allowed
-        if is_root && !allow_root {
-            eprintln!(
-                "\
-Error: Running Zed as root or via sudo is unsupported.
-       Doing so (even once) may subtly break things for all subsequent non-root usage of Zed.
-       It is untested and not recommended, don't complain when things break.
-       If you wish to proceed anyways, set `ZED_ALLOW_ROOT=true` in your environment."
-            );
-            process::exit(1);
-        }
-    }
+    util::prevent_root_execution();
 
     // Check if there is a pending installer
     // If there is, run the installer and exit