FruDevice: Verify offset overlap

Checking each field area offset if they are overlapping with
other field area offset.

Signed-off-by: Vijay Khemka <vijaykhemkalinux@gmail.com>
Change-Id: Id0fcb704ac20083fae1760ec7d6e6cb559442526
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index a48854c..ffae574 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -789,6 +789,81 @@
     }
 }
 
+/* This function verifies for other offsets to check if they are not
+ * falling under other field area
+ *
+ * fruBytes:    Start of Fru data
+ * currentArea: Index of current area offset to be compared against all area
+ *              offset and it is a multiple of 8 bytes as per specification
+ * len:         Length of current area space and it is a multiple of 8 bytes
+ *              as per specification
+ */
+static bool verifyOffset(const std::vector<uint8_t>& fruBytes,
+                         fruAreas currentArea, uint8_t len)
+{
+
+    unsigned int fruBytesSize = fruBytes.size();
+
+    // check if Fru data has at least 8 byte header
+    if (fruBytesSize <= fruBlockSize)
+    {
+        std::cerr << "Error: trying to parse empty FRU\n";
+        return false;
+    }
+
+    // Check range of passed currentArea value
+    if (currentArea > fruAreas::fruAreaMultirecord)
+    {
+        std::cerr << "Error: Fru area is out of range\n";
+        return false;
+    }
+
+    unsigned int currentAreaIndex = getHeaderAreaFieldOffset(currentArea);
+    if (currentAreaIndex > fruBytesSize)
+    {
+        std::cerr << "Error: Fru area index is out of range\n";
+        return false;
+    }
+
+    unsigned int start = fruBytes[currentAreaIndex];
+    unsigned int end = start + len;
+
+    /* Verify each offset within the range of start and end */
+    for (fruAreas area = fruAreas::fruAreaInternal;
+         area <= fruAreas::fruAreaMultirecord; ++area)
+    {
+        // skip the current offset
+        if (area == currentArea)
+        {
+            continue;
+        }
+
+        unsigned int areaIndex = getHeaderAreaFieldOffset(area);
+        if (areaIndex > fruBytesSize)
+        {
+            std::cerr << "Error: Fru area index is out of range\n";
+            return false;
+        }
+
+        unsigned int areaOffset = fruBytes[areaIndex];
+        // if areaOffset is 0 means this area is not available so skip
+        if (areaOffset == 0)
+        {
+            continue;
+        }
+
+        // check for overlapping of current offset with given areaoffset
+        if (areaOffset == start || (areaOffset > start && areaOffset < end))
+        {
+            std::cerr << getFruAreaName(currentArea)
+                      << " offset is overlapping with " << getFruAreaName(area)
+                      << " offset\n";
+            return false;
+        }
+    }
+    return true;
+}
+
 resCodes formatFRU(const std::vector<uint8_t>& fruBytes,
                    boost::container::flat_map<std::string, std::string>& result)
 {
@@ -828,6 +903,15 @@
             return resCodes::resErr;
         }
         ++fruBytesIter;
+
+        /* Verify other area offset for overlap with current area by passing
+         * length of current area offset pointed by *fruBytesIter
+         */
+        if (!verifyOffset(fruBytes, area, *fruBytesIter))
+        {
+            return resCodes::resErr;
+        }
+
         uint8_t fruAreaSize = *fruBytesIter * fruBlockSize;
         std::vector<uint8_t>::const_iterator fruBytesIterEndArea =
             fruBytes.begin() + offset + fruAreaSize - 1;