Pārlūkot izejas kodu

daemon: use readlink not realpath to find the exe

The realpath(3) will fail if the target does not exist (internally
realpath will stat all the components of the link target path).
This is a problem in the case of sandbox applications where
the exe points to the absolute path *inside* the sandbox, e.g. to
/app/bin/<name> in the case of flatpak. For these cases realpath(3)
will then fail. Therefore use readlink(3) instead.
Christian Kellner 5 gadi atpakaļ
vecāks
revīzija
70e601267b
1 mainītis faili ar 24 papildinājumiem un 4 dzēšanām
  1. 24 4
      daemon/gamemode.c

+ 24 - 4
daemon/gamemode.c

@@ -40,10 +40,14 @@ POSSIBILITY OF SUCH DAMAGE.
 #include "helpers.h"
 #include "logging.h"
 
+#include <fcntl.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdatomic.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <systemd/sd-daemon.h>
+#include <unistd.h>
 
 /**
  * The GameModeClient encapsulates the remote connection, providing a list
@@ -650,15 +654,31 @@ static char *game_mode_context_find_exe(pid_t pid)
 {
 	char buffer[PATH_MAX];
 	char *proc_path = NULL, *wine_exe = NULL;
+	autoclose_fd int pidfd = -1;
+	ssize_t r;
 
-	if (!(proc_path = buffered_snprintf(buffer, "/proc/%d/exe", pid)))
+	if (!(proc_path = buffered_snprintf(buffer, "/proc/%d", pid)))
 		goto fail;
 
-	/* Allocate the realpath if possible */
-	char *exe = realpath(proc_path, NULL);
-	if (!exe)
+	/* Translate /proc/<pid>/exe to the application binary */
+	pidfd = openat(AT_FDCWD, proc_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
+	if (pidfd == -1)
 		goto fail;
 
+	r = readlinkat(pidfd, "exe", buffer, sizeof(buffer));
+
+	if (r == sizeof(buffer)) {
+		errno = ENAMETOOLONG;
+		r = -1;
+	}
+
+	if (r == -1)
+		goto fail;
+
+	buffer[r] = '\0';
+
+	char *exe = strdup(buffer);
+
 	/* Detect if the process is a wine loader process */
 	if (game_mode_detect_wine_preloader(exe)) {
 		LOG_MSG("Detected wine preloader for client %d [%s].\n", pid, exe);