Parcourir la source

[2749] Check sizes in memory access functions in io_utilities.h

Mukund Sivaraman il y a 11 ans
Parent
commit
d58433297e
2 fichiers modifiés avec 57 ajouts et 8 suppressions
  1. 33 4
      src/lib/util/io_utilities.h
  2. 24 4
      src/lib/util/tests/io_utilities_unittest.cc

+ 33 - 4
src/lib/util/io_utilities.h

@@ -15,6 +15,7 @@
 #ifndef IO_UTILITIES_H
 #define IO_UTILITIES_H
 
+#include <exceptions/exceptions.h>
 #include <cstddef>
 
 namespace isc {
@@ -28,10 +29,17 @@ namespace util {
 /// \param buffer Data buffer at least two bytes long of which the first two
 ///        bytes are assumed to represent a 16-bit integer in network-byte
 ///        order.
+/// \param length Length of the data buffer.
 ///
 /// \return Value of 16-bit integer
 inline uint16_t
-readUint16(const void* buffer) {
+readUint16(const void* buffer, size_t length) {
+    if (length < sizeof (uint16_t)) {
+        isc_throw(isc::OutOfRange,
+                  "Length (" << length << ") of buffer is insufficient " <<
+                  "to read a uint16_t");
+    }
+
     const uint8_t* byte_buffer = static_cast<const uint8_t*>(buffer);
 
     uint16_t result = (static_cast<uint16_t>(byte_buffer[0])) << 8;
@@ -48,10 +56,17 @@ readUint16(const void* buffer) {
 /// \param value 16-bit value to convert
 /// \param buffer Data buffer at least two bytes long into which the 16-bit
 ///        value is written in network-byte order.
+/// \param length Length of the data buffer.
 ///
 /// \return pointer to the next byte after stored value
 inline uint8_t*
-writeUint16(uint16_t value, void* buffer) {
+writeUint16(uint16_t value, void* buffer, size_t length) {
+    if (length < sizeof (uint16_t)) {
+        isc_throw(isc::OutOfRange,
+                  "Length (" << length << ") of buffer is insufficient " <<
+                  "to write a uint16_t");
+    }
+
     uint8_t* byte_buffer = static_cast<uint8_t*>(buffer);
 
     byte_buffer[0] = static_cast<uint8_t>((value & 0xff00U) >> 8);
@@ -65,10 +80,17 @@ writeUint16(uint16_t value, void* buffer) {
 /// \param buffer Data buffer at least four bytes long of which the first four
 ///        bytes are assumed to represent a 32-bit integer in network-byte
 ///        order.
+/// \param length Length of the data buffer.
 ///
 /// \return Value of 32-bit unsigned integer
 inline uint32_t
-readUint32(const uint8_t* buffer) {
+readUint32(const uint8_t* buffer, size_t length) {
+    if (length < sizeof (uint32_t)) {
+        isc_throw(isc::OutOfRange,
+                  "Length (" << length << ") of buffer is insufficient " <<
+                  "to read a uint32_t");
+    }
+
     const uint8_t* byte_buffer = static_cast<const uint8_t*>(buffer);
 
     uint32_t result = (static_cast<uint32_t>(byte_buffer[0])) << 24;
@@ -84,10 +106,17 @@ readUint32(const uint8_t* buffer) {
 /// \param value 32-bit value to convert
 /// \param buffer Data buffer at least four bytes long into which the 32-bit
 ///        value is written in network-byte order.
+/// \param length Length of the data buffer.
 ///
 /// \return pointer to the next byte after stored value
 inline uint8_t*
-writeUint32(uint32_t value, uint8_t* buffer) {
+writeUint32(uint32_t value, uint8_t* buffer, size_t length) {
+    if (length < sizeof (uint32_t)) {
+        isc_throw(isc::OutOfRange,
+                  "Length (" << length << ") of buffer is insufficient " <<
+                  "to write a uint32_t");
+    }
+
     uint8_t* byte_buffer = static_cast<uint8_t*>(buffer);
 
     byte_buffer[0] = static_cast<uint8_t>((value & 0xff000000U) >> 24);

+ 24 - 4
src/lib/util/tests/io_utilities_unittest.cc

@@ -42,11 +42,15 @@ TEST(asioutil, readUint16) {
             data[0] = i8;
             data[1] = j8;
             buffer.setPosition(0);
-            EXPECT_EQ(buffer.readUint16(), readUint16(data));
+            EXPECT_EQ(buffer.readUint16(), readUint16(data, sizeof (data)));
         }
     }
 }
 
+TEST(asioutil, readUint16OutOfRange) {
+    uint8_t data;
+    EXPECT_THROW(readUint16(&data, sizeof (data)), isc::OutOfRange);
+}
 
 TEST(asioutil, writeUint16) {
 
@@ -64,7 +68,7 @@ TEST(asioutil, writeUint16) {
         buffer.writeUint16(i16);
 
         // ... and the test data
-        writeUint16(i16, test);
+        writeUint16(i16, test, sizeof (test));
 
         // ... and compare
         const uint8_t* ref = static_cast<const uint8_t*>(buffer.getData());
@@ -73,6 +77,12 @@ TEST(asioutil, writeUint16) {
     }
 }
 
+TEST(asioutil, writeUint16OutOfRange) {
+    uint16_t i16 = 42;
+    uint8_t data;
+    EXPECT_THROW(writeUint16(i16, &data, sizeof (data)), isc::OutOfRange);
+}
+
 // test data shared amount readUint32 and writeUint32 tests
 const static uint32_t test32[] = {
     0,
@@ -93,11 +103,15 @@ TEST(asioutil, readUint32) {
             uint32_t tmp = htonl(test32[i]);
             memcpy(&data[offset], &tmp, sizeof(uint32_t));
 
-            EXPECT_EQ(test32[i], readUint32(&data[offset]));
+            EXPECT_EQ(test32[i], readUint32(&data[offset], sizeof (uint32_t)));
         }
     }
 }
 
+TEST(asioutil, readUint32OutOfRange) {
+    uint8_t data[3];
+    EXPECT_THROW(readUint32(data, sizeof (data)), isc::OutOfRange);
+}
 
 TEST(asioutil, writeUint32) {
     uint8_t data[8];
@@ -107,7 +121,7 @@ TEST(asioutil, writeUint32) {
     // it 4 times.
     for (int offset=0; offset < 4; offset++) {
         for (int i=0; i < sizeof(test32)/sizeof(uint32_t); i++) {
-            uint8_t* ptr = writeUint32(test32[i], &data[offset]);
+            uint8_t* ptr = writeUint32(test32[i], &data[offset], sizeof (uint32_t));
 
             EXPECT_EQ(&data[offset]+sizeof(uint32_t), ptr);
 
@@ -117,3 +131,9 @@ TEST(asioutil, writeUint32) {
         }
     }
 }
+
+TEST(asioutil, writeUint32OutOfRange) {
+    uint32_t i32 = 28;
+    uint8_t data[3];
+    EXPECT_THROW(writeUint32(i32, data, sizeof (data)), isc::OutOfRange);
+}