Refuse to open a pre-existing log file (#2068)

On macOS, release builds log to /tmp/Moonlight-<epoch>.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.
This commit is contained in:
Chris authored and GitHub committed 2026-10-24 18:19:58 -05:00
1 parent c8474c515c
commit 8f2e52e540
1 file changed
+10 -1
+10 -1
View File
@@ -465,7 +465,16 @@ int main(int argc, char *argv[])
#endif #endif
{ {
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch()))); 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; QTextStream(stderr) << "Redirecting log output to " << s_LoggerFile->fileName() << Qt::endl;
s_LoggerStream.setDevice(s_LoggerFile); s_LoggerStream.setDevice(s_LoggerFile);
} }