]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: make size verifier in sd_netlink_message_read_xyz() stricter
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 10 Oct 2024 03:45:39 +0000 (12:45 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 10 Oct 2024 17:38:16 +0000 (02:38 +0900)
Also, fill remaining output buffer with zero, for safety.

src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/test-netlink.c

index e064c53486e9ac8040446818ffbe6954f45bcb23..3df032744447948becdfdeaaff84062ae3e173ca 100644 (file)
@@ -754,25 +754,55 @@ static int netlink_message_read_internal(
         return RTA_PAYLOAD(rta);
 }
 
-int sd_netlink_message_read(sd_netlink_message *m, uint16_t attr_type, size_t size, void *ret) {
+static int netlink_message_read_impl(
+                sd_netlink_message *m,
+                uint16_t attr_type,
+                bool strict,
+                NLAType type,
+                size_t size,
+                void *ret,
+                bool *ret_net_byteorder) {
+
+        bool net_byteorder;
         void *attr_data;
         int r;
 
-        assert_return(m, -EINVAL);
+        assert(m);
 
-        r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
+        if (type >= 0) {
+                r = message_attribute_has_type(m, NULL, attr_type, type);
+                if (r < 0)
+                        return r;
+        }
+
+        r = netlink_message_read_internal(m, attr_type, &attr_data, &net_byteorder);
         if (r < 0)
                 return r;
 
         if ((size_t) r > size)
                 return -ENOBUFS;
 
+        if (strict && (size_t) r != size)
+                return -EIO;
+
         if (ret)
-                memcpy(ret, attr_data, r);
+                memzero(mempcpy(ret, attr_data, r), size - (size_t) r);
+
+        if (ret_net_byteorder)
+                *ret_net_byteorder = net_byteorder;
 
         return r;
 }
 
+int sd_netlink_message_read(sd_netlink_message *m, uint16_t attr_type, size_t size, void *ret) {
+        assert_return(m, -EINVAL);
+
+        return netlink_message_read_impl(
+                        m, attr_type, /* strict = */ false,
+                        _NETLINK_TYPE_INVALID, size,
+                        ret, /* ret_net_byteorder = */ NULL);
+}
+
 int sd_netlink_message_read_data(sd_netlink_message *m, uint16_t attr_type, size_t *ret_size, void **ret_data) {
         void *attr_data;
         int r;
@@ -836,227 +866,145 @@ int sd_netlink_message_read_string(sd_netlink_message *m, uint16_t attr_type, co
 }
 
 int sd_netlink_message_read_u8(sd_netlink_message *m, uint16_t attr_type, uint8_t *ret) {
-        void *attr_data;
-        int r;
-
         assert_return(m, -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U8);
-        if (r < 0)
-                return r;
-
-        r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
-        if (r < 0)
-                return r;
-
-        if ((size_t) r < sizeof(uint8_t))
-                return -EIO;
-
-        if (ret)
-                *ret = *(uint8_t *) attr_data;
-
-        return 0;
+        return netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_U8, sizeof(uint8_t),
+                        ret, /* ret_net_byteorder = */ NULL);
 }
 
 int sd_netlink_message_read_u16(sd_netlink_message *m, uint16_t attr_type, uint16_t *ret) {
-        void *attr_data;
         bool net_byteorder;
+        uint16_t u;
         int r;
 
         assert_return(m, -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U16);
+        r = netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_U16, sizeof(uint16_t),
+                        ret ? &u : NULL, &net_byteorder);
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, attr_type, &attr_data, &net_byteorder);
-        if (r < 0)
-                return r;
-
-        if ((size_t) r < sizeof(uint16_t))
-                return -EIO;
-
-        if (ret) {
-                if (net_byteorder)
-                        *ret = be16toh(*(uint16_t *) attr_data);
-                else
-                        *ret = *(uint16_t *) attr_data;
-        }
+        if (ret)
+                *ret = net_byteorder ? be16toh(u) : u;
 
         return 0;
 }
 
 int sd_netlink_message_read_u32(sd_netlink_message *m, uint16_t attr_type, uint32_t *ret) {
-        void *attr_data;
         bool net_byteorder;
+        uint32_t u;
         int r;
 
         assert_return(m, -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U32);
-        if (r < 0)
-                return r;
-
-        r = netlink_message_read_internal(m, attr_type, &attr_data, &net_byteorder);
+        r = netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_U32, sizeof(uint32_t),
+                        ret ? &u : NULL, &net_byteorder);
         if (r < 0)
                 return r;
 
-        if ((size_t) r < sizeof(uint32_t))
-                return -EIO;
-
-        if (ret) {
-                if (net_byteorder)
-                        *ret = be32toh(*(uint32_t *) attr_data);
-                else
-                        *ret = *(uint32_t *) attr_data;
-        }
+        if (ret)
+                *ret = net_byteorder ? be32toh(u) : u;
 
         return 0;
 }
 
 int sd_netlink_message_read_u64(sd_netlink_message *m, uint16_t attr_type, uint64_t *ret) {
-        void *attr_data;
         bool net_byteorder;
+        uint64_t u;
         int r;
 
         assert_return(m, -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U64);
-        if (r < 0)
-                return r;
-
-        r = netlink_message_read_internal(m, attr_type, &attr_data, &net_byteorder);
+        r = netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_U64, sizeof(uint64_t),
+                        ret ? &u : NULL, &net_byteorder);
         if (r < 0)
                 return r;
 
-        if ((size_t) r < sizeof(uint64_t))
-                return -EIO;
-
-        if (ret) {
-                if (net_byteorder)
-                        *ret = be64toh(*(uint64_t *) attr_data);
-                else
-                        *ret = *(uint64_t *) attr_data;
-        }
+        if (ret)
+                *ret = net_byteorder ? be64toh(u) : u;
 
         return 0;
 }
 
 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, uint16_t attr_type, struct ether_addr *ret) {
-        void *attr_data;
-        int r;
-
         assert_return(m, -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_ETHER_ADDR);
-        if (r < 0)
-                return r;
-
-        r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
-        if (r < 0)
-                return r;
-
-        if ((size_t) r < sizeof(struct ether_addr))
-                return -EIO;
-
-        if (ret)
-                memcpy(ret, attr_data, sizeof(struct ether_addr));
-
-        return 0;
+        return netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_ETHER_ADDR, sizeof(struct ether_addr),
+                        ret, /* ret_net_byteorder = */ NULL);
 }
 
 int netlink_message_read_hw_addr(sd_netlink_message *m, uint16_t attr_type, struct hw_addr_data *ret) {
-        void *attr_data;
         int r;
 
         assert_return(m, -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_ETHER_ADDR);
-        if (r < 0)
-                return r;
-
-        r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
+        r = netlink_message_read_impl(
+                        m, attr_type, /* strict = */ false,
+                        NETLINK_TYPE_ETHER_ADDR, HW_ADDR_MAX_SIZE,
+                        ret ? ret->bytes : NULL, /* ret_net_byteorder = */ NULL);
         if (r < 0)
                 return r;
 
-        if (r > HW_ADDR_MAX_SIZE)
-                return -EIO;
-
-        if (ret) {
-                memcpy(ret->bytes, attr_data, r);
+        if (ret)
                 ret->length = r;
-        }
 
-        return 0;
+        return r;
 }
 
 int sd_netlink_message_read_cache_info(sd_netlink_message *m, uint16_t attr_type, struct ifa_cacheinfo *ret) {
-        void *attr_data;
-        int r;
-
         assert_return(m, -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_CACHE_INFO);
-        if (r < 0)
-                return r;
-
-        r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
-        if (r < 0)
-                return r;
-
-        if ((size_t) r < sizeof(struct ifa_cacheinfo))
-                return -EIO;
-
-        if (ret)
-                memcpy(ret, attr_data, sizeof(struct ifa_cacheinfo));
-
-        return 0;
+        return netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_CACHE_INFO, sizeof(struct ifa_cacheinfo),
+                        ret, /* ret_net_byteorder = */ NULL);
 }
 
 int netlink_message_read_in_addr_union(sd_netlink_message *m, uint16_t attr_type, int family, union in_addr_union *ret) {
-        void *attr_data;
         int r;
 
         assert_return(m, -EINVAL);
         assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
 
-        r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_IN_ADDR);
-        if (r < 0)
-                return r;
-
-        r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
+        r = netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_IN_ADDR, FAMILY_ADDRESS_SIZE(family),
+                        ret, /* ret_net_byteorder = */ NULL);
         if (r < 0)
                 return r;
 
-        if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
-                return -EIO;
-
         if (ret)
-                memcpy(ret, attr_data, FAMILY_ADDRESS_SIZE(family));
+                memzero((uint8_t*) ret + FAMILY_ADDRESS_SIZE(family), sizeof(union in_addr_union) - FAMILY_ADDRESS_SIZE(family));
 
-        return 0;
+        return r;
 }
 
 int sd_netlink_message_read_in_addr(sd_netlink_message *m, uint16_t attr_type, struct in_addr *ret) {
-        union in_addr_union u;
-        int r;
-
-        r = netlink_message_read_in_addr_union(m, attr_type, AF_INET, &u);
-        if (r >= 0 && ret)
-                *ret = u.in;
+        assert_return(m, -EINVAL);
 
-        return r;
+        return netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_IN_ADDR, sizeof(struct in_addr),
+                        ret, /* ret_net_byteorder = */ NULL);
 }
 
 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, uint16_t attr_type, struct in6_addr *ret) {
-        union in_addr_union u;
-        int r;
-
-        r = netlink_message_read_in_addr_union(m, attr_type, AF_INET6, &u);
-        if (r >= 0 && ret)
-                *ret = u.in6;
+        assert_return(m, -EINVAL);
 
-        return r;
+        return netlink_message_read_impl(
+                        m, attr_type, /* strict = */ true,
+                        NETLINK_TYPE_IN_ADDR, sizeof(struct in6_addr),
+                        ret, /* ret_net_byteorder = */ NULL);
 }
 
 int sd_netlink_message_has_flag(sd_netlink_message *m, uint16_t attr_type) {
index c58cfc07279bdc026496d3b4388de2108d2212e2..d51b7cf76bae3e1f311b0a20a5a4fceb80f9ef2f 100644 (file)
@@ -108,7 +108,7 @@ TEST(message_address) {
                 assert_se(sd_netlink_message_read_in_addr(reply, IFA_LOCAL, &in_data) >= 0);
                 assert_se(sd_netlink_message_read_in_addr(reply, IFA_ADDRESS, &in_data) >= 0);
                 assert_se(sd_netlink_message_read_string(reply, IFA_LABEL, &label) >= 0);
-                assert_se(sd_netlink_message_read_cache_info(reply, IFA_CACHEINFO, &cache) == 0);
+                assert_se(sd_netlink_message_read_cache_info(reply, IFA_CACHEINFO, &cache) >= 0);
         }
 }