From: Gary King Date: Mon, 11 Oct 2010 21:22:35 +0000 (-0700) Subject: video: tegra: nvmap: fix read failures, super user and noref pinning X-Git-Tag: firefly_0821_release~9833^2~157^2~12 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=9f2af3bee9b5bddb6b54040f28c09350c8dd9e38;p=firefly-linux-kernel-4.4.55.git video: tegra: nvmap: fix read failures, super user and noref pinning a >= vs > error when checking the operating region of the read and write ioctls was causing failures when reading the last byte of a handle. the super-user node (knvmap) wasn't registered correctly due to a cut- and-paste error, and the regular user node was assigned super-user priveleges. noref pinning wasn't correctly validating that the specified handle existed before pinning it, which caused the reference count for the handle to become imbalanced on a subsequent unpin Change-Id: I9985b85023705b00389a53fb962c3b60d62da6b8 Signed-off-by: Gary King --- diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c index 7419731a7c52..506aef8408a9 100644 --- a/drivers/video/tegra/nvmap/nvmap.c +++ b/drivers/video/tegra/nvmap/nvmap.c @@ -225,12 +225,17 @@ int nvmap_pin_ids(struct nvmap_client *client, if (ref) { atomic_inc(&ref->pin); nvmap_handle_get(h[i]); - } else if (!client->super && (h[i]->owner != client) && - !h[i]->global) { - ret = -EPERM; } else { - nvmap_warn(client, "%s pinning unreferenced handle " - "%p\n", current->group_leader->comm, h[i]); + struct nvmap_handle *verify; + nvmap_ref_unlock(client); + verify = nvmap_validate_get(client, ids[i]); + if (verify) + nvmap_warn(client, "%s pinning unreferenced " + "handle %p\n", + current->group_leader->comm, h[i]); + else + ret = -EPERM; + nvmap_ref_lock(client); } } nvmap_ref_unlock(client); diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c index b84a788dd33b..c6669ed86c24 100644 --- a/drivers/video/tegra/nvmap/nvmap_dev.c +++ b/drivers/video/tegra/nvmap/nvmap_dev.c @@ -353,6 +353,8 @@ struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client, if ((unsigned long)h == id) { if (client->super || h->global || (h->owner == client)) h = nvmap_handle_get(h); + else + h = NULL; spin_unlock(&client->dev->handle_lock); return h; } @@ -696,9 +698,9 @@ static int nvmap_probe(struct platform_device *pdev) dev->dev_user.parent = &pdev->dev; dev->dev_super.minor = MISC_DYNAMIC_MINOR; - dev->dev_super.name = "kvmap"; - dev->dev_user.fops = &nvmap_super_fops; - dev->dev_user.parent = &pdev->dev; + dev->dev_super.name = "knvmap"; + dev->dev_super.fops = &nvmap_super_fops; + dev->dev_super.parent = &pdev->dev; dev->handles = RB_ROOT; diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c index 9051803aa68d..b943065a44c0 100644 --- a/drivers/video/tegra/nvmap/nvmap_ioctl.c +++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c @@ -459,7 +459,8 @@ static int cache_maint(struct nvmap_client *client, struct nvmap_handle *h, } if (h->flags == NVMAP_HANDLE_UNCACHEABLE || - h->flags == NVMAP_HANDLE_WRITE_COMBINE) + h->flags == NVMAP_HANDLE_WRITE_COMBINE || + start == end) goto out; if (WARN_ON_ONCE(op == NVMAP_CACHE_OP_WB_INV)) @@ -607,7 +608,7 @@ static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h, return PTR_ERR(pte); while (count--) { - if (h_offs + elem_size >= h->size) { + if (h_offs + elem_size > h->size) { nvmap_warn(client, "read/write outside of handle\n"); ret = -EFAULT; break;