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

Commit c888393b authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Johannes Berg
Browse files

cfg80211: avoid freeing last_request while in flight



Avoid freeing the last request while it is being processed. This can
happen in some cases if reg_work is kicked for some reason while the
currently pending request is in flight.

Cc: Sander Eikelenboom <linux@eikelenboom.it>
Tested-by: default avatarEliad Peller <eliad@wizery.com>
Tested-by: default avatarColleen Twitty <colleen@cozybit.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarLuis R. Rodriguez <mcgrof@suse.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 4f267c11
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -263,8 +263,16 @@ static char user_alpha2[2];
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");

static void reg_free_request(struct regulatory_request *lr)
static void reg_free_request(struct regulatory_request *request)
{
	if (request != get_last_request())
		kfree(request);
}

static void reg_free_last_request(void)
{
	struct regulatory_request *lr = get_last_request();

	if (lr != &core_request_world && lr)
		kfree_rcu(lr, rcu_head);
}
@@ -277,7 +285,7 @@ static void reg_update_last_request(struct regulatory_request *request)
	if (lr == request)
		return;

	reg_free_request(lr);
	reg_free_last_request();
	rcu_assign_pointer(last_request, request);
}

@@ -1661,7 +1669,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
	if (treatment == REG_REQ_IGNORE ||
	    treatment == REG_REQ_ALREADY_SET ||
	    treatment == REG_REQ_USER_HINT_HANDLED) {
		kfree(user_request);
		reg_free_request(user_request);
		return treatment;
	}

@@ -1722,14 +1730,14 @@ reg_process_hint_driver(struct wiphy *wiphy,
		break;
	case REG_REQ_IGNORE:
	case REG_REQ_USER_HINT_HANDLED:
		kfree(driver_request);
		reg_free_request(driver_request);
		return treatment;
	case REG_REQ_INTERSECT:
		/* fall through */
	case REG_REQ_ALREADY_SET:
		regd = reg_copy_regd(get_cfg80211_regdom());
		if (IS_ERR(regd)) {
			kfree(driver_request);
			reg_free_request(driver_request);
			return REG_REQ_IGNORE;
		}
		rcu_assign_pointer(wiphy->regd, regd);
@@ -1824,10 +1832,10 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
	case REG_REQ_USER_HINT_HANDLED:
		/* fall through */
	case REG_REQ_ALREADY_SET:
		kfree(country_ie_request);
		reg_free_request(country_ie_request);
		return treatment;
	case REG_REQ_INTERSECT:
		kfree(country_ie_request);
		reg_free_request(country_ie_request);
		/*
		 * This doesn't happen yet, not sure we
		 * ever want to support it for this case.
@@ -1888,7 +1896,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
	return;

out_free:
	kfree(reg_request);
	reg_free_request(reg_request);
}

/*