Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1fc9b725 authored by Johannes Berg's avatar Johannes Berg
Browse files

cfg80211: prevent speculation on cfg80211_classify8021d() return



It's possible that the caller of cfg80211_classify8021d() uses the
value to index an array, like mac80211 in ieee80211_downgrade_queue().
Prevent speculation on the return value.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ff1bab1b
Loading
Loading
Loading
Loading
+24 −11
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
 * Copyright 2007-2009	Johannes Berg <johannes@sipsolutions.net>
 * Copyright 2013-2014  Intel Mobile Communications GmbH
 * Copyright 2017	Intel Deutschland GmbH
 * Copyright (C) 2018 Intel Corporation
 * Copyright (C) 2018-2019 Intel Corporation
 */
#include <linux/export.h>
#include <linux/bitops.h>
@@ -19,6 +19,7 @@
#include <linux/mpls.h>
#include <linux/gcd.h>
#include <linux/bitfield.h>
#include <linux/nospec.h>
#include "core.h"
#include "rdev-ops.h"

@@ -715,20 +716,25 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
{
	unsigned int dscp;
	unsigned char vlan_priority;
	unsigned int ret;

	/* skb->priority values from 256->263 are magic values to
	 * directly indicate a specific 802.1d priority.  This is used
	 * to allow 802.1d priority to be passed directly in from VLAN
	 * tags, etc.
	 */
	if (skb->priority >= 256 && skb->priority <= 263)
		return skb->priority - 256;
	if (skb->priority >= 256 && skb->priority <= 263) {
		ret = skb->priority - 256;
		goto out;
	}

	if (skb_vlan_tag_present(skb)) {
		vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK)
			>> VLAN_PRIO_SHIFT;
		if (vlan_priority > 0)
			return vlan_priority;
		if (vlan_priority > 0) {
			ret = vlan_priority;
			goto out;
		}
	}

	switch (skb->protocol) {
@@ -747,8 +753,9 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
		if (!mpls)
			return 0;

		return (ntohl(mpls->entry) & MPLS_LS_TC_MASK)
		ret = (ntohl(mpls->entry) & MPLS_LS_TC_MASK)
			>> MPLS_LS_TC_SHIFT;
		goto out;
	}
	case htons(ETH_P_80221):
		/* 802.21 is always network control traffic */
@@ -761,18 +768,24 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
		unsigned int i, tmp_dscp = dscp >> 2;

		for (i = 0; i < qos_map->num_des; i++) {
			if (tmp_dscp == qos_map->dscp_exception[i].dscp)
				return qos_map->dscp_exception[i].up;
			if (tmp_dscp == qos_map->dscp_exception[i].dscp) {
				ret = qos_map->dscp_exception[i].up;
				goto out;
			}
		}

		for (i = 0; i < 8; i++) {
			if (tmp_dscp >= qos_map->up[i].low &&
			    tmp_dscp <= qos_map->up[i].high)
				return i;
			    tmp_dscp <= qos_map->up[i].high) {
				ret = i;
				goto out;
			}
		}
	}

	return dscp >> 5;
	ret = dscp >> 5;
out:
	return array_index_nospec(ret, IEEE80211_NUM_TIDS);
}
EXPORT_SYMBOL(cfg80211_classify8021d);