mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	Refresh all patches. The removed patches were integrated upstream. This contains fixes for CVE-2020-3702 1. These patches (ath, ath9k, mac80211) were included in kernel versions since 4.14.245 and 4.19.205. They fix security vulnerability CVE-2020-3702 [1] similar to KrØØk, which was found by ESET [2]. Thank you Josef Schlehofer for reporting this problem. [1] https://nvd.nist.gov/vuln/detail/CVE-2020-3702 [2] https://www.welivesecurity.com/2020/08/06/beyond-kr00k-even-more-wifi-chips-vulnerable-eavesdropping/ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
		
			
				
	
	
		
			399 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Carl Huang <cjhuang@codeaurora.org>
 | |
| Date: Thu, 3 Dec 2020 05:37:26 -0500
 | |
| Subject: [PATCH] nl80211: add common API to configure SAR power limitations
 | |
| 
 | |
| NL80211_CMD_SET_SAR_SPECS is added to configure SAR from
 | |
| user space. NL80211_ATTR_SAR_SPEC is used to pass the SAR
 | |
| power specification when used with NL80211_CMD_SET_SAR_SPECS.
 | |
| 
 | |
| Wireless driver needs to register SAR type, supported frequency
 | |
| ranges to wiphy, so user space can query it. The index in
 | |
| frequency range is used to specify which sub band the power
 | |
| limitation applies to. The SAR type is for compatibility, so later
 | |
| other SAR mechanism can be implemented without breaking the user
 | |
| space SAR applications.
 | |
| 
 | |
| Normal process is user space queries the SAR capability, and
 | |
| gets the index of supported frequency ranges and associates the
 | |
| power limitation with this index and sends to kernel.
 | |
| 
 | |
| Here is an example of message send to kernel:
 | |
| 8c 00 00 00 08 00 01 00 00 00 00 00 38 00 2b 81
 | |
| 08 00 01 00 00 00 00 00 2c 00 02 80 14 00 00 80
 | |
| 08 00 02 00 00 00 00 00 08 00 01 00 38 00 00 00
 | |
| 14 00 01 80 08 00 02 00 01 00 00 00 08 00 01 00
 | |
| 48 00 00 00
 | |
| 
 | |
| NL80211_CMD_SET_SAR_SPECS:  0x8c
 | |
| NL80211_ATTR_WIPHY:     0x01(phy idx is 0)
 | |
| NL80211_ATTR_SAR_SPEC:  0x812b (NLA_NESTED)
 | |
| NL80211_SAR_ATTR_TYPE:  0x00 (NL80211_SAR_TYPE_POWER)
 | |
| NL80211_SAR_ATTR_SPECS: 0x8002 (NLA_NESTED)
 | |
| freq range 0 power: 0x38 in 0.25dbm unit (14dbm)
 | |
| freq range 1 power: 0x48 in 0.25dbm unit (18dbm)
 | |
| 
 | |
| Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
 | |
| Reviewed-by: Brian Norris <briannorris@chromium.org>
 | |
| Reviewed-by: Abhishek Kumar <kuabhs@chromium.org>
 | |
| Link: https://lore.kernel.org/r/20201203103728.3034-2-cjhuang@codeaurora.org
 | |
| [minor edits, NLA parse cleanups]
 | |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 | |
| ---
 | |
| 
 | |
| --- a/include/net/cfg80211.h
 | |
| +++ b/include/net/cfg80211.h
 | |
| @@ -1737,6 +1737,54 @@ struct station_info {
 | |
|  	u8 connected_to_as;
 | |
|  };
 | |
|  
 | |
| +/**
 | |
| + * struct cfg80211_sar_sub_specs - sub specs limit
 | |
| + * @power: power limitation in 0.25dbm
 | |
| + * @freq_range_index: index the power limitation applies to
 | |
| + */
 | |
| +struct cfg80211_sar_sub_specs {
 | |
| +	s32 power;
 | |
| +	u32 freq_range_index;
 | |
| +};
 | |
| +
 | |
| +/**
 | |
| + * struct cfg80211_sar_specs - sar limit specs
 | |
| + * @type: it's set with power in 0.25dbm or other types
 | |
| + * @num_sub_specs: number of sar sub specs
 | |
| + * @sub_specs: memory to hold the sar sub specs
 | |
| + */
 | |
| +struct cfg80211_sar_specs {
 | |
| +	enum nl80211_sar_type type;
 | |
| +	u32 num_sub_specs;
 | |
| +	struct cfg80211_sar_sub_specs sub_specs[];
 | |
| +};
 | |
| +
 | |
| +
 | |
| +/**
 | |
| + * @struct cfg80211_sar_chan_ranges - sar frequency ranges
 | |
| + * @start_freq:  start range edge frequency
 | |
| + * @end_freq:    end range edge frequency
 | |
| + */
 | |
| +struct cfg80211_sar_freq_ranges {
 | |
| +	u32 start_freq;
 | |
| +	u32 end_freq;
 | |
| +};
 | |
| +
 | |
| +/**
 | |
| + * struct cfg80211_sar_capa - sar limit capability
 | |
| + * @type: it's set via power in 0.25dbm or other types
 | |
| + * @num_freq_ranges: number of frequency ranges
 | |
| + * @freq_ranges: memory to hold the freq ranges.
 | |
| + *
 | |
| + * Note: WLAN driver may append new ranges or split an existing
 | |
| + * range to small ones and then append them.
 | |
| + */
 | |
| +struct cfg80211_sar_capa {
 | |
| +	enum nl80211_sar_type type;
 | |
| +	u32 num_freq_ranges;
 | |
| +	const struct cfg80211_sar_freq_ranges *freq_ranges;
 | |
| +};
 | |
| +
 | |
|  #if IS_ENABLED(CPTCFG_CFG80211)
 | |
|  /**
 | |
|   * cfg80211_get_station - retrieve information about a given station
 | |
| @@ -4259,6 +4307,8 @@ struct cfg80211_ops {
 | |
|  				  struct cfg80211_tid_config *tid_conf);
 | |
|  	int	(*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev,
 | |
|  				    const u8 *peer, u8 tids);
 | |
| +	int	(*set_sar_specs)(struct wiphy *wiphy,
 | |
| +				 struct cfg80211_sar_specs *sar);
 | |
|  };
 | |
|  
 | |
|  /*
 | |
| @@ -5030,6 +5080,8 @@ struct wiphy {
 | |
|  
 | |
|  	u8 max_data_retry_count;
 | |
|  
 | |
| +	const struct cfg80211_sar_capa *sar_capa;
 | |
| +
 | |
|  	char priv[] __aligned(NETDEV_ALIGN);
 | |
|  };
 | |
|  
 | |
| --- a/net/wireless/nl80211.c
 | |
| +++ b/net/wireless/nl80211.c
 | |
| @@ -405,6 +405,18 @@ nl80211_unsol_bcast_probe_resp_policy[NL
 | |
|  						       .len = IEEE80211_MAX_DATA_LEN }
 | |
|  };
 | |
|  
 | |
| +static const struct nla_policy
 | |
| +sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = {
 | |
| +	[NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 },
 | |
| +	[NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 },
 | |
| +};
 | |
| +
 | |
| +static const struct nla_policy
 | |
| +sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
 | |
| +	[NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE),
 | |
| +	[NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
 | |
| +};
 | |
| +
 | |
|  static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 | |
|  	[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
 | |
|  	[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
 | |
| @@ -739,6 +751,7 @@ static const struct nla_policy nl80211_p
 | |
|  	[NL80211_ATTR_SAE_PWE] =
 | |
|  		NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
 | |
|  				 NL80211_SAE_PWE_BOTH),
 | |
| +	[NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
 | |
|  	[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
 | |
|  };
 | |
|  
 | |
| @@ -2117,6 +2130,56 @@ fail:
 | |
|  	return -ENOBUFS;
 | |
|  }
 | |
|  
 | |
| +static int
 | |
| +nl80211_put_sar_specs(struct cfg80211_registered_device *rdev,
 | |
| +		      struct sk_buff *msg)
 | |
| +{
 | |
| +	struct nlattr *sar_capa, *specs, *sub_freq_range;
 | |
| +	u8 num_freq_ranges;
 | |
| +	int i;
 | |
| +
 | |
| +	if (!rdev->wiphy.sar_capa)
 | |
| +		return 0;
 | |
| +
 | |
| +	num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges;
 | |
| +
 | |
| +	sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC);
 | |
| +	if (!sar_capa)
 | |
| +		return -ENOSPC;
 | |
| +
 | |
| +	if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type))
 | |
| +		goto fail;
 | |
| +
 | |
| +	specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS);
 | |
| +	if (!specs)
 | |
| +		goto fail;
 | |
| +
 | |
| +	/* report supported freq_ranges */
 | |
| +	for (i = 0; i < num_freq_ranges; i++) {
 | |
| +		sub_freq_range = nla_nest_start(msg, i + 1);
 | |
| +		if (!sub_freq_range)
 | |
| +			goto fail;
 | |
| +
 | |
| +		if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ,
 | |
| +				rdev->wiphy.sar_capa->freq_ranges[i].start_freq))
 | |
| +			goto fail;
 | |
| +
 | |
| +		if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ,
 | |
| +				rdev->wiphy.sar_capa->freq_ranges[i].end_freq))
 | |
| +			goto fail;
 | |
| +
 | |
| +		nla_nest_end(msg, sub_freq_range);
 | |
| +	}
 | |
| +
 | |
| +	nla_nest_end(msg, specs);
 | |
| +	nla_nest_end(msg, sar_capa);
 | |
| +
 | |
| +	return 0;
 | |
| +fail:
 | |
| +	nla_nest_cancel(msg, sar_capa);
 | |
| +	return -ENOBUFS;
 | |
| +}
 | |
| +
 | |
|  struct nl80211_dump_wiphy_state {
 | |
|  	s64 filter_wiphy;
 | |
|  	long start;
 | |
| @@ -2366,6 +2429,8 @@ static int nl80211_send_wiphy(struct cfg
 | |
|  			CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
 | |
|  			CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
 | |
|  			CMD(update_ft_ies, UPDATE_FT_IES);
 | |
| +			if (rdev->wiphy.sar_capa)
 | |
| +				CMD(set_sar_specs, SET_SAR_SPECS);
 | |
|  		}
 | |
|  #undef CMD
 | |
|  
 | |
| @@ -2691,6 +2756,11 @@ static int nl80211_send_wiphy(struct cfg
 | |
|  
 | |
|  		if (nl80211_put_tid_config_support(rdev, msg))
 | |
|  			goto nla_put_failure;
 | |
| +		state->split_start++;
 | |
| +		break;
 | |
| +	case 16:
 | |
| +		if (nl80211_put_sar_specs(rdev, msg))
 | |
| +			goto nla_put_failure;
 | |
|  
 | |
|  		/* done */
 | |
|  		state->split_start = 0;
 | |
| @@ -14712,6 +14782,111 @@ static void nl80211_post_doit(__genl_con
 | |
|  	}
 | |
|  }
 | |
|  
 | |
| +static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev,
 | |
| +				     struct cfg80211_sar_specs *sar_specs,
 | |
| +				     struct nlattr *spec[], int index)
 | |
| +{
 | |
| +	u32 range_index, i;
 | |
| +
 | |
| +	if (!sar_specs || !spec)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	if (!spec[NL80211_SAR_ATTR_SPECS_POWER] ||
 | |
| +	    !spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX])
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]);
 | |
| +
 | |
| +	/* check if range_index exceeds num_freq_ranges */
 | |
| +	if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	/* check if range_index duplicates */
 | |
| +	for (i = 0; i < index; i++) {
 | |
| +		if (sar_specs->sub_specs[i].freq_range_index == range_index)
 | |
| +			return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	sar_specs->sub_specs[index].power =
 | |
| +		nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]);
 | |
| +
 | |
| +	sar_specs->sub_specs[index].freq_range_index = range_index;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
 | |
| +{
 | |
| +	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 | |
| +	struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1];
 | |
| +	struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1];
 | |
| +	struct cfg80211_sar_specs *sar_spec;
 | |
| +	enum nl80211_sar_type type;
 | |
| +	struct nlattr *spec_list;
 | |
| +	u32 specs;
 | |
| +	int rem, err;
 | |
| +
 | |
| +	if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs)
 | |
| +		return -EOPNOTSUPP;
 | |
| +
 | |
| +	if (!info->attrs[NL80211_ATTR_SAR_SPEC])
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	nla_parse_nested(tb, NL80211_SAR_ATTR_MAX,
 | |
| +			 info->attrs[NL80211_ATTR_SAR_SPEC],
 | |
| +			 NULL, NULL);
 | |
| +
 | |
| +	if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS])
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]);
 | |
| +	if (type != rdev->wiphy.sar_capa->type)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	specs = 0;
 | |
| +	nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem)
 | |
| +		specs++;
 | |
| +
 | |
| +	if (specs > rdev->wiphy.sar_capa->num_freq_ranges)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	sar_spec = kzalloc(sizeof(*sar_spec) +
 | |
| +			   specs * sizeof(struct cfg80211_sar_sub_specs),
 | |
| +			   GFP_KERNEL);
 | |
| +	if (!sar_spec)
 | |
| +		return -ENOMEM;
 | |
| +
 | |
| +	sar_spec->type = type;
 | |
| +	specs = 0;
 | |
| +	nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) {
 | |
| +		nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX,
 | |
| +				 spec_list, NULL, NULL);
 | |
| +
 | |
| +		switch (type) {
 | |
| +		case NL80211_SAR_TYPE_POWER:
 | |
| +			if (nl80211_set_sar_sub_specs(rdev, sar_spec,
 | |
| +						      spec, specs)) {
 | |
| +				err = -EINVAL;
 | |
| +				goto error;
 | |
| +			}
 | |
| +			break;
 | |
| +		default:
 | |
| +			err = -EINVAL;
 | |
| +			goto error;
 | |
| +		}
 | |
| +		specs++;
 | |
| +	}
 | |
| +
 | |
| +	sar_spec->num_sub_specs = specs;
 | |
| +
 | |
| +	rdev->cur_cmd_info = info;
 | |
| +	err = rdev_set_sar_specs(rdev, sar_spec);
 | |
| +	rdev->cur_cmd_info = NULL;
 | |
| +error:
 | |
| +	kfree(sar_spec);
 | |
| +	return err;
 | |
| +}
 | |
| +
 | |
|  static __genl_const struct genl_ops nl80211_ops[] = {
 | |
|  	{
 | |
|  		.cmd = NL80211_CMD_GET_WIPHY,
 | |
| @@ -15575,6 +15750,14 @@ static const struct genl_small_ops nl802
 | |
|  		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 | |
|  				  NL80211_FLAG_NEED_RTNL,
 | |
|  	},
 | |
| +	{
 | |
| +		.cmd = NL80211_CMD_SET_SAR_SPECS,
 | |
| +		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 | |
| +		.doit = nl80211_set_sar_specs,
 | |
| +		.flags = GENL_UNS_ADMIN_PERM,
 | |
| +		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 | |
| +				  NL80211_FLAG_NEED_RTNL,
 | |
| +	},
 | |
|  };
 | |
|  
 | |
|  static struct genl_family nl80211_fam __genl_ro_after_init = {
 | |
| --- a/net/wireless/rdev-ops.h
 | |
| +++ b/net/wireless/rdev-ops.h
 | |
| @@ -1356,4 +1356,16 @@ static inline int rdev_reset_tid_config(
 | |
|  	return ret;
 | |
|  }
 | |
|  
 | |
| +static inline int rdev_set_sar_specs(struct cfg80211_registered_device *rdev,
 | |
| +				     struct cfg80211_sar_specs *sar)
 | |
| +{
 | |
| +	int ret;
 | |
| +
 | |
| +	trace_rdev_set_sar_specs(&rdev->wiphy, sar);
 | |
| +	ret = rdev->ops->set_sar_specs(&rdev->wiphy, sar);
 | |
| +	trace_rdev_return_int(&rdev->wiphy, ret);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
|  #endif /* __CFG80211_RDEV_OPS */
 | |
| --- a/net/wireless/trace.h
 | |
| +++ b/net/wireless/trace.h
 | |
| @@ -3551,6 +3551,25 @@ TRACE_EVENT(rdev_reset_tid_config,
 | |
|  	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x",
 | |
|  		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids)
 | |
|  );
 | |
| +
 | |
| +TRACE_EVENT(rdev_set_sar_specs,
 | |
| +	TP_PROTO(struct wiphy *wiphy, struct cfg80211_sar_specs *sar),
 | |
| +	TP_ARGS(wiphy, sar),
 | |
| +	TP_STRUCT__entry(
 | |
| +		WIPHY_ENTRY
 | |
| +		__field(u16, type)
 | |
| +		__field(u16, num)
 | |
| +	),
 | |
| +	TP_fast_assign(
 | |
| +		WIPHY_ASSIGN;
 | |
| +		__entry->type = sar->type;
 | |
| +		__entry->num = sar->num_sub_specs;
 | |
| +
 | |
| +	),
 | |
| +	TP_printk(WIPHY_PR_FMT ", Set type:%d, num_specs:%d",
 | |
| +		  WIPHY_PR_ARG, __entry->type, __entry->num)
 | |
| +);
 | |
| +
 | |
|  #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 | |
|  
 | |
|  #undef TRACE_INCLUDE_PATH
 |