media: tegra: nvavp: Fix UAF issue.
Jitendra Kumar [Thu, 27 Oct 2016 08:35:00 +0000 (13:35 +0530)]
Use locking to protect generated fd, so that it can't be
freed before channel open completes. Also add null value checks
in release call.

CVE-2016-8449 (A-31798848)
Bug 1830023
Bug 1849492

Change-Id: Ie6e2b29c7132fdfdff6b0bfa75440bd43afffd5f
Signed-off-by: Gagan Grover <ggrover@nvidia.com>
Reviewed-on: http://git-master/r/1285817
(cherry picked from commit 2ff0fdedfd65f269359d6540df4662e958681aa7)
Reviewed-on: http://git-master/r/1299505
(cherry picked from commit ea1af2ce5a746bda36205357c9e0adaf527026bb)
Reviewed-on: http://git-master/r/1311418
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Vinayak Pane <vpane@nvidia.com>

drivers/media/platform/tegra/nvavp/nvavp_dev.c

index 05e8100..2a7b4ab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * drivers/media/video/tegra/nvavp/nvavp_dev.c
  *
- * Copyright (c) 2011-2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION.  All rights reserved.
  *
  * This file is licensed under the terms of the GNU General Public License
  * version 2. This program is licensed "as is" without any warranty of any
@@ -2121,10 +2121,17 @@ out:
 
 static int tegra_nvavp_video_release(struct inode *inode, struct file *filp)
 {
-       struct nvavp_clientctx *clientctx = filp->private_data;
-       struct nvavp_info *nvavp = clientctx->nvavp;
+       struct nvavp_clientctx *clientctx;
+       struct nvavp_info *nvavp;
        int ret = 0;
 
+       clientctx = filp->private_data;
+       if (!clientctx)
+               return ret;
+       nvavp = clientctx->nvavp;
+       if (!nvavp)
+               return ret;
+
        mutex_lock(&nvavp->open_lock);
        filp->private_data = NULL;
        ret = tegra_nvavp_release(clientctx, NVAVP_VIDEO_CHANNEL);
@@ -2137,10 +2144,17 @@ static int tegra_nvavp_video_release(struct inode *inode, struct file *filp)
 static int tegra_nvavp_audio_release(struct inode *inode,
                                          struct file *filp)
 {
-       struct nvavp_clientctx *clientctx = filp->private_data;
-       struct nvavp_info *nvavp = clientctx->nvavp;
+       struct nvavp_clientctx *clientctx;
+       struct nvavp_info *nvavp;
        int ret = 0;
 
+       clientctx = filp->private_data;
+       if (!clientctx)
+               return ret;
+       nvavp = clientctx->nvavp;
+       if (!nvavp)
+               return ret;
+
        mutex_lock(&nvavp->open_lock);
        filp->private_data = NULL;
        ret = tegra_nvavp_release(clientctx, NVAVP_AUDIO_CHANNEL);
@@ -2152,9 +2166,15 @@ static int tegra_nvavp_audio_release(struct inode *inode,
 int tegra_nvavp_audio_client_release(nvavp_clientctx_t client)
 {
        struct nvavp_clientctx *clientctx = client;
-       struct nvavp_info *nvavp = clientctx->nvavp;
+       struct nvavp_info *nvavp;
        int ret = 0;
 
+       if (!clientctx)
+               return ret;
+       nvavp = clientctx->nvavp;
+       if (!nvavp)
+               return ret;
+
        mutex_lock(&nvavp->open_lock);
        ret = tegra_nvavp_release(clientctx, NVAVP_AUDIO_CHANNEL);
        mutex_unlock(&nvavp->open_lock);
@@ -2196,10 +2216,8 @@ nvavp_channel_open(struct file *filp, struct nvavp_channel_open_args *arg)
                return err;
        }
 
-       fd_install(fd, file);
-
-       nonseekable_open(file->f_inode, filp);
        mutex_lock(&nvavp->open_lock);
+
        err = tegra_nvavp_open(nvavp,
                (struct nvavp_clientctx **)&file->private_data,
                clientctx->channel_id);
@@ -2209,9 +2227,13 @@ nvavp_channel_open(struct file *filp, struct nvavp_channel_open_args *arg)
                mutex_unlock(&nvavp->open_lock);
                return err;
        }
-       mutex_unlock(&nvavp->open_lock);
 
        arg->channel_fd = fd;
+
+       nonseekable_open(file->f_inode, filp);
+       fd_install(fd, file);
+
+       mutex_unlock(&nvavp->open_lock);
        return err;
 }