hyprctl: fix buffer overflowing writes to the socket

This commit is contained in:
Vaxry 2026-02-28 15:06:10 +00:00
parent f7114016c6
commit 362ea7b0f3
No known key found for this signature in database
GPG key ID: 665806380871D640
2 changed files with 41 additions and 19 deletions

View file

@ -228,6 +228,9 @@ int request(std::string_view arg, int minArgs = 0, bool needRoll = false) {
constexpr size_t BUFFER_SIZE = 8192; constexpr size_t BUFFER_SIZE = 8192;
char buffer[BUFFER_SIZE] = {0}; char buffer[BUFFER_SIZE] = {0};
// read all data until server closes the connection
// this handles partial writes on the server side under high load
while (true) {
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
if (sizeWritten < 0) { if (sizeWritten < 0) {
@ -237,14 +240,11 @@ int request(std::string_view arg, int minArgs = 0, bool needRoll = false) {
return 6; return 6;
} }
reply += std::string(buffer, sizeWritten); if (sizeWritten == 0) {
// server closed connection, we're done
while (sizeWritten == BUFFER_SIZE) { break;
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
if (sizeWritten < 0) {
log("Couldn't read (6)");
return 6;
} }
reply += std::string(buffer, sizeWritten); reply += std::string(buffer, sizeWritten);
} }

View file

@ -2210,18 +2210,40 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) {
} }
static bool successWrite(int fd, const std::string& data, bool needLog = true) { static bool successWrite(int fd, const std::string& data, bool needLog = true) {
if (write(fd, data.c_str(), data.length()) > 0) size_t totalWritten = 0;
return true; size_t remaining = data.length();
size_t waitsDone = 0;
constexpr const size_t MAX_WAITS = 20; // 2000µs = 2ms
if (errno == EAGAIN) while (totalWritten < data.length()) {
return true; ssize_t written = write(fd, data.c_str() + totalWritten, remaining);
if (needLog)
Log::logger->log(Log::ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno)));
if (waitsDone > MAX_WAITS) {
Log::logger->log(Log::ERR, "Couldn't write to socket. Buffer was full and the client couldn't read in time.");
return false; return false;
} }
if (written < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// socket buffer full, wait a bit and retry
std::this_thread::sleep_for(std::chrono::microseconds(100));
waitsDone++;
continue;
}
if (needLog)
Log::logger->log(Log::ERR, "Couldn't write to socket. Error: {}", strerror(errno));
return false;
}
waitsDone = 0;
totalWritten += written;
remaining -= written;
}
return true;
}
static void runWritingDebugLogThread(const int conn) { static void runWritingDebugLogThread(const int conn) {
using namespace std::chrono_literals; using namespace std::chrono_literals;
Log::logger->log(Log::DEBUG, "In followlog thread, got connection, start writing: {}", conn); Log::logger->log(Log::DEBUG, "In followlog thread, got connection, start writing: {}", conn);