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

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

Merge "misc: qfpfuse: Fix overflow condition"

parents 3faf5188 6f090cae
Loading
Loading
Loading
Loading
+49 −34
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@
/*
 * Time QFPROM requires to reliably burn a fuse.
 */
#define QFPROM_BLOW_TIMEOUT_US      10
#define QFPROM_BLOW_TIMEOUT_US      20
#define QFPROM_BLOW_TIMER_OFFSET    0x2038
/*
 * Denotes number of cycles required to blow the fuse.
@@ -42,6 +42,9 @@

#define QFP_FUSE_READY              0x01
#define QFP_FUSE_OFF                0x00

#define QFP_FUSE_BUF_SIZE           64

static const char *blow_supply = "vdd-blow";

struct qfp_priv_t {
@@ -63,6 +66,20 @@ struct qfp_resource {
/* We need only one instance of this for the driver */
static struct qfp_priv_t *qfp_priv;

static inline bool is_usr_req_valid(const struct qfp_fuse_req *req)
{
	uint32_t size = qfp_priv->end - qfp_priv->base;
	uint32_t req_size = req->size * sizeof(uint32_t);

	if ((req_size == 0) || (req_size > size))
		return false;
	if (req->offset >= size)
		return false;
	if ((req->offset + req_size) > size)
		return false;

	return true;
}

static int qfp_fuse_open(struct inode *inode, struct file *filp)
{
@@ -187,7 +204,9 @@ qfp_fuse_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int err = 0;
	struct qfp_fuse_req req;
	u32 *buf = NULL;
	u32 fuse_buf[QFP_FUSE_BUF_SIZE];
	u32 *buf = fuse_buf;
	u32 *ptr = NULL;
	int i;

	/* Verify user arguments. */
@@ -209,26 +228,22 @@ qfp_fuse_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		}

		/* Check for limits */
		if (!req.size) {
			pr_err("Request size zero.\n");
			err = -EFAULT;
			break;
		}

		if (qfp_priv->base + req.offset + (req.size - 1) * 4 >
				qfp_priv->end) {
			pr_err("Req size exceeds QFPROM addr space\n");
			err = -EFAULT;
		if (is_usr_req_valid(&req) == false) {
			pr_err("Invalid request\n");
			err = -EINVAL;
			break;
		}

		if (req.size > QFP_FUSE_BUF_SIZE) {
			/* Allocate memory for buffer */
		buf = kzalloc(req.size * 4, GFP_KERNEL);
		if (buf == NULL) {
			ptr = kzalloc(req.size * 4, GFP_KERNEL);
			if (ptr == NULL) {
				pr_alert("No memory for data\n");
				err = -ENOMEM;
				break;
			}
			buf = ptr;
		}

		if (mutex_lock_interruptible(&qfp_priv->lock)) {
			err = -ERESTARTSYS;
@@ -260,26 +275,24 @@ qfp_fuse_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
			err = -EFAULT;
			break;
		}

		/* Check for limits */
		if (!req.size) {
			pr_err("Request size zero.\n");
			err = -EFAULT;
			break;
		}
		if (qfp_priv->base + req.offset + (req.size - 1) * 4 >
				qfp_priv->end) {
			pr_err("Req size exceeds QFPROM space\n");
			err = -EFAULT;
		if (is_usr_req_valid(&req) == false) {
			pr_err("Invalid request\n");
			err = -EINVAL;
			break;
		}

		if (req.size > QFP_FUSE_BUF_SIZE) {
			/* Allocate memory for buffer */
		buf = kzalloc(4 * (req.size), GFP_KERNEL);
		if (buf == NULL) {
			ptr = kzalloc(req.size * 4, GFP_KERNEL);
			if (ptr == NULL) {
				pr_alert("No memory for data\n");
				err = -ENOMEM;
				break;
			}
			buf = ptr;
		}

		/* Copy user data to local buffer */
		if (copy_from_user(buf, (void __user *)req.data,
@@ -306,7 +319,9 @@ qfp_fuse_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		pr_err("Invalid ioctl command.\n");
		return -ENOTTY;
	}
	kfree(buf);

	kfree(ptr);

	return err;
}