Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0efd8b75 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wcnss: fix the potential buffer overflow in wlan ctrl data process"

parents 4c194c8c 9f3778e4
Loading
Loading
Loading
Loading
+44 −93
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pm_qos.h>
#include <linux/bitops.h>
#include <soc/qcom/socinfo.h>

#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_notif.h>
@@ -187,16 +188,14 @@ static DEFINE_SPINLOCK(reg_spinlock);
#define WCNSS_MAX_BUILD_VER_LEN		256
#define WCNSS_MAX_CMD_LEN		(128)
#define WCNSS_MIN_CMD_LEN		(3)
#define WCNSS_MIN_SERIAL_LEN		(6)
#define WCNSS_CMD_INFO_LEN		2

/* control messages from userspace */
#define WCNSS_USR_CTRL_MSG_START  0x00000000
#define WCNSS_USR_SERIAL_NUM      (WCNSS_USR_CTRL_MSG_START + 1)
#define WCNSS_USR_HAS_CAL_DATA    (WCNSS_USR_CTRL_MSG_START + 2)
#define WCNSS_USR_WLAN_MAC_ADDR   (WCNSS_USR_CTRL_MSG_START + 3)

#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
#define SHOW_MAC_ADDRESS_STR	"%02x:%02x:%02x:%02x:%02x:%02x\n"
#define WCNSS_USER_MAC_ADDR_LENGTH	18

/* message types */
@@ -459,11 +458,7 @@ static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
		       (char *)&macAddr[index], sizeof(char));
	}

	pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
		penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
		penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
		penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);

	pr_info("%s: Write MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr);
	return count;
}

@@ -473,43 +468,12 @@ static ssize_t wcnss_wlan_macaddr_show(struct device *dev,
	if (!penv)
		return -ENODEV;

	return scnprintf(buf, PAGE_SIZE, SHOW_MAC_ADDRESS_STR,
		penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
		penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
		penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
	return scnprintf(buf, PAGE_SIZE, "%pM\n", penv->wlan_nv_macAddr);
}

static DEVICE_ATTR(wcnss_mac_addr, S_IRUSR | S_IWUSR,
	wcnss_wlan_macaddr_show, wcnss_wlan_macaddr_store);

static ssize_t wcnss_serial_number_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	if (!penv)
		return -ENODEV;

	return scnprintf(buf, PAGE_SIZE, "%08X\n", penv->serial_number);
}

static ssize_t wcnss_serial_number_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	unsigned int value;

	if (!penv)
		return -ENODEV;

	if (sscanf(buf, "%08X", &value) != 1)
		return -EINVAL;

	penv->serial_number = value;
	return count;
}

static DEVICE_ATTR(serial_number, S_IRUSR | S_IWUSR,
	wcnss_serial_number_show, wcnss_serial_number_store);


static ssize_t wcnss_thermal_mitigation_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
@@ -1178,13 +1142,9 @@ static int wcnss_create_sysfs(struct device *dev)
	if (!dev)
		return -ENODEV;

	ret = device_create_file(dev, &dev_attr_serial_number);
	if (ret)
		return ret;

	ret = device_create_file(dev, &dev_attr_thermal_mitigation);
	if (ret)
		goto remove_serial;
		return ret;

	ret = device_create_file(dev, &dev_attr_wcnss_version);
	if (ret)
@@ -1200,8 +1160,6 @@ remove_version:
	device_remove_file(dev, &dev_attr_wcnss_version);
remove_thermal:
	device_remove_file(dev, &dev_attr_thermal_mitigation);
remove_serial:
	device_remove_file(dev, &dev_attr_serial_number);

	return ret;
}
@@ -1209,7 +1167,6 @@ remove_serial:
static void wcnss_remove_sysfs(struct device *dev)
{
	if (dev) {
		device_remove_file(dev, &dev_attr_serial_number);
		device_remove_file(dev, &dev_attr_thermal_mitigation);
		device_remove_file(dev, &dev_attr_wcnss_version);
		device_remove_file(dev, &dev_attr_wcnss_mac_addr);
@@ -1657,8 +1614,13 @@ EXPORT_SYMBOL(wcnss_unregister_thermal_mitigation);

unsigned int wcnss_get_serial_number(void)
{
	if (penv)
	if (penv) {
		penv->serial_number = socinfo_get_serial_number();
		pr_info("%s: Device serial number: %u\n",
			__func__, penv->serial_number);
		return penv->serial_number;
	}

	return 0;
}
EXPORT_SYMBOL(wcnss_get_serial_number);
@@ -1669,10 +1631,8 @@ int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE])
		return -ENODEV;

	memcpy(mac_addr, penv->wlan_nv_macAddr, WLAN_MAC_ADDR_SIZE);
	pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
		penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
		penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
		penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
	pr_debug("%s: Get MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr);

	return 0;
}
EXPORT_SYMBOL(wcnss_get_wlan_mac_address);
@@ -2641,66 +2601,57 @@ static int wcnss_ctrl_open(struct inode *inode, struct file *file)
	return rc;
}


void process_usr_ctrl_cmd(u8 *buf, size_t len)
static ssize_t wcnss_ctrl_write(struct file *fp, const char __user
			*user_buffer, size_t count, loff_t *position)
{
	u16 cmd = buf[0] << 8 | buf[1];
	int rc = 0;
	u16 cmd;
	u8 buf[WCNSS_MAX_CMD_LEN];

	switch (cmd) {
	if (!penv || !penv->ctrl_device_opened ||
	    WCNSS_MAX_CMD_LEN < count || WCNSS_MIN_CMD_LEN > count)
		return -EFAULT;

	case WCNSS_USR_SERIAL_NUM:
		if (WCNSS_MIN_SERIAL_LEN > len) {
			pr_err("%s: Invalid serial number\n", __func__);
			return;
	mutex_lock(&penv->ctrl_lock);
	rc = copy_from_user(buf, user_buffer, count);
	if (rc) {
		pr_err("%s: Failed to copy ctrl data\n", __func__);
		goto exit;
	}
		penv->serial_number = buf[2] << 24 | buf[3] << 16
			| buf[4] << 8 | buf[5];
		break;

	cmd = buf[0] << 8 | buf[1];
	switch (cmd) {
	case WCNSS_USR_HAS_CAL_DATA:
		if (1 < buf[2])
			pr_err("%s: Invalid data for cal %d\n", __func__,
				buf[2]);
		if (buf[2] > 1) {
			pr_err("%s: Invalid cal data %d\n", __func__, buf[2]);
			rc = -EINVAL;
			goto exit;
		}
		has_calibrated_data = buf[2];
		break;

	case WCNSS_USR_WLAN_MAC_ADDR:
		if ((count - WCNSS_CMD_INFO_LEN) != WLAN_MAC_ADDR_SIZE) {
			pr_err("%s: Invalid Mac addr %d\n", __func__, buf[2]);
			rc = -EINVAL;
			goto exit;
		}

		memcpy(&penv->wlan_nv_macAddr, &buf[2],
		       sizeof(penv->wlan_nv_macAddr));

		pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
			penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
			penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
			penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
		pr_debug("%s:MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr);
		break;

	default:
		pr_err("%s: Invalid command %d\n", __func__, cmd);
		rc = -EINVAL;
		break;
	}
}

static ssize_t wcnss_ctrl_write(struct file *fp, const char __user
			*user_buffer, size_t count, loff_t *position)
{
	int rc = 0;
	u8 buf[WCNSS_MAX_CMD_LEN];

	if (!penv || !penv->ctrl_device_opened || WCNSS_MAX_CMD_LEN < count
			|| WCNSS_MIN_CMD_LEN > count)
		return -EFAULT;

	mutex_lock(&penv->ctrl_lock);
	rc = copy_from_user(buf, user_buffer, count);
	if (0 == rc)
		process_usr_ctrl_cmd(buf, count);

exit:
	mutex_unlock(&penv->ctrl_lock);

	return rc;
}


static const struct file_operations wcnss_ctrl_fops = {
	.owner = THIS_MODULE,
	.open = wcnss_ctrl_open,