CVE-2022-23950: Exposure of Resource to Wrong Sphere (CWE-668)
value: In Keylime before 6.3.0, Revocation Notifier uses a fixed /tmp path for UNIX domain socket which can allow unprivileged users a method to prohibit keylime operations.
CWE description: The product exposes a resource to the wrong control sphere, providing unintended actors with inappropriate access to the resource.
CVSS v3 base score: 7.5
Published: 2022-09-21T19:15Z
Repository: https://github.com/keylime/keylime
Language: Python
Files changed: keylime/revocation_notifier.py
Commit date: 2022-01-27 11:09:26 -0500
Commit message: revocation_notifier: move zmq socket to /var/run/keylime

Currently we are placing the zmq IPC socket in /tmp, that can be
accessed by all the users.

This patch moves the socket into /var/run/keylime, making sure that the
directory is created and present with the correct user permissions.

Signed-off-by: Alberto Planas <aplanas@suse.com>

Diff: diff --git a/keylime/revocation_notifier.py b/keylime/revocation_notifier.py
index eabbf1a..e9e3b3f 100644
--- a/keylime/revocation_notifier.py
+++ b/keylime/revocation_notifier.py
@@ -21,16 +21,27 @@ from keylime import secure_mount
 
 
 logger = keylime_logging.init_logging('revocation_notifier')
 broker_proc = None
 
+_SOCKET_PATH = "/var/run/keylime/keylime.verifier.ipc"
+
 
 def start_broker():
     def worker():
+        dir_name = os.path.dirname(_SOCKET_PATH)
+        if not os.path.exists(dir_name):
+            os.makedirs(dir_name, 0o700)
+        else:
+            if os.stat(_SOCKET_PATH).st_mode & 0o777 != 0o700:
+                msg = f"{_SOCKET_PATH} present with wrong permissions"
+                logger.error(msg)
+                raise Exception(msg)
+
         context = zmq.Context(1)
         frontend = context.socket(zmq.SUB)
-        frontend.bind("ipc:///tmp/keylime.verifier.ipc")
+        frontend.bind(f"ipc://{_SOCKET_PATH}")
 
         frontend.setsockopt(zmq.SUBSCRIBE, b'')
 
         # Socket facing services
         backend = context.socket(zmq.PUB)
@@ -50,22 +61,22 @@ def start_broker():
 
 def stop_broker():
     global broker_proc
     if broker_proc is not None:
         # Remove the socket file before  we kill the process
-        if os.path.exists("/tmp/keylime.verifier.ipc"):
-            os.remove("/tmp/keylime.verifier.ipc")
+        if os.path.exists(f"ipc://{_SOCKET_PATH}"):
+            os.remove(f"ipc://{_SOCKET_PATH}")
         logger.info("Stopping revocation notifier...")
         broker_proc.terminate()
         broker_proc.join()
 
 
 def notify(tosend):
     def worker(tosend):
         context = zmq.Context()
         mysock = context.socket(zmq.PUB)
-        mysock.connect("ipc:///tmp/keylime.verifier.ipc")
+        mysock.connect(f"ipc://{_SOCKET_PATH}")
         # wait 100ms for connect to happen
         time.sleep(0.2)
         # now send it out via 0mq
         logger.info("Sending revocation event to listening nodes...")
         for i in range(config.getint('cloud_verifier', 'max_retries')):

Vulnerable code:         frontend.bind("ipc:///tmp/keylime.verifier.ipc")
        if os.path.exists("/tmp/keylime.verifier.ipc"):
            os.remove("/tmp/keylime.verifier.ipc")
        mysock.connect("ipc:///tmp/keylime.verifier.ipc")
Fixed code: _SOCKET_PATH = "/var/run/keylime/keylime.verifier.ipc"

        dir_name = os.path.dirname(_SOCKET_PATH)
        if not os.path.exists(dir_name):
            os.makedirs(dir_name, 0o700)
        else:
            if os.stat(_SOCKET_PATH).st_mode & 0o777 != 0o700:
                msg = f"{_SOCKET_PATH} present with wrong permissions"
                logger.error(msg)
                raise Exception(msg)

        frontend.bind(f"ipc://{_SOCKET_PATH}")
        if os.path.exists(f"ipc://{_SOCKET_PATH}"):
            os.remove(f"ipc://{_SOCKET_PATH}")
        mysock.connect(f"ipc://{_SOCKET_PATH}")