Skip to content

Commit

Permalink
wext: verify buffer size for SIOCSIWENCODEEXT
Browse files Browse the repository at this point in the history
Another design flaw in wireless extensions (is anybody
surprised?) in the way it handles the iw_encode_ext
structure: The structure is part of the 'extra' memory
but contains the key length explicitly, instead of it
just being the length of the extra buffer - size of
the struct and using the explicit key length only for
the get operation (which only writes it).

Therefore, we have this layout:

extra: +-------------------------+
       | struct iw_encode_ext  { |
       |     ...                 |
       |     u16 key_len;        |
       |     u8 key[0];          |
       | };                      |
       +-------------------------+
       | key material            |
       +-------------------------+

Now, all drivers I checked use ext->key_len without
checking that both key_len and the struct fit into the
extra buffer that has been copied from userspace. This
leads to a buffer overrun while reading that buffer,
depending on the driver it may be possible to specify
arbitrary key_len or it may need to be a proper length
for the key algorithm specified.

Thankfully, this is only exploitable by root, but root
can actually cause a segfault or use kernel memory as
a key (which you can even get back with siocgiwencode
or siocgiwencodeext from the key buffer).

Fix this by verifying that key_len fits into the buffer
along with struct iw_encode_ext.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Johannes Berg authored and John W. Linville committed May 20, 2009
1 parent 2b611cb commit 88f16db
Showing 1 changed file with 7 additions and 0 deletions.
7 changes: 7 additions & 0 deletions net/wireless/wext.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,13 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
err = -EFAULT;
goto out;
}

if (cmd == SIOCSIWENCODEEXT) {
struct iw_encode_ext *ee = (void *) extra;

if (iwp->length < sizeof(*ee) + ee->key_len)
return -EFAULT;
}
}

err = handler(dev, info, (union iwreq_data *) iwp, extra);
Expand Down

0 comments on commit 88f16db

Please sign in to comment.