From d1f9c16b1a8187110e501c9116d21ffee25c0ba4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Hiram=20Soltren?= <jsoltren@nvidia.com>
Date: Mon, 17 Aug 2015 16:01:44 -0500
Subject: [PATCH] Use secure_getenv(3) to improve security

This patch is in response to the following security vulnerabilities
(CVEs) reported to NVIDIA against libvdpau:

CVE-2015-5198
CVE-2015-5199
CVE-2015-5200

To address these CVEs, this patch:

- replaces all uses of getenv(3) with secure_getenv(3);
- uses secure_getenv(3) when available, with a fallback option;
- protects VDPAU_DRIVER against directory traversal by checking for '/'

On platforms where secure_getenv(3) is not available, the C preprocessor
will print a warning at compile time. Then, a preprocessor macro will
replace secure_getenv(3) with our getenv_wrapper(), which utilizes the check:

  getuid() == geteuid() && getgid() == getegid()

See getuid(2) and getgid(2) for further details.

Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
---
 configure.ac          |  4 ++++
 src/Makefile.am       |  1 +
 src/mesa_dri2.c       |  6 ++++--
 src/util.h            | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/vdpau_wrapper.c   | 28 ++++++++++++++++------------
 trace/vdpau_trace.cpp |  8 +++++---
 6 files changed, 78 insertions(+), 17 deletions(-)
 create mode 100644 src/util.h

Index: libvdpau-0.8/configure.ac
===================================================================
--- libvdpau-0.8.orig/configure.ac
+++ libvdpau-0.8/configure.ac
@@ -6,6 +6,10 @@ AM_MAINTAINER_MODE
 
 AC_CONFIG_HEADERS(config.h)
 
+# Check for secure_getenv
+AC_USE_SYSTEM_EXTENSIONS
+AC_CHECK_FUNCS([__secure_getenv secure_getenv])
+
 # Disable static libraries by default.  Use --enable-static if you really want
 # them.
 AC_DISABLE_STATIC
Index: libvdpau-0.8/src/Makefile.am
===================================================================
--- libvdpau-0.8.orig/src/Makefile.am
+++ libvdpau-0.8/src/Makefile.am
@@ -9,6 +9,7 @@ lib_LTLIBRARIES = libvdpau.la
 
 libvdpau_la_SOURCES = \
     vdpau_wrapper.c \
+    util.h \
     $(DRI2_SOURCES)
 
 if DRI2
Index: libvdpau-0.8/src/mesa_dri2.c
===================================================================
--- libvdpau-0.8.orig/src/mesa_dri2.c
+++ libvdpau-0.8/src/mesa_dri2.c
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2008 Red Hat, Inc.
- * Copyright © 2010 NVIDIA Corporation
+ * Copyright © 2010-2015 NVIDIA Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Soft-
@@ -30,6 +30,7 @@
  * Authors:
  *   Kristian Høgsberg (krh@redhat.com)
  *   Modified for VDPAU by Aaron Plattner (aplattner@nvidia.com)
+ *   and José Hiram Soltren (jsoltren@nvidia.com)
  */
 
 
@@ -39,6 +40,7 @@
 #include <X11/extensions/extutil.h>
 #include <X11/extensions/dri2proto.h>
 #include "mesa_dri2.h"
+#include "util.h"
 
 static char dri2ExtensionName[] = DRI2_NAME;
 static XExtensionInfo *dri2Info;
@@ -130,7 +132,7 @@ _vdp_DRI2Connect(Display * dpy, XID wind
    req->driverType = DRI2DriverVDPAU;
 #ifdef DRI2DriverPrimeShift
    {
-      char *prime = getenv("DRI_PRIME");
+      char *prime = secure_getenv("DRI_PRIME");
       if (prime) {
          unsigned int primeid;
          errno = 0;
Index: libvdpau-0.8/src/util.h
===================================================================
--- /dev/null
+++ libvdpau-0.8/src/util.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+
+static char * getenv_wrapper(const char *name)
+{
+    if (getuid() == geteuid() && getgid() == getegid()) {
+        return getenv(name);
+    }
+    else {
+        return NULL;
+    }
+}
+
+#ifndef HAVE_SECURE_GETENV
+#  ifdef HAVE___SECURE_GETENV
+#    define secure_getenv __secure_getenv
+#  else
+#    warning Neither secure_getenv nor __secure_getenv is available.
+#    define secure_getenv getenv_wrapper
+#  endif
+#endif
Index: libvdpau-0.8/src/vdpau_wrapper.c
===================================================================
--- libvdpau-0.8.orig/src/vdpau_wrapper.c
+++ libvdpau-0.8/src/vdpau_wrapper.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 NVIDIA, Corporation
+ * Copyright (c) 2008-2015 NVIDIA Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -36,6 +36,7 @@
 #include "mesa_dri2.h"
 #include <X11/Xlib.h>
 #endif
+#include "util.h"
 
 typedef void SetDllHandle(
     void * driver_dll_handle
@@ -114,7 +115,12 @@ static VdpStatus _vdp_open_driver(
     char const * vdpau_trace;
     char const * func_name;
 
-    vdpau_driver = getenv("VDPAU_DRIVER");
+    vdpau_driver = secure_getenv("VDPAU_DRIVER");
+    if (vdpau_driver) {
+        if (strchr(vdpau_driver, '/')) {
+            vdpau_driver = NULL;
+        }
+    }
     if (!vdpau_driver) {
         vdpau_driver = vdpau_driver_dri2 =
             _vdp_get_driver_name_from_dri2(display, screen);
@@ -123,15 +129,13 @@ static VdpStatus _vdp_open_driver(
         vdpau_driver = "nvidia";
     }
 
-    if (geteuid() == getuid()) {
-        /* don't allow setuid apps to use VDPAU_DRIVER_PATH */
-        vdpau_driver_path = getenv("VDPAU_DRIVER_PATH");
-        if (vdpau_driver_path &&
-            snprintf(vdpau_driver_lib, sizeof(vdpau_driver_lib),
-                     DRIVER_LIB_FORMAT, vdpau_driver_path, vdpau_driver) <
-                sizeof(vdpau_driver_lib)) {
-            _vdp_driver_dll = dlopen(vdpau_driver_lib, RTLD_NOW | RTLD_GLOBAL);
-        }
+    /* Don't allow setuid apps to use VDPAU_DRIVER_PATH */
+    vdpau_driver_path = secure_getenv("VDPAU_DRIVER_PATH");
+    if (vdpau_driver_path &&
+        snprintf(vdpau_driver_lib, sizeof(vdpau_driver_lib),
+                 DRIVER_LIB_FORMAT, vdpau_driver_path, vdpau_driver) <
+            sizeof(vdpau_driver_lib)) {
+        _vdp_driver_dll = dlopen(vdpau_driver_lib, RTLD_NOW | RTLD_GLOBAL);
     }
 
     /* Fallback to VDPAU_MODULEDIR when VDPAU_DRIVER_PATH is not set,
@@ -174,7 +178,7 @@ static VdpStatus _vdp_open_driver(
 
     _vdp_backend_dll = _vdp_driver_dll;
 
-    vdpau_trace = getenv("VDPAU_TRACE");
+    vdpau_trace = secure_getenv("VDPAU_TRACE");
     if (vdpau_trace && atoi(vdpau_trace)) {
         SetDllHandle * set_dll_handle;
 
Index: libvdpau-0.8/trace/vdpau_trace.cpp
===================================================================
--- libvdpau-0.8.orig/trace/vdpau_trace.cpp
+++ libvdpau-0.8/trace/vdpau_trace.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 NVIDIA, Corporation
+ * Copyright (c) 2008-2015 NVIDIA Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -31,6 +31,8 @@
 #include <string.h>
 #include <vdpau/vdpau_x11.h>
 
+#include "../src/util.h"
+
 #define _VDP_TRACE_ARSIZE(_x_) ((sizeof (_x_)) / (sizeof ((_x_)[0])))
 
 #if DEBUG
@@ -4558,13 +4560,13 @@ VdpStatus vdp_trace_device_create_x11(
     }
     else {
         _vdp_cap_data.level = 0;
-        char const * vdpau_trace = getenv("VDPAU_TRACE");
+        char const * vdpau_trace = secure_getenv("VDPAU_TRACE");
         if (vdpau_trace) {
             _vdp_cap_data.level = atoi(vdpau_trace);
         }
 
         _vdp_cap_data.fp = 0;
-        char const * vdpau_trace_file = getenv("VDPAU_TRACE_FILE");
+        char const * vdpau_trace_file = secure_getenv("VDPAU_TRACE_FILE");
         if (vdpau_trace_file && strlen(vdpau_trace_file)) {
             if (vdpau_trace_file[0] == '&') {
                 int fd = atoi(&vdpau_trace_file[1]);
