video: tegra: host: validate error notifier offset
Konsta Holtta [Tue, 8 Mar 2016 11:56:19 +0000 (13:56 +0200)]
Make sure that the notifier object fits within the supplied buffer.

Bug 1739183

Change-Id: Ifbf46eddea86bedf0236851ea1c3f73e5f820beb
Signed-off-by: Konsta Holtta <kholtta@nvidia.com>
Reviewed-on: http://git-master/r/1026409
(cherry picked from commit 4086d2137e9b51137aa335fa264d924c73dea5fc)
Reviewed-on: http://git-master/r/1029074
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
Reviewed-by: Shridhar Rasal <srasal@nvidia.com>
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-by: Arto Merilainen <amerilainen@nvidia.com>

drivers/video/tegra/host/bus_client.c

index 6343843..973b8f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Tegra Graphics Host Client Module
  *
- * Copyright (c) 2010-2014, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2010-2016, NVIDIA Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -322,10 +322,12 @@ void nvhost_free_error_notifiers(struct nvhost_channel *ch)
 }
 
 static int nvhost_init_error_notifier(struct nvhost_channel *ch,
-               struct nvhost_set_error_notifier *args) {
+               struct nvhost_set_error_notifier *args)
+{
+       u64 end = args->offset + sizeof(struct nvhost_notification);
+       struct dma_buf *dmabuf;
        void *va;
 
-       struct dma_buf *dmabuf;
        if (!args->mem) {
                dev_err(&ch->dev->dev, "invalid memory handle\n");
                return -EINVAL;
@@ -333,14 +335,20 @@ static int nvhost_init_error_notifier(struct nvhost_channel *ch,
 
        dmabuf = dma_buf_get(args->mem);
 
-       if (ch->error_notifier_ref)
-               nvhost_free_error_notifiers(ch);
-
        if (IS_ERR(dmabuf)) {
                dev_err(&ch->dev->dev, "Invalid handle: %d\n", args->mem);
                return -EINVAL;
        }
 
+       if (end > dmabuf->size || end < sizeof(struct nvhost_notification)) {
+               dma_buf_put(dmabuf);
+               pr_err("%s: invalid offset\n", __func__);
+               return -EINVAL;
+       }
+
+       if (ch->error_notifier_ref)
+               nvhost_free_error_notifiers(ch);
+
        /* map handle */
        va = dma_buf_vmap(dmabuf);
        if (!va) {