util: Fix mac truncation

We don't want to allow MACs to be silently truncated.

Change-Id: I1d2771c481bccb30e957b829fd1db1e4db0dc051
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/util.cpp b/src/util.cpp
index c6aedde..7935ba6 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -27,6 +27,7 @@
 #include <stdexcept>
 #include <stdplus/raw.hpp>
 #include <string>
+#include <string_view>
 #include <variant>
 #include <xyz/openbmc_project/Common/error.hpp>
 
@@ -531,26 +532,42 @@
     return fromString(std::get<std::string>(value));
 }
 
-ether_addr fromString(stdplus::zstring_view str)
+static uint8_t decodeHex(std::string_view str)
 {
-    std::string genstr;
+    uint8_t ret;
+    auto res = std::from_chars(str.begin(), str.end(), ret, 16);
+    if (res.ptr != str.end() || res.ec != std::errc())
+    {
+        throw std::invalid_argument("Not hex");
+    }
+    return ret;
+}
 
-    // MAC address without colons
+ether_addr fromString(std::string_view str)
+{
+    ether_addr ret;
     if (str.size() == 12 && str.find(":") == str.npos)
     {
-        genstr =
-            fmt::format(FMT_COMPILE("{}:{}:{}:{}:{}:{}"), str.substr(0, 2),
-                        str.substr(2, 2), str.substr(4, 2), str.substr(6, 2),
-                        str.substr(8, 2), str.substr(10, 2));
-        str = genstr;
+        for (size_t i = 0; i < 6; ++i)
+        {
+            ret.ether_addr_octet[i] = decodeHex(str.substr(i * 2, 2));
+        }
     }
-
-    ether_addr addr;
-    if (ether_aton_r(str.c_str(), &addr) == nullptr)
+    else
     {
-        throw std::invalid_argument("Invalid MAC Address");
+        for (size_t i = 0; i < 5; ++i)
+        {
+            auto loc = str.find(":");
+            ret.ether_addr_octet[i] = decodeHex(str.substr(0, loc));
+            str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
+            if (str.empty())
+            {
+                throw std::invalid_argument("Missing mac data");
+            }
+        }
+        ret.ether_addr_octet[5] = decodeHex(str);
     }
-    return addr;
+    return ret;
 }
 
 std::string toString(const ether_addr& mac)
diff --git a/src/util.hpp b/src/util.hpp
index 8ca8b4b..dece269 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -9,7 +9,6 @@
 #include <optional>
 #include <sdbusplus/bus.hpp>
 #include <stdplus/zstring.hpp>
-#include <stdplus/zstring_view.hpp>
 #include <string>
 #include <string_view>
 #include <unordered_set>
@@ -45,7 +44,7 @@
  *  @returns A mac address in network byte order
  *  @throws std::runtime_error for bad mac
  */
-ether_addr fromString(stdplus::zstring_view str);
+ether_addr fromString(std::string_view str);
 
 /** @brief Converts the given mac address bytes into a string
  *  @param[in] mac - The mac address
diff --git a/test/test_util.cpp b/test/test_util.cpp
index dbf0a27..677b3f6 100644
--- a/test/test_util.cpp
+++ b/test/test_util.cpp
@@ -147,6 +147,13 @@
 {
     EXPECT_THROW(fromString("0x:00:00:00:00:00"), std::invalid_argument);
     EXPECT_THROW(fromString("00:00:00:00:00"), std::invalid_argument);
+    EXPECT_THROW(fromString("00:00:00:00:00:"), std::invalid_argument);
+    EXPECT_THROW(fromString("00:00:00:00::00"), std::invalid_argument);
+    EXPECT_THROW(fromString(":00:00:00:00:00"), std::invalid_argument);
+    EXPECT_THROW(fromString("00::00:00:00:00"), std::invalid_argument);
+    EXPECT_THROW(fromString(":::::"), std::invalid_argument);
+    EXPECT_THROW(fromString("00:0:0:0:0"), std::invalid_argument);
+    EXPECT_THROW(fromString("00:00:00:00:00:00:00"), std::invalid_argument);
     EXPECT_THROW(fromString(""), std::invalid_argument);
     EXPECT_THROW(fromString("123456789XYZ"), std::invalid_argument);
     EXPECT_THROW(fromString("123456789AB"), std::invalid_argument);