]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/Ip6Dxe/Ip6Option.c
NetworkPkg/Ip6Dxe: Improve Neightbor Discovery message validation.
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6Option.c
index 4d92a852dc864757aa8d3f4b05acaa58740d0c3e..6b4b029d14791c1643ed607fb7775d4c0745da2c 100644 (file)
@@ -129,45 +129,74 @@ Ip6IsNDOptionValid (
   IN UINT16                 OptionLen\r
   )\r
 {\r
-  UINT16                    Offset;\r
-  UINT8                     OptionType;\r
+  UINT32                    Offset;\r
   UINT16                    Length;\r
+  IP6_OPTION_HEADER         *OptionHeader;\r
+\r
+  if (Option == NULL) {\r
+    ASSERT (Option != NULL);\r
+    return FALSE;\r
+  }\r
 \r
   Offset = 0;\r
 \r
-  while (Offset < OptionLen) {\r
-    OptionType = *(Option + Offset);\r
-     Length    = (UINT16) (*(Option + Offset + 1) * 8);\r
+  //\r
+  // RFC 4861 states that Neighbor Discovery packet can contain zero or more\r
+  // options. Start processing the options if at least Type + Length fields\r
+  // fit within the input buffer.\r
+  //\r
+  while (Offset + sizeof (IP6_OPTION_HEADER) - 1 < OptionLen) {\r
+    OptionHeader  = (IP6_OPTION_HEADER*) (Option + Offset);\r
+    Length        = (UINT16) OptionHeader->Length * 8;\r
 \r
-    switch (OptionType) {\r
+    switch (OptionHeader->Type) {\r
     case Ip6OptionPrefixInfo:\r
       if (Length != 32) {\r
         return FALSE;\r
       }\r
-\r
       break;\r
 \r
     case Ip6OptionMtu:\r
       if (Length != 8) {\r
         return FALSE;\r
       }\r
-\r
       break;\r
 \r
     default:\r
-      //\r
-      // Check the length of Ip6OptionEtherSource, Ip6OptionEtherTarget, and\r
-      // Ip6OptionRedirected here. For unrecognized options, silently ignore\r
-      // and continue processing the message.\r
-      //\r
+      // RFC 4861 states that Length field cannot be 0.\r
       if (Length == 0) {\r
         return FALSE;\r
       }\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Check whether recognized options are within the input buffer's scope.\r
+    //\r
+    switch (OptionHeader->Type) {\r
+    case Ip6OptionEtherSource:\r
+    case Ip6OptionEtherTarget:\r
+    case Ip6OptionPrefixInfo:\r
+    case Ip6OptionRedirected:\r
+    case Ip6OptionMtu:\r
+      if (Offset + Length > (UINT32) OptionLen) {\r
+        return FALSE;\r
+      }\r
+      break;\r
 \r
+    default:\r
+      //\r
+      // Unrecognized options can be either valid (but unused) or invalid\r
+      // (garbage in between or right after valid options). Silently ignore.\r
+      //\r
       break;\r
     }\r
 \r
-    Offset = (UINT16) (Offset + Length);\r
+    //\r
+    // Advance to the next option.\r
+    // Length already considers option header's Type + Length.\r
+    //\r
+    Offset += Length;\r
   }\r
 \r
   return TRUE;\r