staging: rtl8192u: Avoid field-overflowing memcpy()
authorKees Cook <keescook@chromium.org>
Fri, 6 Aug 2021 20:12:07 +0000 (13:12 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 10 Aug 2021 10:09:35 +0000 (12:09 +0200)
In preparation for FORTIFY_SOURCE performing compile-time and run-time
field bounds checking for memcpy(), memmove(), and memset(), avoid
intentionally writing across neighboring fields.

Split the 3 addr memcpy() into 3 memcpy() calls so the compiler doesn't
think an overflowing memcpy() happens against the addr1 field (the
neighbors are intended to be copied as well).

ieee80211_read_qos_param_element() copies a struct ieee80211_info_element
into a struct ieee80211_qos_information_element, but is actually wanting to
copy into the larger struct ieee80211_qos_parameter_info (the contents of
ac_params_record[] is later examined). Refactor the routine to perform
centralized checks, and copy the entire contents directly (since the id
and len members match the elementID and length members):

struct ieee80211_info_element {
        u8 id;
        u8 len;
        u8 data[];
} __packed;

struct ieee80211_qos_information_element {
        u8 elementID;
        u8 length;
        u8 qui[QOS_OUI_LEN];
        u8 qui_type;
        u8 qui_subtype;
        u8 version;
        u8 ac_info;
} __packed;

struct ieee80211_qos_parameter_info {
        struct ieee80211_qos_information_element info_element;
        u8 reserved;
        struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
} __packed;

Additionally replace old-style zero-element arrays with flexible arrays.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Pascal Terjan <pterjan@google.com>
Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Cc: devel@driverdev.osuosl.org
Signed-off-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20210806201208.2871467-1-keescook@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/rtl8192u/ieee80211/ieee80211.h
drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c

index 7903c777a41781dd08a9f30ab292535500a06920..15207dc1f5c5d93de1997b99152a2ccad601c7c0 100644 (file)
@@ -303,7 +303,7 @@ struct ieee_param {
                struct {
                        u32 len;
                        u8 reserved[32];
-                       u8 data[0];
+                       u8 data[];
                } wpa_ie;
                struct{
                        int command;
@@ -316,7 +316,7 @@ struct ieee_param {
                        u8 idx;
                        u8 seq[8]; /* sequence counter (set: RX, get: TX) */
                        u16 key_len;
-                       u8 key[0];
+                       u8 key[];
                } crypt;
        } u;
 };
index c241cf484023a49861a8947f589424432a89ee26..ccff385cf1f8f74ebd8ad1379b577db9e3307136 100644 (file)
@@ -141,7 +141,9 @@ static int ccmp_init_iv_and_aad(struct rtl_80211_hdr_4addr *hdr,
        pos = (u8 *)hdr;
        aad[0] = pos[0] & 0x8f;
        aad[1] = pos[1] & 0xc7;
-       memcpy(aad + 2, hdr->addr1, 3 * ETH_ALEN);
+       memcpy(&aad[2], &hdr->addr1, ETH_ALEN);
+       memcpy(&aad[8], &hdr->addr2, ETH_ALEN);
+       memcpy(&aad[14], &hdr->addr3, ETH_ALEN);
        pos = (u8 *)&hdr->seq_ctl;
        aad[20] = pos[0] & 0x0f;
        aad[21] = 0; /* all bits masked */
index b0e01ee65f7f8b10d28694866b4153f92349c560..b58e75932ecd5e28e302c7f955a68fafb4e4507b 100644 (file)
@@ -1310,7 +1310,8 @@ static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
 static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element
                                     *info_element, int sub_type)
 {
-
+       if (info_element->elementID != QOS_ELEMENT_ID)
+               return -1;
        if (info_element->qui_subtype != sub_type)
                return -1;
        if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
@@ -1327,27 +1328,18 @@ static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element
 /*
  * Parse a QoS parameter element
  */
-static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
-                                           *element_param, struct ieee80211_info_element
-                                           *info_element)
+static int ieee80211_read_qos_param_element(
+               struct ieee80211_qos_parameter_info *element_param,
+               struct ieee80211_info_element *info_element)
 {
-       int ret = 0;
-       u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2;
+       size_t size = sizeof(*element_param);
 
-       if (!info_element || !element_param)
+       if (!element_param || !info_element || info_element->len != size - 2)
                return -1;
 
-       if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) {
-               memcpy(element_param->info_element.qui, info_element->data,
-                      info_element->len);
-               element_param->info_element.elementID = info_element->id;
-               element_param->info_element.length = info_element->len;
-       } else
-               ret = -1;
-       if (ret == 0)
-               ret = ieee80211_verify_qos_info(&element_param->info_element,
-                                               QOS_OUI_PARAM_SUB_TYPE);
-       return ret;
+       memcpy(element_param, info_element, size);
+       return ieee80211_verify_qos_info(&element_param->info_element,
+                                        QOS_OUI_PARAM_SUB_TYPE);
 }
 
 /*
@@ -1357,26 +1349,13 @@ static int ieee80211_read_qos_info_element(
                struct ieee80211_qos_information_element *element_info,
                struct ieee80211_info_element *info_element)
 {
-       int ret = 0;
-       u16 size = sizeof(struct ieee80211_qos_information_element) - 2;
+       size_t size = sizeof(*element_info);
 
-       if (!element_info)
+       if (!element_info || !info_element || info_element->len != size - 2)
                return -1;
-       if (!info_element)
-               return -1;
-
-       if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) {
-               memcpy(element_info->qui, info_element->data,
-                      info_element->len);
-               element_info->elementID = info_element->id;
-               element_info->length = info_element->len;
-       } else
-               ret = -1;
 
-       if (ret == 0)
-               ret = ieee80211_verify_qos_info(element_info,
-                                               QOS_OUI_INFO_SUB_TYPE);
-       return ret;
+       memcpy(element_info, info_element, size);
+       return ieee80211_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE);
 }