| This is a tricky one. |
| |
| Consider a kernel that has this code in net/wireless/wext-core.c: |
| |
| #ifdef CONFIG_CFG80211_WEXT |
| if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy) |
| handlers = dev->ieee80211_ptr->wiphy->wext; |
| #endif |
| #ifdef CONFIG_WIRELESS_EXT |
| if (dev->wireless_handlers) |
| handlers = dev->wireless_handlers; |
| #endif |
| |
| If a kernel is compiled without CONFIG_WIRELESS_EXT then |
| compat-wireless can't do wireless extensions against it. |
| However, if the kernel is compiled with CONFIG_CFG80211_WEXT |
| then it will try to get the wext handlers from struct wiphy. |
| |
| Now, struct wiphy in the base kernel and struct wiphy in |
| compat-wireless don't match, so the kernel crashes!! |
| |
| To fix this, add lots of padding to compat-wireless's |
| struct wiphy so that the "wext" pointer is guaranteed |
| to be NULL. |
| |
| Make sure the padding is larger than the struct so we |
| don't ever run into this again because the wext pointer |
| moved due to struct enlargements. |
| |
| |
| --- a/include/net/cfg80211.h |
| +++ b/include/net/cfg80211.h |
| @@ -1964,6 +1964,9 @@ struct wiphy_wowlan_support { |
| struct wiphy { |
| /* assign these fields before you register the wiphy */ |
| |
| +#define WIPHY_COMPAT_PAD_SIZE 2048 |
| + u8 padding[WIPHY_COMPAT_PAD_SIZE]; |
| + |
| /* permanent MAC address(es) */ |
| u8 perm_addr[ETH_ALEN]; |
| u8 addr_mask[ETH_ALEN]; |
| --- a/net/wireless/core.c |
| +++ b/net/wireless/core.c |
| @@ -332,6 +332,17 @@ struct wiphy *wiphy_new(const struct cfg |
| struct cfg80211_registered_device *rdev; |
| int alloc_size; |
| |
| + /* |
| + * Make sure the padding is >= the rest of the struct so that we |
| + * always keep it large enough to pad out the entire original |
| + * kernel's struct. We really only need to make sure it's larger |
| + * than the kernel compat is compiled against, but since it'll |
| + * only increase in size make sure it's larger than the current |
| + * version of it. Subtract since it's included. |
| + */ |
| + BUILD_BUG_ON(WIPHY_COMPAT_PAD_SIZE < |
| + sizeof(struct wiphy) - WIPHY_COMPAT_PAD_SIZE); |
| + |
| WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); |
| WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); |
| WARN_ON(ops->connect && !ops->disconnect); |