CVE-2022-27815: Improper Link Resolution Before File Access ('Link Following') (CWE-59)
value: SWHKD 1.1.5 unsafely uses the /tmp/swhkd.pid pathname. There can be an information leak or denial of service.
CWE description: The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource.
CVSS v3 base score: 7.8
Published: 2022-03-30T00:15Z
Repository: https://github.com/waycrate/swhkd
Language: Other
Files changed: Makefile, src/daemon.rs
Commit date: 2022-03-25 20:55:28 +0530
Commit message: [patch] CVE-2022-27815

Diff: diff --git a/Makefile b/Makefile
index d77329d..74e7d22 100644
--- a/Makefile
+++ b/Makefile
@@ -19,10 +19,13 @@ glibc:
 
 install:
 	@mkdir -p $(TARGET_DIR)
 	@mkdir -p $(POLKIT_DIR)
 	@mkdir -p /etc/$(DAEMON_BINARY)
+	@mkdir -p /etc/$(DAEMON_BINARY)/runtime
+	@sudo chown root:root /etc/$(DAEMON_BINARY)/runtime
+	@sudo chmod 700 /etc/$(DAEMON_BINARY)/runtime
 	@touch /etc/$(DAEMON_BINARY)/$(DAEMON_BINARY)rc
 	@cp ./bin/$(DAEMON_BINARY) $(TARGET_DIR)
 	@cp ./bin/$(SERVER_BINARY) $(TARGET_DIR)
 	@cp ./$(POLKIT_RULE) $(POLKIT_DIR)/$(POLKIT_RULE)
 	@chmod +x $(TARGET_DIR)/$(DAEMON_BINARY)
diff --git a/src/daemon.rs b/src/daemon.rs
index 6b1d07d..ff396c0 100644
--- a/src/daemon.rs
+++ b/src/daemon.rs
@@ -37,20 +37,21 @@ impl KeyboardState {
 }
 
 #[tokio::main]
 async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let args = set_command_line_args().get_matches();
+    let invoking_uid = env::var("PKEXEC_UID").unwrap().parse::<u32>().unwrap();
     env::set_var("RUST_LOG", "swhkd=warn");
 
     if args.is_present("debug") {
         env::set_var("RUST_LOG", "swhkd=trace");
     }
 
     env_logger::init();
     log::trace!("Logger initialized.");
 
-    let pidfile: String = String::from("/tmp/swhkd.pid");
+    let pidfile: String = String::from(format!("/etc/swhkd/runtime/swhkd_{}.pid", invoking_uid));
     if Path::new(&pidfile).exists() {
         log::trace!("Reading {} file and checking for running instances.", pidfile);
         let swhkd_pid = match fs::read_to_string(&pidfile) {
             Ok(swhkd_pid) => swhkd_pid,
             Err(e) => {
@@ -83,11 +84,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     if check_user_permissions().is_err() {
         exit(1);
     }
 
     let load_config = || {
-        seteuid(env::var("PKEXEC_UID").unwrap().parse::<u32>().unwrap()); // Dropping privileges to invoking user.
+        seteuid(invoking_uid); // Dropping privileges to invoking user.
         let config_file_path: std::path::PathBuf = if args.is_present("config") {
             Path::new(args.value_of("config").unwrap()).to_path_buf()
         } else {
             fetch_xdg_config_path()
         };

Vulnerable code:     let pidfile: String = String::from("/tmp/swhkd.pid");
        seteuid(env::var("PKEXEC_UID").unwrap().parse::<u32>().unwrap()); // Dropping privileges to invoking user.
Fixed code: 	@mkdir -p /etc/$(DAEMON_BINARY)/runtime
	@sudo chown root:root /etc/$(DAEMON_BINARY)/runtime
	@sudo chmod 700 /etc/$(DAEMON_BINARY)/runtime
    let invoking_uid = env::var("PKEXEC_UID").unwrap().parse::<u32>().unwrap();
    let pidfile: String = String::from(format!("/etc/swhkd/runtime/swhkd_{}.pid", invoking_uid));
        seteuid(invoking_uid); // Dropping privileges to invoking user.