Summary
The IPC mechanism has a busy-wait loop consuming 100% CPU and lacks authentication, allowing any same-user process to inject events.
Details
Busy-wait loop (src/ipc.cpp:234-249)
bool IPC::waitUntilAccepted(time_t postTime, int32_t timeout /*=-1*/)
{
bool result = false;
const time_t start = time(nullptr);
forever {
result = isEventAccepted(postTime);
if (result || (timeout > 0 && difftime(time(nullptr), start) >= timeout)) {
break;
}
qApp->processEvents();
QThread::msleep(0); // yields but does NOT actually sleep
}
return result;
}
With timeout == -1 (the default), this is an infinite busy-wait. Even with a positive timeout, the loop polls at maximum speed. QThread::msleep(0) only yields the time slice but doesn't sleep.
Fix: Use QThread::msleep(50) for a reasonable poll interval, or replace with QEventLoop + QTimer. Add a maximum timeout even for the -1 case.
Unauthenticated shared memory (src/ipc.cpp:34-42)
The shared memory key is "qtox-2-<USERNAME>". Any process running as the same user can:
- Attach to the segment
- Inject events (e.g.,
tox: URIs that trigger friend request dialogs)
- Read event data from the queue
Additionally, getenv("USER") returns NULL if unset, causing all users without the variable to share IPC key "qtox-2-" (line 37-40).
Fix for username: Use getpwuid(getuid()) on POSIX, GetUserNameW() on Windows instead of environment variables.
Fix for authentication: Add a random shared secret initialized at first launch and stored in the profile. Verify it in a HMAC field on each IPCEvent.
Impact
Busy-wait causes 100% CPU on one core during IPC synchronization. Unauthenticated IPC allows local event injection (low severity for desktop app, but relevant for privacy-focused software).
Summary
The IPC mechanism has a busy-wait loop consuming 100% CPU and lacks authentication, allowing any same-user process to inject events.
Details
Busy-wait loop (
src/ipc.cpp:234-249)With
timeout == -1(the default), this is an infinite busy-wait. Even with a positive timeout, the loop polls at maximum speed.QThread::msleep(0)only yields the time slice but doesn't sleep.Fix: Use
QThread::msleep(50)for a reasonable poll interval, or replace withQEventLoop+QTimer. Add a maximum timeout even for the-1case.Unauthenticated shared memory (
src/ipc.cpp:34-42)The shared memory key is
"qtox-2-<USERNAME>". Any process running as the same user can:tox:URIs that trigger friend request dialogs)Additionally,
getenv("USER")returns NULL if unset, causing all users without the variable to share IPC key"qtox-2-"(line 37-40).Fix for username: Use
getpwuid(getuid())on POSIX,GetUserNameW()on Windows instead of environment variables.Fix for authentication: Add a random shared secret initialized at first launch and stored in the profile. Verify it in a HMAC field on each
IPCEvent.Impact
Busy-wait causes 100% CPU on one core during IPC synchronization. Unauthenticated IPC allows local event injection (low severity for desktop app, but relevant for privacy-focused software).