diff options
author | Anssi Kalliolahti <akalliolahti@nvidia.com> | 2010-05-20 14:45:03 +0300 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-06-11 16:35:44 -0700 |
commit | c7d7d2960d9f46b6b0cb4f0041a91779ffacc12e (patch) | |
tree | b816560cb8eec362dad043430deb297486aaf1b0 | |
parent | 0ad0f96d590c15c8bbe1165ed8da250edc222a6f (diff) |
nvmap: tighten handle validation before pinning
Added check for handle poison before pinning. This prevents panic
(BUG_ON in _nvmap_handle_pin_locked) when trying to pin already freed
handle.
Bug 684375
Change-Id: I85ba4b37b2f193c19782edeaa562b7f77915cfc4
Reviewed-on: http://git-master/r/2478
Tested-by: Anssi Kalliolahti <akalliolahti@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r-- | drivers/char/nvmap.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/drivers/char/nvmap.c b/drivers/char/nvmap.c index dbd60a1a0d3a..6e1830862b64 100644 --- a/drivers/char/nvmap.c +++ b/drivers/char/nvmap.c @@ -1372,6 +1372,12 @@ struct nvmap_handle_ref *_nvmap_ref_lookup_locked( struct nvmap_file_priv *priv, unsigned long ref) { struct rb_node *n = priv->handle_refs.rb_node; + struct nvmap_handle *h = (struct nvmap_handle *)ref; + + if (unlikely(h->poison != NVDA_POISON)) { + pr_err("%s: handle is poisoned\n", __func__); + return NULL; + } while (n) { struct nvmap_handle_ref *r; @@ -1551,16 +1557,19 @@ static int _nvmap_do_pin(struct nvmap_file_priv *priv, spin_lock(&priv->ref_lock); for (i=0; i<nr && !ret; i++) { r = _nvmap_ref_lookup_locked(priv, refs[i]); - if (!r && (!(priv->su || h[i]->global || - current->group_leader == h[i]->owner))) - ret = -EPERM; - else if (r) atomic_inc(&r->pin); + if (r) atomic_inc(&r->pin); else { - pr_err("%s: %s pinning %s's %uB handle without " - "local context\n", __func__, - current->group_leader->comm, - h[i]->owner->comm, h[i]->orig_size); - } + if ((h[i]->poison != NVDA_POISON) || + (!(priv->su || h[i]->global || + current->group_leader == h[i]->owner))) + ret = -EPERM; + else { + pr_err("%s: %s pinning %s's %uB handle without " + "local context\n", __func__, + current->group_leader->comm, + h[i]->owner->comm, h[i]->orig_size); + } + } } while (ret && i--) { |