diff mbox series

[1/3] tools/thermal/tmon: Prevent symlink attack on log file

Message ID 20250509154435.14670-2-trenn@suse.de
State New
Headers show
Series [1/3] tools/thermal/tmon: Prevent symlink attack on log file | expand

Commit Message

Thomas Renninger May 9, 2025, 3:44 p.m. UTC
From: Wolfgang Frisch <wolfgang.frisch@suse.com>

If fs.protected_symlinks=0, an unprivileged local user could create a
symbolic link at /var/log/tmon.log and, in turn, cause `tmon -l` to
truncate arbitrary files on the system when prepare_logging() is
executed.

Change prepare_logging() to use openat() and create the log file
securely.

Fixes: 951fda3d8c644597a1d5cdae14cab31567e754a1
Signed-off-by: Wolfgang Frisch <wolfgang.frisch@suse.com>
Reviewed-by: Thomas Renninger <trenn@suse.de>
---
 tools/thermal/tmon/tmon.c | 50 +++++++++++++++++++++++++++------------
 tools/thermal/tmon/tmon.h |  3 ++-
 2 files changed, 37 insertions(+), 16 deletions(-)
diff mbox series

Patch

diff --git a/tools/thermal/tmon/tmon.c b/tools/thermal/tmon/tmon.c
index 7eb3216a27f4..e7392c0f6388 100644
--- a/tools/thermal/tmon/tmon.c
+++ b/tools/thermal/tmon/tmon.c
@@ -24,6 +24,8 @@ 
 #include <math.h>
 #include <stdarg.h>
 #include <syslog.h>
+#include <fcntl.h>
+#include <errno.h>
 
 #include "tmon.h"
 
@@ -132,35 +134,53 @@  static void prepare_logging(void)
 {
 	int i;
 	struct stat logstat;
+	int dir_fd = -1;
+	int log_fd = -1;
+	tmon_log = NULL;
 
 	if (!logging)
 		return;
-	/* open local data log file */
-	tmon_log = fopen(TMON_LOG_FILE, "w+");
-	if (!tmon_log) {
-		syslog(LOG_ERR, "failed to open log file %s\n", TMON_LOG_FILE);
+
+	/* get a file descriptor for the log directory */
+	dir_fd = open(TMON_LOG_DIR, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+	if (dir_fd < 0) {
+		syslog(LOG_ERR, "Failed to open log directory %s: %s\n",
+		       TMON_LOG_DIR, strerror(errno));
 		return;
 	}
 
-	if (lstat(TMON_LOG_FILE, &logstat) < 0) {
-		syslog(LOG_ERR, "Unable to stat log file %s\n", TMON_LOG_FILE);
-		fclose(tmon_log);
-		tmon_log = NULL;
+	/* open local data log file securely using openat() */
+	log_fd = openat(dir_fd, TMON_LOG_FILENAME,
+	                O_RDWR | O_CREAT | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
+	                0600);
+	close(dir_fd);
+
+	if (log_fd < 0) {
+		syslog(LOG_ERR, "Failed to open log file %s/%s: %s\n",
+		       TMON_LOG_DIR, TMON_LOG_FILENAME, strerror(errno));
 		return;
 	}
 
-	/* The log file must be a regular file owned by us */
-	if (S_ISLNK(logstat.st_mode)) {
-		syslog(LOG_ERR, "Log file is a symlink.  Will not log\n");
-		fclose(tmon_log);
-		tmon_log = NULL;
+	if (fstat(log_fd, &logstat) < 0) {
+		syslog(LOG_ERR, "Unable to stat log file %s/%s\n",
+		       TMON_LOG_DIR, TMON_LOG_FILENAME);
+		close(log_fd);
 		return;
 	}
 
+	/* The log file must be owned by us */
 	if (logstat.st_uid != getuid()) {
 		syslog(LOG_ERR, "We don't own the log file.  Not logging\n");
-		fclose(tmon_log);
-		tmon_log = NULL;
+		close(log_fd);
+		return;
+	}
+
+	/* All checks passed. Convert the file descriptor to a FILE stream. */
+	tmon_log = fdopen(log_fd, "w+");
+	if (!tmon_log) {
+		syslog(LOG_ERR, "Failed to fdopen log file descriptor for %s/%s: %s\n",
+		       TMON_LOG_DIR, TMON_LOG_FILENAME, strerror(errno));
+		close(log_fd);
 		return;
 	}
 
diff --git a/tools/thermal/tmon/tmon.h b/tools/thermal/tmon/tmon.h
index 44d16d778f04..5c35f8cd7cab 100644
--- a/tools/thermal/tmon/tmon.h
+++ b/tools/thermal/tmon/tmon.h
@@ -25,7 +25,8 @@ 
  */
 #define DATA_LEFT_ALIGN 10
 #define NR_LINES_TZDATA 1
-#define TMON_LOG_FILE "/var/tmp/tmon.log"
+#define TMON_LOG_DIR "/var/tmp"
+#define TMON_LOG_FILENAME "tmon.log"
 
 #include <sys/time.h>
 #include <pthread.h>