wifi: nl80211: Avoid address calculations via out of bounds array indexing
authorKees Cook <keescook@chromium.org>
Wed, 24 Apr 2024 22:01:01 +0000 (15:01 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 3 May 2024 07:20:26 +0000 (09:20 +0200)
Before request->channels[] can be used, request->n_channels must be set.
Additionally, address calculations for memory after the "channels" array
need to be calculated from the allocation base ("request") rather than
via the first "out of bounds" index of "channels", otherwise run-time
bounds checking will throw a warning.

Reported-by: Nathan Chancellor <nathan@kernel.org>
Fixes: e3eac9f32ec0 ("wifi: cfg80211: Annotate struct cfg80211_scan_request with __counted_by")
Signed-off-by: Kees Cook <keescook@chromium.org>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Link: https://msgid.link/20240424220057.work.819-kees@kernel.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/nl80211.c

index 30ff9a47081348d1b14d1db520aeedf9c9ffdd09..65c416e8d25eb9c93d912dc658a0333c19da0699 100644 (file)
@@ -9162,6 +9162,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        struct wiphy *wiphy;
        int err, tmp, n_ssids = 0, n_channels, i;
        size_t ie_len, size;
+       size_t ssids_offset, ie_offset;
 
        wiphy = &rdev->wiphy;
 
@@ -9207,21 +9208,20 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        size = struct_size(request, channels, n_channels);
+       ssids_offset = size;
        size = size_add(size, array_size(sizeof(*request->ssids), n_ssids));
+       ie_offset = size;
        size = size_add(size, ie_len);
        request = kzalloc(size, GFP_KERNEL);
        if (!request)
                return -ENOMEM;
+       request->n_channels = n_channels;
 
        if (n_ssids)
-               request->ssids = (void *)&request->channels[n_channels];
+               request->ssids = (void *)request + ssids_offset;
        request->n_ssids = n_ssids;
-       if (ie_len) {
-               if (n_ssids)
-                       request->ie = (void *)(request->ssids + n_ssids);
-               else
-                       request->ie = (void *)(request->channels + n_channels);
-       }
+       if (ie_len)
+               request->ie = (void *)request + ie_offset;
 
        i = 0;
        if (scan_freqs) {