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: Eliad Peller <eliad@wizery.com> Tested-by: Colleen Twitty <colleen@cozybit.com> Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
		
				
					committed by
					
						 Johannes Berg
						Johannes Berg
					
				
			
			
				
	
			
			
			
						parent
						
							4f267c1198
						
					
				
				
					commit
					c888393b74
				
			| @@ -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); | ||||
| } | ||||
|  | ||||
| /* | ||||
|   | ||||
		Reference in New Issue
	
	Block a user