Loading net/wireless/wext.c +134 −124 Original line number Original line Diff line number Diff line Loading @@ -694,49 +694,17 @@ void wext_proc_exit(struct net *net) */ */ /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */ /* static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, * Wrapper to call a standard Wireless Extension handler. const struct iw_ioctl_description *descr, * We do various checks and also take care of moving data between iw_handler handler, struct net_device *dev, * user space and kernel space. struct iw_request_info *info) */ static int ioctl_standard_call(struct net_device * dev, struct ifreq * ifr, unsigned int cmd, iw_handler handler) { { struct iwreq * iwr = (struct iwreq *) ifr; int err, extra_size, user_length = 0, essid_compat = 0; const struct iw_ioctl_description * descr; struct iw_request_info info; int ret = -EINVAL; /* Get the description of the IOCTL */ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); /* Prepare the call */ info.cmd = cmd; info.flags = 0; /* Check if we have a pointer to user space data or not */ if (descr->header_type != IW_HEADER_TYPE_POINT) { /* No extra arguments. Trivial to handle */ ret = handler(dev, &info, &(iwr->u), NULL); /* Generate an event to notify listeners of the change */ if ((descr->flags & IW_DESCR_FLAG_EVENT) && ((ret == 0) || (ret == -EIWCOMMIT))) wireless_send_event(dev, cmd, &(iwr->u), NULL); } else { char *extra; char *extra; int extra_size; int user_length = 0; int err; int essid_compat = 0; /* Calculate space needed by arguments. Always allocate /* Calculate space needed by arguments. Always allocate * for max space. Easier, and won't last long... */ * for max space. */ extra_size = descr->max_tokens * descr->token_size; extra_size = descr->max_tokens * descr->token_size; /* Check need for ESSID compatibility for WE < 21 */ /* Check need for ESSID compatibility for WE < 21 */ Loading @@ -745,18 +713,18 @@ static int ioctl_standard_call(struct net_device * dev, case SIOCGIWESSID: case SIOCGIWESSID: case SIOCSIWNICKN: case SIOCSIWNICKN: case SIOCGIWNICKN: case SIOCGIWNICKN: if (iwr->u.data.length == descr->max_tokens + 1) if (iwp->length == descr->max_tokens + 1) essid_compat = 1; essid_compat = 1; else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { else if (IW_IS_SET(cmd) && (iwp->length != 0)) { char essid[IW_ESSID_MAX_SIZE + 1]; char essid[IW_ESSID_MAX_SIZE + 1]; err = copy_from_user(essid, iwr->u.data.pointer, err = copy_from_user(essid, iwp->pointer, iwr->u.data.length * iwp->length * descr->token_size); descr->token_size); if (err) if (err) return -EFAULT; return -EFAULT; if (essid[iwr->u.data.length - 1] == '\0') if (essid[iwp->length - 1] == '\0') essid_compat = 1; essid_compat = 1; } } break; break; Loading @@ -764,95 +732,137 @@ static int ioctl_standard_call(struct net_device * dev, break; break; } } iwr->u.data.length -= essid_compat; iwp->length -= essid_compat; /* Check what user space is giving us */ /* Check what user space is giving us */ if (IW_IS_SET(cmd)) { if (IW_IS_SET(cmd)) { /* Check NULL pointer */ /* Check NULL pointer */ if ((iwr->u.data.pointer == NULL) && if (!iwp->pointer && iwp->length != 0) (iwr->u.data.length != 0)) return -EFAULT; return -EFAULT; /* Check if number of token fits within bounds */ /* Check if number of token fits within bounds */ if (iwr->u.data.length > descr->max_tokens) if (iwp->length > descr->max_tokens) return -E2BIG; return -E2BIG; if (iwr->u.data.length < descr->min_tokens) if (iwp->length < descr->min_tokens) return -EINVAL; return -EINVAL; } else { } else { /* Check NULL pointer */ /* Check NULL pointer */ if (iwr->u.data.pointer == NULL) if (!iwp->pointer) return -EFAULT; return -EFAULT; /* Save user space buffer size for checking */ /* Save user space buffer size for checking */ user_length = iwr->u.data.length; user_length = iwp->length; /* Don't check if user_length > max to allow forward /* Don't check if user_length > max to allow forward * compatibility. The test user_length < min is * compatibility. The test user_length < min is * implied by the test at the end. */ * implied by the test at the end. */ /* Support for very large requests */ /* Support for very large requests */ if ((descr->flags & IW_DESCR_FLAG_NOMAX) && if ((descr->flags & IW_DESCR_FLAG_NOMAX) && (user_length > descr->max_tokens)) { (user_length > descr->max_tokens)) { /* Allow userspace to GET more than max so /* Allow userspace to GET more than max so * we can support any size GET requests. * we can support any size GET requests. * There is still a limit : -ENOMEM. */ * There is still a limit : -ENOMEM. */ extra_size = user_length * descr->token_size; extra_size = user_length * descr->token_size; /* Note : user_length is originally a __u16, /* Note : user_length is originally a __u16, * and token_size is controlled by us, * and token_size is controlled by us, * so extra_size won't get negative and * so extra_size won't get negative and * won't overflow... */ * won't overflow... */ } } } } /* Create the kernel buffer */ /* kzalloc() ensures NULL-termination for essid_compat. */ /* kzalloc ensures NULL-termination for essid_compat */ extra = kzalloc(extra_size, GFP_KERNEL); extra = kzalloc(extra_size, GFP_KERNEL); if (extra == NULL) if (!extra) return -ENOMEM; return -ENOMEM; /* If it is a SET, get all the extra data in here */ /* If it is a SET, get all the extra data in here */ if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { if (IW_IS_SET(cmd) && (iwp->length != 0)) { err = copy_from_user(extra, iwr->u.data.pointer, if (copy_from_user(extra, iwp->pointer, iwr->u.data.length * iwp->length * descr->token_size); descr->token_size)) { if (err) { err = -EFAULT; kfree(extra); goto out; return -EFAULT; } } } } /* Call the handler */ err = handler(dev, info, (union iwreq_data *) iwp, extra); ret = handler(dev, &info, &(iwr->u), extra); iwr->u.data.length += essid_compat; iwp->length += essid_compat; /* If we have something to return to the user */ /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) { if (!err && IW_IS_GET(cmd)) { /* Check if there is enough buffer up there */ /* Check if there is enough buffer up there */ if (user_length < iwr->u.data.length) { if (user_length < iwp->length) { kfree(extra); err = -E2BIG; return -E2BIG; goto out; } } err = copy_to_user(iwr->u.data.pointer, extra, if (copy_to_user(iwp->pointer, extra, iwr->u.data.length * iwp->length * descr->token_size); descr->token_size)) { if (err) err = -EFAULT; ret = -EFAULT; goto out; } } } /* Generate an event to notify listeners of the change */ /* Generate an event to notify listeners of the change */ if ((descr->flags & IW_DESCR_FLAG_EVENT) && if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { ((ret == 0) || (ret == -EIWCOMMIT))) { union iwreq_data *data = (union iwreq_data *) iwp; if (descr->flags & IW_DESCR_FLAG_RESTRICT) if (descr->flags & IW_DESCR_FLAG_RESTRICT) /* If the event is restricted, don't /* If the event is restricted, don't * export the payload */ * export the payload. wireless_send_event(dev, cmd, &(iwr->u), NULL); */ wireless_send_event(dev, cmd, data, NULL); else else wireless_send_event(dev, cmd, &(iwr->u), wireless_send_event(dev, cmd, data, extra); extra); } } /* Cleanup - I told you it wasn't that long ;-) */ out: kfree(extra); kfree(extra); return err; } /* * Wrapper to call a standard Wireless Extension handler. * We do various checks and also take care of moving data between * user space and kernel space. */ static int ioctl_standard_call(struct net_device * dev, struct ifreq * ifr, unsigned int cmd, iw_handler handler) { struct iwreq * iwr = (struct iwreq *) ifr; const struct iw_ioctl_description * descr; struct iw_request_info info; int ret = -EINVAL; /* Get the description of the IOCTL */ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); /* Prepare the call */ info.cmd = cmd; info.flags = 0; /* Check if we have a pointer to user space data or not */ if (descr->header_type != IW_HEADER_TYPE_POINT) { /* No extra arguments. Trivial to handle */ ret = handler(dev, &info, &(iwr->u), NULL); /* Generate an event to notify listeners of the change */ if ((descr->flags & IW_DESCR_FLAG_EVENT) && ((ret == 0) || (ret == -EIWCOMMIT))) wireless_send_event(dev, cmd, &(iwr->u), NULL); } else { ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, handler, dev, &info); } } /* Call commit handler if needed and defined */ /* Call commit handler if needed and defined */ Loading Loading
net/wireless/wext.c +134 −124 Original line number Original line Diff line number Diff line Loading @@ -694,49 +694,17 @@ void wext_proc_exit(struct net *net) */ */ /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */ /* static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, * Wrapper to call a standard Wireless Extension handler. const struct iw_ioctl_description *descr, * We do various checks and also take care of moving data between iw_handler handler, struct net_device *dev, * user space and kernel space. struct iw_request_info *info) */ static int ioctl_standard_call(struct net_device * dev, struct ifreq * ifr, unsigned int cmd, iw_handler handler) { { struct iwreq * iwr = (struct iwreq *) ifr; int err, extra_size, user_length = 0, essid_compat = 0; const struct iw_ioctl_description * descr; struct iw_request_info info; int ret = -EINVAL; /* Get the description of the IOCTL */ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); /* Prepare the call */ info.cmd = cmd; info.flags = 0; /* Check if we have a pointer to user space data or not */ if (descr->header_type != IW_HEADER_TYPE_POINT) { /* No extra arguments. Trivial to handle */ ret = handler(dev, &info, &(iwr->u), NULL); /* Generate an event to notify listeners of the change */ if ((descr->flags & IW_DESCR_FLAG_EVENT) && ((ret == 0) || (ret == -EIWCOMMIT))) wireless_send_event(dev, cmd, &(iwr->u), NULL); } else { char *extra; char *extra; int extra_size; int user_length = 0; int err; int essid_compat = 0; /* Calculate space needed by arguments. Always allocate /* Calculate space needed by arguments. Always allocate * for max space. Easier, and won't last long... */ * for max space. */ extra_size = descr->max_tokens * descr->token_size; extra_size = descr->max_tokens * descr->token_size; /* Check need for ESSID compatibility for WE < 21 */ /* Check need for ESSID compatibility for WE < 21 */ Loading @@ -745,18 +713,18 @@ static int ioctl_standard_call(struct net_device * dev, case SIOCGIWESSID: case SIOCGIWESSID: case SIOCSIWNICKN: case SIOCSIWNICKN: case SIOCGIWNICKN: case SIOCGIWNICKN: if (iwr->u.data.length == descr->max_tokens + 1) if (iwp->length == descr->max_tokens + 1) essid_compat = 1; essid_compat = 1; else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { else if (IW_IS_SET(cmd) && (iwp->length != 0)) { char essid[IW_ESSID_MAX_SIZE + 1]; char essid[IW_ESSID_MAX_SIZE + 1]; err = copy_from_user(essid, iwr->u.data.pointer, err = copy_from_user(essid, iwp->pointer, iwr->u.data.length * iwp->length * descr->token_size); descr->token_size); if (err) if (err) return -EFAULT; return -EFAULT; if (essid[iwr->u.data.length - 1] == '\0') if (essid[iwp->length - 1] == '\0') essid_compat = 1; essid_compat = 1; } } break; break; Loading @@ -764,95 +732,137 @@ static int ioctl_standard_call(struct net_device * dev, break; break; } } iwr->u.data.length -= essid_compat; iwp->length -= essid_compat; /* Check what user space is giving us */ /* Check what user space is giving us */ if (IW_IS_SET(cmd)) { if (IW_IS_SET(cmd)) { /* Check NULL pointer */ /* Check NULL pointer */ if ((iwr->u.data.pointer == NULL) && if (!iwp->pointer && iwp->length != 0) (iwr->u.data.length != 0)) return -EFAULT; return -EFAULT; /* Check if number of token fits within bounds */ /* Check if number of token fits within bounds */ if (iwr->u.data.length > descr->max_tokens) if (iwp->length > descr->max_tokens) return -E2BIG; return -E2BIG; if (iwr->u.data.length < descr->min_tokens) if (iwp->length < descr->min_tokens) return -EINVAL; return -EINVAL; } else { } else { /* Check NULL pointer */ /* Check NULL pointer */ if (iwr->u.data.pointer == NULL) if (!iwp->pointer) return -EFAULT; return -EFAULT; /* Save user space buffer size for checking */ /* Save user space buffer size for checking */ user_length = iwr->u.data.length; user_length = iwp->length; /* Don't check if user_length > max to allow forward /* Don't check if user_length > max to allow forward * compatibility. The test user_length < min is * compatibility. The test user_length < min is * implied by the test at the end. */ * implied by the test at the end. */ /* Support for very large requests */ /* Support for very large requests */ if ((descr->flags & IW_DESCR_FLAG_NOMAX) && if ((descr->flags & IW_DESCR_FLAG_NOMAX) && (user_length > descr->max_tokens)) { (user_length > descr->max_tokens)) { /* Allow userspace to GET more than max so /* Allow userspace to GET more than max so * we can support any size GET requests. * we can support any size GET requests. * There is still a limit : -ENOMEM. */ * There is still a limit : -ENOMEM. */ extra_size = user_length * descr->token_size; extra_size = user_length * descr->token_size; /* Note : user_length is originally a __u16, /* Note : user_length is originally a __u16, * and token_size is controlled by us, * and token_size is controlled by us, * so extra_size won't get negative and * so extra_size won't get negative and * won't overflow... */ * won't overflow... */ } } } } /* Create the kernel buffer */ /* kzalloc() ensures NULL-termination for essid_compat. */ /* kzalloc ensures NULL-termination for essid_compat */ extra = kzalloc(extra_size, GFP_KERNEL); extra = kzalloc(extra_size, GFP_KERNEL); if (extra == NULL) if (!extra) return -ENOMEM; return -ENOMEM; /* If it is a SET, get all the extra data in here */ /* If it is a SET, get all the extra data in here */ if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { if (IW_IS_SET(cmd) && (iwp->length != 0)) { err = copy_from_user(extra, iwr->u.data.pointer, if (copy_from_user(extra, iwp->pointer, iwr->u.data.length * iwp->length * descr->token_size); descr->token_size)) { if (err) { err = -EFAULT; kfree(extra); goto out; return -EFAULT; } } } } /* Call the handler */ err = handler(dev, info, (union iwreq_data *) iwp, extra); ret = handler(dev, &info, &(iwr->u), extra); iwr->u.data.length += essid_compat; iwp->length += essid_compat; /* If we have something to return to the user */ /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) { if (!err && IW_IS_GET(cmd)) { /* Check if there is enough buffer up there */ /* Check if there is enough buffer up there */ if (user_length < iwr->u.data.length) { if (user_length < iwp->length) { kfree(extra); err = -E2BIG; return -E2BIG; goto out; } } err = copy_to_user(iwr->u.data.pointer, extra, if (copy_to_user(iwp->pointer, extra, iwr->u.data.length * iwp->length * descr->token_size); descr->token_size)) { if (err) err = -EFAULT; ret = -EFAULT; goto out; } } } /* Generate an event to notify listeners of the change */ /* Generate an event to notify listeners of the change */ if ((descr->flags & IW_DESCR_FLAG_EVENT) && if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { ((ret == 0) || (ret == -EIWCOMMIT))) { union iwreq_data *data = (union iwreq_data *) iwp; if (descr->flags & IW_DESCR_FLAG_RESTRICT) if (descr->flags & IW_DESCR_FLAG_RESTRICT) /* If the event is restricted, don't /* If the event is restricted, don't * export the payload */ * export the payload. wireless_send_event(dev, cmd, &(iwr->u), NULL); */ wireless_send_event(dev, cmd, data, NULL); else else wireless_send_event(dev, cmd, &(iwr->u), wireless_send_event(dev, cmd, data, extra); extra); } } /* Cleanup - I told you it wasn't that long ;-) */ out: kfree(extra); kfree(extra); return err; } /* * Wrapper to call a standard Wireless Extension handler. * We do various checks and also take care of moving data between * user space and kernel space. */ static int ioctl_standard_call(struct net_device * dev, struct ifreq * ifr, unsigned int cmd, iw_handler handler) { struct iwreq * iwr = (struct iwreq *) ifr; const struct iw_ioctl_description * descr; struct iw_request_info info; int ret = -EINVAL; /* Get the description of the IOCTL */ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); /* Prepare the call */ info.cmd = cmd; info.flags = 0; /* Check if we have a pointer to user space data or not */ if (descr->header_type != IW_HEADER_TYPE_POINT) { /* No extra arguments. Trivial to handle */ ret = handler(dev, &info, &(iwr->u), NULL); /* Generate an event to notify listeners of the change */ if ((descr->flags & IW_DESCR_FLAG_EVENT) && ((ret == 0) || (ret == -EIWCOMMIT))) wireless_send_event(dev, cmd, &(iwr->u), NULL); } else { ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, handler, dev, &info); } } /* Call commit handler if needed and defined */ /* Call commit handler if needed and defined */ Loading