chiark / gitweb /
sd-rtnl: message - protect against SEGFAULT when reading messages
[elogind.git] / src / libsystemd / sd-rtnl / rtnl-message.c
index 7ea68f18ae4fed56a8420abf8d0ac3acd11b6926..23c8099c30dce16fe732b80ee2b3edcec512a170 100644 (file)
@@ -295,6 +295,12 @@ int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
         return 0;
 }
 
+int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
+        assert_return(m, -EINVAL);
+
+        return !m->hdr->nlmsg_pid;
+}
+
 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
         struct ifinfomsg *ifi;
 
@@ -801,6 +807,8 @@ int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data)
 }
 
 int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
+        struct rtattr *rta;
+
         assert_return(m, -EINVAL);
         assert_return(m->sealed, -EPERM);
         assert_return(data, -EINVAL);
@@ -810,9 +818,11 @@ int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **d
         if(!m->rta_offset_tb[type])
                 return -ENODATA;
 
-        *data = RTA_DATA((struct rtattr *)((uint8_t *) m->hdr + m->rta_offset_tb[type]));
+        rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[type]);
 
-        return 0;
+        *data = RTA_DATA(rta);
+
+        return RTA_PAYLOAD(rta);
 }
 
 int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) {
@@ -822,8 +832,10 @@ int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **
         assert_return(data, -EINVAL);
 
         r = rtnl_message_read_internal(m, type, &attr_data);
-        if(r < 0)
+        if (r < 0)
                 return r;
+        else if (strnlen(attr_data, r) >= (size_t) r)
+                return -EIO;
 
         *data = (char *) attr_data;
 
@@ -837,8 +849,10 @@ int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *da
         assert_return(data, -EINVAL);
 
         r = rtnl_message_read_internal(m, type, &attr_data);
-        if(r < 0)
+        if (r < 0)
                 return r;
+        else if ((size_t) r < sizeof(uint8_t))
+                return -EIO;
 
         *data = *(uint8_t *) attr_data;
 
@@ -852,8 +866,10 @@ int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *
         assert_return(data, -EINVAL);
 
         r = rtnl_message_read_internal(m, type, &attr_data);
-        if(r < 0)
+        if (r < 0)
                 return r;
+        else if ((size_t) r < sizeof(uint16_t))
+                return -EIO;
 
         *data = *(uint16_t *) attr_data;
 
@@ -867,8 +883,10 @@ int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *
         assert_return(data, -EINVAL);
 
         r = rtnl_message_read_internal(m, type, &attr_data);
-        if(r < 0)
+        if (r < 0)
                 return r;
+        else if ((size_t)r < sizeof(uint32_t))
+                return -EIO;
 
         *data = *(uint32_t *) attr_data;
 
@@ -882,8 +900,10 @@ int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, str
         assert_return(data, -EINVAL);
 
         r = rtnl_message_read_internal(m, type, &attr_data);
-        if(r < 0)
+        if (r < 0)
                 return r;
+        else if ((size_t)r < sizeof(struct ether_addr))
+                return -EIO;
 
         memcpy(data, attr_data, sizeof(struct ether_addr));
 
@@ -897,8 +917,10 @@ int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct
         assert_return(data, -EINVAL);
 
         r = rtnl_message_read_internal(m, type, &attr_data);
-        if(r < 0)
+        if (r < 0)
                 return r;
+        else if ((size_t)r < sizeof(struct in_addr))
+                return -EIO;
 
         memcpy(data, attr_data, sizeof(struct in_addr));
 
@@ -1010,7 +1032,7 @@ int rtnl_message_parse(sd_rtnl_message *m,
         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
                 type = rta->rta_type;
 
-                if (type < max && !tb[type])
+                if (type <= max)
                         tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
         }