Commit message: staging: wlags49_h2: buffer overflow setting station name

We need to check the length parameter before doing the memcpy().  I've
actually changed it to strlcpy() as well so that it's NUL terminated.

You need CAP_NET_ADMIN to trigger these so it's not the end of the
world.

Reported-by: Nico Golde <nico@ngolde.de>
Reported-by: Fabian Yamaguchi <fabs@goesec.de>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
CVE: CVE-2013-4514
CWE: CWE-119
Vulnerability description: Multiple buffer overflows in drivers/staging/wlags49_h2/wl_priv.c in the Linux kernel before 3.12 allow local users to cause a denial of service or possibly have unspecified other impact by leveraging the CAP_NET_ADMIN capability and providing a long station-name string, related to the (1) wvlan_uil_put_info and (2) wvlan_set_station_nickname functions.

Project: linux
File: wl_priv.c

int wvlan_uil(struct uilreq *urq, struct wl_private *lp)
{
	int ioctl_ret = 0;
	/*------------------------------------------------------------------------*/

	DBG_FUNC("wvlan_uil");
	DBG_ENTER(DbgInfo);

	switch (urq->command) {
	case UIL_FUN_CONNECT:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_CONNECT\n");
		ioctl_ret = wvlan_uil_connect(urq, lp);
		break;
	case UIL_FUN_DISCONNECT:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_DISCONNECT\n");
		ioctl_ret = wvlan_uil_disconnect(urq, lp);
		break;
	case UIL_FUN_ACTION:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_ACTION\n");
		ioctl_ret = wvlan_uil_action(urq, lp);
		break;
	case UIL_FUN_SEND_DIAG_MSG:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_SEND_DIAG_MSG\n");
		ioctl_ret = wvlan_uil_send_diag_msg(urq, lp);
		break;
	case UIL_FUN_GET_INFO:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_GET_INFO\n");
		ioctl_ret = wvlan_uil_get_info(urq, lp);
		break;
	case UIL_FUN_PUT_INFO:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- WVLAN2_UIL_PUT_INFO\n");
		ioctl_ret = wvlan_uil_put_info(urq, lp);
		break;
	default:
		DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL -- UNSUPPORTED UIL CODE: 0x%X", urq->command);
		ioctl_ret = -EOPNOTSUPP;
		break;
	}
	DBG_LEAVE(DbgInfo);
	return ioctl_ret;
} /* wvlan_uil */

Project: linux
File: wl_priv.c

int wvlan_uil_action(struct uilreq *urq, struct wl_private *lp)
{
	int     result = 0;
	ltv_t   *ltv;
	/*------------------------------------------------------------------------*/


	DBG_FUNC("wvlan_uil_action");
	DBG_ENTER(DbgInfo);


	if (urq->hcfCtx == &(lp->hcfCtx)) {
		/* Make sure there's an LTV in the request buffer */
		ltv = (ltv_t *)urq->data;
		if (ltv != NULL) {
			/* Switch on the Type field of the LTV contained in the request
			   buffer */
			switch (ltv->typ) {
			case UIL_ACT_BLOCK:
				DBG_TRACE(DbgInfo, "UIL_ACT_BLOCK\n");
				result = wvlan_uil_block(urq, lp);
				break;
			case UIL_ACT_UNBLOCK:
				DBG_TRACE(DbgInfo, "UIL_ACT_UNBLOCK\n");
				result = wvlan_uil_unblock(urq, lp);
				break;
			case UIL_ACT_SCAN:
				DBG_TRACE(DbgInfo, "UIL_ACT_SCAN\n");
				urq->result = hcf_action(&(lp->hcfCtx), MDD_ACT_SCAN);
				break;
			case UIL_ACT_APPLY:
				DBG_TRACE(DbgInfo, "UIL_ACT_APPLY\n");
				urq->result = wl_apply(lp);
				break;
			case UIL_ACT_RESET:
				DBG_TRACE(DbgInfo, "UIL_ACT_RESET\n");
				urq->result = wl_go(lp);
				break;
			default:
				DBG_WARNING(DbgInfo, "Unknown action code: 0x%x\n", ltv->typ);
				break;
			}
		} else {
			DBG_ERROR(DbgInfo, "Bad LTV for this action\n");
			urq->result = UIL_ERR_LEN;
		}
	} else {
		DBG_ERROR(DbgInfo, "UIL_ERR_WRONG_IFB\n");
		urq->result = UIL_ERR_WRONG_IFB;
	}

	DBG_LEAVE(DbgInfo);
	return result;
} /* wvlan_uil_action */