From 8f2e52e54046fc942e2b80ffb88a71ff0f2300bd Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 24 Oct 2026 18:19:58 -0500 Subject: [PATCH] Refuse to open a pre-existing log file (#2068) On macOS, release builds log to /tmp/Moonlight-.log. /tmp is shared by all users and the file name is predictable, so another local user could plant symlinks at upcoming log names and have Moonlight truncate and overwrite any file the victim can write to. The log was also created world-readable. Open the log with QIODevice::NewOnly (O_CREAT|O_EXCL) so an existing file or symlink is never opened, and create it readable only by the owner on Qt 6.3+. If the open fails we keep logging to stderr, as we already did for any other open failure. --- app/main.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/main.cpp b/app/main.cpp index 7ec0cca9..6629a752 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -465,7 +465,16 @@ int main(int argc, char *argv[]) #endif { s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch()))); - if (s_LoggerFile->open(QIODevice::WriteOnly | QIODevice::Text)) { + + // The log directory may be shared with other users (/tmp on macOS), so + // we must never open a file or symlink that someone else planted there. + // NewOnly fails if anything already exists at this path. + QIODevice::OpenMode logOpenMode = QIODevice::WriteOnly | QIODevice::Text | QIODevice::NewOnly; +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) + if (s_LoggerFile->open(logOpenMode, QFileDevice::ReadOwner | QFileDevice::WriteOwner)) { +#else + if (s_LoggerFile->open(logOpenMode)) { +#endif QTextStream(stderr) << "Redirecting log output to " << s_LoggerFile->fileName() << Qt::endl; s_LoggerStream.setDevice(s_LoggerFile); }