nl80211: validate beacon head
authorJohannes Berg <johannes.berg@intel.com>
Fri, 20 Sep 2019 19:54:17 +0000 (21:54 +0200)
committerStricted <info@stricted.net>
Fri, 16 Oct 2020 20:56:07 +0000 (20:56 +0000)
commit f88eb7c0d002a67ef31aeb7850b42ff69abc46dc upstream.

We currently don't validate the beacon head, i.e. the header,
fixed part and elements that are to go in front of the TIM
element. This means that the variable elements there can be
malformed, e.g. have a length exceeding the buffer size, but
most downstream code from this assumes that this has already
been checked.

Add the necessary checks to the netlink policy.

Mot-CRs-fixed: (CR)
CVE-Fixed: CVE-2019-16746
Bug: 145728612

Cc: stable@vger.kernel.org
Fixes: ed1b6cc7f80f ("cfg80211/nl80211: add beacon settings")
Link: https://lore.kernel.org/r/1569009255-I7ac7fbe9436e9d8733439eab8acbbd35e55c74ef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Jignesh Patel <jignesh@motorola.com>
Change-Id: Icab1d8731e6c38b3ca2dafb45cf7429eb72e12f0
Reviewed-on: https://gerrit.mot.com/1669954
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com>
Submit-Approved: Jira Key
(cherry picked from commit 7623ecab677c53ce07dad4783d4786e255017df8)

net/wireless/nl80211.c

index 108db3b84bd5b6330f14d958cbae26a677bf02e0..28640961d08c07b20484962f984a090954ef1643 100644 (file)
@@ -199,6 +199,38 @@ cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
        return __cfg80211_rdev_from_attrs(netns, info->attrs);
 }
 
+static int validate_beacon_head(const struct nlattr *attr,
+                               struct netlink_ext_ack *extack)
+{
+       const u8 *data = nla_data(attr);
+       unsigned int len = nla_len(attr);
+       const struct element *elem;
+       const struct ieee80211_mgmt *mgmt = (void *)data;
+       unsigned int fixedlen = offsetof(struct ieee80211_mgmt,
+                                        u.beacon.variable);
+
+       if (len < fixedlen)
+               goto err;
+
+       if (ieee80211_hdrlen(mgmt->frame_control) !=
+           offsetof(struct ieee80211_mgmt, u.beacon))
+               goto err;
+
+       data += fixedlen;
+       len -= fixedlen;
+
+       for_each_element(elem, data, len) {
+               /* nothing */
+       }
+
+       if (for_each_element_completed(elem, data, len))
+               return 0;
+
+err:
+       NL_SET_ERR_MSG_ATTR(extack, attr, "malformed beacon head");
+       return -EINVAL;
+}
+
 /* policy for the attributes */
 static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@@ -3739,6 +3771,12 @@ static int nl80211_parse_beacon(struct nlattr *attrs[],
        memset(bcn, 0, sizeof(*bcn));
 
        if (attrs[NL80211_ATTR_BEACON_HEAD]) {
+               int ret = validate_beacon_head(attrs[NL80211_ATTR_BEACON_HEAD],
+                                              NULL);
+
+               if (ret)
+                       return ret;
+
                bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
                bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
                if (!bcn->head_len)