Commit Diff


commit - b23e19ecd4f7a33e6cd03ab53103b65ccf4f8f1d
commit + 3bde6929768adf802fbe57b27d1ef99204bad8cc
blob - 4f07a3ef3f1b6dfc6da80ebc11996b99bbe90669
blob + b8c555ceffae58e8e93eb6eecad45354d127f0c7
--- include/globals.h
+++ include/globals.h
@@ -102,6 +102,9 @@
 // clients from Keep Alive packets.
 #define NETWORK_TIMEOUT_TIME 15000000
 
+// Size of the receive buffer for incoming string data
+#define MAX_RECV_BUF_LEN 256 
+
 // If defined, sends the server brand to clients. Doesn't do much, but will
 // show up in the top-left of the F3/debug menu, in the Minecraft client.
 // You can change the brand string in the "brand" variable in src/globals.c
blob - f83ba09748d486b9bef7b6f325e6a8b9c39155ff
blob + 9eb796dbb8671892346b640e07410a2d819e3102
--- include/tools.h
+++ include/tools.h
@@ -32,7 +32,9 @@ int64_t readInt64 (int client_fd);
 float readFloat (int client_fd);
 double readDouble (int client_fd);
 
+ssize_t readLengthPrefixedData (int client_fd);
 void readString (int client_fd);
+void readStringN (int client_fd, uint32_t max_length);
 
 uint32_t fast_rand ();
 uint64_t splitmix64 (uint64_t state);
blob - 731e7fad9e48b6855e54acb2603331ca3c42380b
blob + 1b5b462f7b7d434bac0b4c0b00ede8cd0b12501c
--- src/globals.c
+++ src/globals.c
@@ -29,7 +29,7 @@
 #endif
 
 ssize_t recv_count;
-uint8_t recv_buffer[256] = {0};
+uint8_t recv_buffer[MAX_RECV_BUF_LEN] = {0};
 
 uint32_t world_seed = INITIAL_WORLD_SEED;
 uint32_t rng_seed = INITIAL_RNG_SEED;
blob - cbb110903212a3c5afd085aa3c8cdc688d50d4cc
blob + 97c26f1ebd721ff802b643e96bfea1e6a7254433
--- src/packets.c
+++ src/packets.c
@@ -658,10 +658,8 @@ int cs_clickContainer (int client_fd) {
     count = (uint8_t)readVarInt(client_fd);
 
     // ignore components
-    tmp = readVarInt(client_fd);
-    recv_all(client_fd, recv_buffer, tmp, false);
-    tmp = readVarInt(client_fd);
-    recv_all(client_fd, recv_buffer, tmp, false);
+    readLengthPrefixedData(client_fd);
+    readLengthPrefixedData(client_fd);
 
     if (count > 0 && apply_changes) {
       *p_item = item;
@@ -691,10 +689,8 @@ int cs_clickContainer (int client_fd) {
     player->flagval_16 = readVarInt(client_fd);
     player->flagval_8 = readVarInt(client_fd);
     // ignore components
-    tmp = readVarInt(client_fd);
-    recv_all(client_fd, recv_buffer, tmp, false);
-    tmp = readVarInt(client_fd);
-    recv_all(client_fd, recv_buffer, tmp, false);
+    readLengthPrefixedData(client_fd);
+    readLengthPrefixedData(client_fd);
   } else {
     player->flagval_16 = 0;
     player->flagval_8 = 0;
@@ -1117,7 +1113,8 @@ int sc_systemChat (int client_fd, char* message, uint1
 // C->S Chat Message
 int cs_chat (int client_fd) {
 
-  readString(client_fd);
+  // To be safe, cap messages to 32 bytes before the buffer length
+  readStringN(client_fd, 224);
 
   PlayerData *player;
   if (getPlayerData(client_fd, &player)) return 1;
@@ -1125,12 +1122,6 @@ int cs_chat (int client_fd) {
   size_t message_len = strlen((char *)recv_buffer);
   uint8_t name_len = strlen(player->name);
 
-  // To be safe, cap messages to 32 bytes before the buffer length
-  if (message_len > 224) {
-    recv_buffer[224] = '\0';
-    message_len = 224;
-  }
-
   if (recv_buffer[0] != '!') { // Standard chat message
 
     // Shift message contents forward to make space for player name tag
blob - 0b7050f9785d2d07f62890ca08ae09b4c24b3ecc
blob + a84ffd1d0d554d906f5000834af086c8bbeed8a5
--- src/tools.c
+++ src/tools.c
@@ -217,11 +217,44 @@ double readDouble (int client_fd) {
   return output;
 }
 
+// Receive length prefixed data with bounds checking
+ssize_t readLengthPrefixedData (int client_fd) {
+  uint32_t length = readVarInt(client_fd);
+  if (length >= MAX_RECV_BUF_LEN) {
+    printf("ERROR: Received length (%u) exceeds maximum (%u)\n", length, MAX_RECV_BUF_LEN);
+    disconnectClient(&client_fd, -1);
+    recv_count = 0;
+    return 0;
+  }
+  return recv_all(client_fd, recv_buffer, length, false);
+}
+
 // Reads a networked string into recv_buffer
 void readString (int client_fd) {
+  recv_count = readLengthPrefixedData(client_fd);
+  recv_buffer[recv_count] = '\0';
+}
+// Reads a networked string of up to N bytes into recv_buffer
+void readStringN (int client_fd, uint32_t max_length) {
+  // Forward to readString if max length is invalid
+  if (max_length >= MAX_RECV_BUF_LEN) {
+    readString(client_fd);
+    return;
+  }
+  // Attempt to read full string within maximum
   uint32_t length = readVarInt(client_fd);
-  recv_count = recv_all(client_fd, recv_buffer, length, false);
+  if (max_length > length) {
+    recv_count = recv_all(client_fd, recv_buffer, length, false);
+    recv_buffer[recv_count] = '\0';
+    return;
+  }
+  // Read string up to maximum, dump the rest
+  recv_count = recv_all(client_fd, recv_buffer, max_length, false);
   recv_buffer[recv_count] = '\0';
+  uint8_t dummy;
+  for (uint32_t i = max_length; i < length; i ++) {
+    recv_all(client_fd, &dummy, 1, false);
+  }
 }
 
 uint32_t fast_rand () {