<div dir="ltr"><div><div><div><div>Sent that a little too soon; please consider "Reviewed-by: Ben Crocker <<a href="mailto:bcrocker@redhat.com">bcrocker@redhat.com</a>>" to be<br></div>added after each of the "Signed-off-by: Nicolai Haehnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>>" lines.<br><br></div>Also please note that I rebased Nicolai's original patch, <a href="https://patchwork.freedesktop.org/series/18684/">https://patchwork.freedesktop.org/series/18684/</a>,<br></div>against a very recent copy of master.<br><br></div>  Thanks,<br><div>  Ben<br><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Mar 8, 2018 at 4:53 PM, Ben Crocker <span dir="ltr"><<a href="mailto:bcrocker@redhat.com" target="_blank">bcrocker@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Nicolai Hähnle <<a href="mailto:nhaehnle@gmail.com">nhaehnle@gmail.com</a>><br>
<div><div class="h5"><br>
From: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
<br>
Having different types of code all trying to check for elevated privileges<br>
is a bad idea. This implementation is the most thorough one.<br>
<br>
Signed-off-by: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
---<br>
 hw/xfree86/common/xf86Init.c | 59 +-----------------------------<wbr>-----------<br>
 include/os.h                 |  3 +++<br>
 os/utils.c                   | 63 ++++++++++++++++++++++++++++++<wbr>++++++++++++++<br>
 3 files changed, 67 insertions(+), 58 deletions(-)<br>
<br>
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c<br>
index e61fe66..758b926 100644<br>
--- a/hw/xfree86/common/xf86Init.c<br>
+++ b/hw/xfree86/common/xf86Init.c<br>
@@ -230,78 +230,21 @@ xf86PrintBanner(void)<br>
     xf86ErrorFVerb(0, "Current version of pixman: %s\n",<br>
                    pixman_version_string());<br>
     xf86ErrorFVerb(0, "\tBefore reporting problems, check "<br>
                    "" __VENDORDWEBSUPPORT__ "\n"<br>
                    "\tto make sure that you have the latest version.\n");<br>
 }<br>
<br>
 Bool<br>
 xf86PrivsElevated(void)<br>
 {<br>
-    static Bool privsTested = FALSE;<br>
-    static Bool privsElevated = TRUE;<br>
-<br>
-    if (!privsTested) {<br>
-#if defined(WIN32)<br>
-        privsElevated = FALSE;<br>
-#else<br>
-        if ((getuid() != geteuid()) || (getgid() != getegid())) {<br>
-            privsElevated = TRUE;<br>
-        }<br>
-        else {<br>
-#if defined(HAVE_ISSETUGID)<br>
-            privsElevated = issetugid();<br>
-#elif defined(HAVE_GETRESUID)<br>
-            uid_t ruid, euid, suid;<br>
-            gid_t rgid, egid, sgid;<br>
-<br>
-            if ((getresuid(&ruid, &euid, &suid) == 0) &&<br>
-                (getresgid(&rgid, &egid, &sgid) == 0)) {<br>
-                privsElevated = (euid != suid) || (egid != sgid);<br>
-            }<br>
-            else {<br>
-                printf("Failed getresuid or getresgid");<br>
-                /* Something went wrong, make defensive assumption */<br>
-                privsElevated = TRUE;<br>
-            }<br>
-#else<br>
-            if (getuid() == 0) {<br>
-                /* running as root: uid==euid==0 */<br>
-                privsElevated = FALSE;<br>
-            }<br>
-            else {<br>
-                /*<br>
-                 * If there are saved ID's the process might still be privileged<br>
-                 * even though the above test succeeded. If issetugid() and<br>
-                 * getresgid() aren't available, test this by trying to set<br>
-                 * euid to 0.<br>
-                 */<br>
-                unsigned int oldeuid;<br>
-<br>
-                oldeuid = geteuid();<br>
-<br>
-                if (seteuid(0) != 0) {<br>
-                    privsElevated = FALSE;<br>
-                }<br>
-                else {<br>
-                    if (seteuid(oldeuid) != 0) {<br>
-                        FatalError("Failed to drop privileges.  Exiting\n");<br>
-                    }<br>
-                    privsElevated = TRUE;<br>
-                }<br>
-            }<br>
-#endif<br>
-        }<br>
-#endif<br>
-        privsTested = TRUE;<br>
-    }<br>
-    return privsElevated;<br>
+    return PrivsElevated();<br>
 }<br>
<br>
 static void<br>
</div></div> TrapSignals(void)<br>
 {<br>
     if (xf86Info.notrapSignals) {<br>
         OsSignal(SIGSEGV, SIG_DFL);<br>
         OsSignal(SIGABRT, SIG_DFL);<br>
         OsSignal(SIGILL, SIG_DFL);<br>
 #ifdef SIGEMT<br>
<div><div class="h5">diff --git a/include/os.h b/include/os.h<br>
index d2c41b4..686f6d6 100644<br>
--- a/include/os.h<br>
+++ b/include/os.h<br>
@@ -355,20 +355,23 @@ Fclose(void *);<br>
 extern const char *<br>
 Win32TempDir(void);<br>
<br>
 extern int<br>
 System(const char *cmdline);<br>
<br>
 #define Fopen(a,b) fopen(a,b)<br>
 #define Fclose(a) fclose(a)<br>
 #endif<br>
<br>
+extern _X_EXPORT Bool<br>
+PrivsElevated(void);<br>
+<br>
 extern _X_EXPORT void<br>
 CheckUserParameters(int argc, char **argv, char **envp);<br>
 extern _X_EXPORT void<br>
 CheckUserAuthorization(void);<br>
<br>
 extern _X_EXPORT int<br>
 AddHost(ClientPtr /*client */ ,<br>
         int /*family */ ,<br>
         unsigned /*length */ ,<br>
         const void * /*pAddr */ );<br>
diff --git a/os/utils.c b/os/utils.c<br>
index ac55cd7..024989e 100644<br>
--- a/os/utils.c<br>
+++ b/os/utils.c<br>
@@ -1717,20 +1717,83 @@ System(const char *cmdline)<br>
<br>
     /* Close process and thread handles. */<br>
     CloseHandle(pi.hProcess);<br>
     CloseHandle(pi.hThread);<br>
     free(cmd);<br>
<br>
     return dwExitCode;<br>
 }<br>
 #endif<br>
<br>
+Bool<br>
+PrivsElevated(void)<br>
+{<br>
+    static Bool privsTested = FALSE;<br>
+    static Bool privsElevated = TRUE;<br>
+<br>
+    if (!privsTested) {<br>
+#if defined(WIN32)<br>
+        privsElevated = FALSE;<br>
+#else<br>
+        if ((getuid() != geteuid()) || (getgid() != getegid())) {<br>
+            privsElevated = TRUE;<br>
+        }<br>
+        else {<br>
+#if defined(HAVE_ISSETUGID)<br>
+            privsElevated = issetugid();<br>
+#elif defined(HAVE_GETRESUID)<br>
+            uid_t ruid, euid, suid;<br>
+            gid_t rgid, egid, sgid;<br>
+<br>
+            if ((getresuid(&ruid, &euid, &suid) == 0) &&<br>
+                (getresgid(&rgid, &egid, &sgid) == 0)) {<br>
+                privsElevated = (euid != suid) || (egid != sgid);<br>
+            }<br>
+            else {<br>
+                printf("Failed getresuid or getresgid");<br>
+                /* Something went wrong, make defensive assumption */<br>
+                privsElevated = TRUE;<br>
+            }<br>
+#else<br>
+            if (getuid() == 0) {<br>
+                /* running as root: uid==euid==0 */<br>
+                privsElevated = FALSE;<br>
+            }<br>
+            else {<br>
+                /*<br>
+                 * If there are saved ID's the process might still be privileged<br>
+                 * even though the above test succeeded. If issetugid() and<br>
+                 * getresgid() aren't available, test this by trying to set<br>
+                 * euid to 0.<br>
+                 */<br>
+                unsigned int oldeuid;<br>
+<br>
+                oldeuid = geteuid();<br>
+<br>
+                if (seteuid(0) != 0) {<br>
+                    privsElevated = FALSE;<br>
+                }<br>
+                else {<br>
+                    if (seteuid(oldeuid) != 0) {<br>
+                        FatalError("Failed to drop privileges.  Exiting\n");<br>
+                    }<br>
+                    privsElevated = TRUE;<br>
+                }<br>
+            }<br>
+#endif<br>
+        }<br>
+#endif<br>
+        privsTested = TRUE;<br>
+    }<br>
+    return privsElevated;<br>
+}<br>
+<br>
 /*<br>
  * CheckUserParameters: check for long command line arguments and long<br>
  * environment variables.  By default, these checks are only done when<br>
  * the server's euid != ruid.  In 3.3.x, these checks were done in an<br>
  * external wrapper utility.<br>
  */<br>
<br>
 /* Consider LD* variables insecure? */<br>
 #ifndef REMOVE_ENV_LD<br>
 #define REMOVE_ENV_LD 1<br>
<br>
</div></div>From patchwork Fri Jan 27 13:37:36 2017<br>
Content-Type: text/plain; charset="utf-8"<br>
MIME-Version: 1.0<br>
Content-Transfer-Encoding: 8bit<br>
Subject: [xserver,2/4] os: use PrivsElevated instead of a manual check<br>
From: =?utf-8?q?Nicolai_H=C3=A4hnle?<wbr>= <<a href="mailto:nhaehnle@gmail.com">nhaehnle@gmail.com</a>><br>
X-Patchwork-Id: 135711<br>
Message-Id: <<a href="mailto:1485524258-6482-3-git-send-email-nhaehnle@gmail.com">1485524258-6482-3-git-send-<wbr>email-nhaehnle@gmail.com</a>><br>
To: <a href="mailto:xorg-devel@lists.x.org">xorg-devel@lists.x.org</a><br>
Cc: =?UTF-8?q?Nicolai=20H=C3=<wbr>A4hnle?= <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
Date: Fri, 27 Jan 2017 14:37:36 +0100<br>
<br>
From: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
<span class=""><br>
Signed-off-by: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
---<br>
</span> os/utils.c | 2 +-<br>
 1 file changed, 1 insertion(+), 1 deletion(-)<br>
<br>
diff --git a/os/utils.c b/os/utils.c<br>
index 024989e..05733b0 100644<br>
--- a/os/utils.c<br>
+++ b/os/utils.c<br>
@@ -1861,21 +1861,21 @@ enum BadCode {<br>
 #endif<br>
<span class=""><br>
 void<br>
 CheckUserParameters(int argc, char **argv, char **envp)<br>
</span> {<br>
     enum BadCode bad = NotBad;<br>
     int i = 0, j;<br>
     char *a, *e = NULL;<br>
<br>
 #if CHECK_EUID<br>
-    if (geteuid() == 0 && getuid() != geteuid())<br>
+    if (PrivsElevated())<br>
 #endif<br>
     {<br>
         /* Check each argv[] */<br>
         for (i = 1; i < argc; i++) {<br>
             if (strcmp(argv[i], "-fp") == 0) {<br>
                 i++;            /* continue with next argument. skip the length check */<br>
                 if (i >= argc)<br>
                     break;<br>
             }<br>
             else {<br>
<br>
>From patchwork Fri Jan 27 13:37:37 2017<br>
Content-Type: text/plain; charset="utf-8"<br>
MIME-Version: 1.0<br>
Content-Transfer-Encoding: 8bit<br>
Subject: [xserver, 3/4] xfree86: replace all uses of xf86PrivsElevated with<br>
 PrivsElevated<br>
From: =?utf-8?q?Nicolai_H=C3=A4hnle?<wbr>= <<a href="mailto:nhaehnle@gmail.com">nhaehnle@gmail.com</a>><br>
X-Patchwork-Id: 135712<br>
Message-Id: <<a href="mailto:1485524258-6482-4-git-send-email-nhaehnle@gmail.com">1485524258-6482-4-git-send-<wbr>email-nhaehnle@gmail.com</a>><br>
To: <a href="mailto:xorg-devel@lists.x.org">xorg-devel@lists.x.org</a><br>
Cc: =?UTF-8?q?Nicolai=20H=C3=<wbr>A4hnle?= <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
Date: Fri, 27 Jan 2017 14:37:37 +0100<br>
<br>
From: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
<span class=""><br>
Signed-off-by: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
---<br>
</span> hw/xfree86/common/xf86Config.c |  2 +-<br>
 hw/xfree86/common/xf86Init.c   | 12 +++---------<br>
 hw/xfree86/common/xf86Priv.h   |  2 --<br>
 3 files changed, 4 insertions(+), 12 deletions(-)<br>
<br>
diff --git a/hw/xfree86/common/<wbr>xf86Config.c b/hw/xfree86/common/<wbr>xf86Config.c<br>
index f03acf3..5d2cf0a 100644<br>
--- a/hw/xfree86/common/<wbr>xf86Config.c<br>
+++ b/hw/xfree86/common/<wbr>xf86Config.c<br>
@@ -2309,21 +2309,21 @@ xf86HandleConfigFile(Bool autoconfig)<br>
 #endif<br>
     Bool implicit_layout = FALSE;<br>
     XF86ConfLayoutPtr layout;<br>
<br>
     if (!autoconfig) {<br>
         char *filename, *dirname, *sysdirname;<br>
         const char *filesearch, *dirsearch;<br>
         MessageType filefrom = X_DEFAULT;<br>
         MessageType dirfrom = X_DEFAULT;<br>
<br>
-        if (!xf86PrivsElevated()) {<br>
+        if (!PrivsElevated()) {<br>
             filesearch = ALL_CONFIGPATH;<br>
             dirsearch = ALL_CONFIGDIRPATH;<br>
         }<br>
         else {<br>
             filesearch = RESTRICTED_CONFIGPATH;<br>
             dirsearch = RESTRICTED_CONFIGDIRPATH;<br>
         }<br>
<br>
         if (xf86ConfigFile)<br>
             filefrom = X_CMDLINE;<br>
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c<br>
index 758b926..deed91f 100644<br>
--- a/hw/xfree86/common/xf86Init.c<br>
+++ b/hw/xfree86/common/xf86Init.c<br>
@@ -227,26 +227,20 @@ xf86PrintBanner(void)<br>
 #if defined(BUILDERSTRING)<br>
     xf86ErrorFVerb(0, "%s \n", BUILDERSTRING);<br>
 #endif<br>
<span class="">     xf86ErrorFVerb(0, "Current version of pixman: %s\n",<br>
                    pixman_version_string());<br>
     xf86ErrorFVerb(0, "\tBefore reporting problems, check "<br>
                    "" __VENDORDWEBSUPPORT__ "\n"<br>
                    "\tto make sure that you have the latest version.\n");<br>
 }<br>
<br>
</span>-Bool<br>
-xf86PrivsElevated(void)<br>
-{<br>
-    return PrivsElevated();<br>
-}<br>
-<br>
 static void<br>
 TrapSignals(void)<br>
 {<br>
     if (xf86Info.notrapSignals) {<br>
         OsSignal(SIGSEGV, SIG_DFL);<br>
         OsSignal(SIGABRT, SIG_DFL);<br>
         OsSignal(SIGILL, SIG_DFL);<br>
 #ifdef SIGEMT<br>
         OsSignal(SIGEMT, SIG_DFL);<br>
 #endif<br>
@@ -886,21 +880,21 @@ OsVendorInit(void)<br>
     /* Set stderr to non-blocking. */<br>
 #ifndef O_NONBLOCK<br>
 #if defined(FNDELAY)<br>
 #define O_NONBLOCK FNDELAY<br>
 #elif defined(O_NDELAY)<br>
 #define O_NONBLOCK O_NDELAY<br>
 #endif<br>
<br>
 #ifdef O_NONBLOCK<br>
     if (!beenHere) {<br>
-        if (xf86PrivsElevated()) {<br>
+        if (PrivsElevated()) {<br>
             int status;<br>
<br>
             status = fcntl(fileno(stderr), F_GETFL, 0);<br>
             if (status != -1) {<br>
                 fcntl(fileno(stderr), F_SETFL, status | O_NONBLOCK);<br>
             }<br>
         }<br>
     }<br>
 #endif<br>
 #endif<br>
@@ -1041,21 +1035,21 @@ xf86PrintDefaultModulePath(<wbr>void)<br>
<br>
 static void<br>
 xf86PrintDefaultLibraryPath(<wbr>void)<br>
 {<br>
     ErrorF("%s\n", DEFAULT_LIBRARY_PATH);<br>
 }<br>
<br>
 static void<br>
 xf86CheckPrivs(const char *option, const char *arg)<br>
 {<br>
-    if (xf86PrivsElevated() && !xf86PathIsSafe(arg)) {<br>
+    if (PrivsElevated() && !xf86PathIsSafe(arg)) {<br>
         FatalError("\nInvalid argument for %s - \"%s\"\n"<br>
                     "\tWith elevated privileges %s must specify a relative path\n"<br>
                     "\twithout any \"..\" elements.\n\n", option, arg, option);<br>
     }<br>
 }<br>
<br>
 /*<br>
  * ddxProcessArgument --<br>
  *     Process device-dependent command line args. Returns 0 if argument is<br>
  *      not device dependent, otherwise Count of number of elements of argv<br>
@@ -1342,21 +1336,21 @@ ddxProcessArgument(int argc, char **argv, int i)<br>
  *     Print out correct use of device dependent commandline options.<br>
  *      Maybe the user now knows what really to do ...<br>
  */<br>
<br>
 void<br>
 ddxUseMsg(void)<br>
 {<br>
     ErrorF("\n");<br>
     ErrorF("\n");<br>
     ErrorF("Device Dependent Usage\n");<br>
-    if (!xf86PrivsElevated()) {<br>
+    if (!PrivsElevated()) {<br>
         ErrorF("-modulepath paths      specify the module search path\n");<br>
         ErrorF("-logfile file          specify a log file name\n");<br>
         ErrorF("-configure             probe for devices and write an "<br>
                XCONFIGFILE "\n");<br>
         ErrorF<br>
             ("-showopts              print available options for all installed drivers\n");<br>
     }<br>
     ErrorF<br>
         ("-config file           specify a configuration file, relative to the\n");<br>
     ErrorF("                       " XCONFIGFILE<br>
diff --git a/hw/xfree86/common/xf86Priv.h b/hw/xfree86/common/xf86Priv.h<br>
index c1f8a18..d78e8f6 100644<br>
--- a/hw/xfree86/common/xf86Priv.h<br>
+++ b/hw/xfree86/common/xf86Priv.h<br>
@@ -154,16 +154,14 @@ xf86CloseLog(enum ExitCode error);<br>
<br>
 /* xf86Init.c */<br>
 extern _X_EXPORT Bool<br>
 xf86LoadModules(const char **list, void **optlist);<br>
 extern _X_EXPORT int<br>
 xf86SetVerbosity(int verb);<br>
 extern _X_EXPORT int<br>
 xf86SetLogVerbosity(int verb);<br>
 extern _X_EXPORT Bool<br>
 xf86CallDriverProbe(struct _DriverRec *drv, Bool detect_only);<br>
-extern _X_EXPORT Bool<br>
-xf86PrivsElevated(void);<br>
<br>
 #endif                          /* _NO_XF86_PROTOTYPES */<br>
<br>
 #endif                          /* _XF86PRIV_H */<br>
<br>
>From patchwork Fri Jan 27 13:37:38 2017<br>
Content-Type: text/plain; charset="utf-8"<br>
MIME-Version: 1.0<br>
Content-Transfer-Encoding: 8bit<br>
Subject: [xserver,4/4] glx: honor LIBGL_DRIVERS_PATH when loading DRI drivers<br>
From: =?utf-8?q?Nicolai_H=C3=A4hnle?<wbr>= <<a href="mailto:nhaehnle@gmail.com">nhaehnle@gmail.com</a>><br>
X-Patchwork-Id: 135713<br>
Message-Id: <<a href="mailto:1485524258-6482-5-git-send-email-nhaehnle@gmail.com">1485524258-6482-5-git-send-<wbr>email-nhaehnle@gmail.com</a>><br>
To: <a href="mailto:xorg-devel@lists.x.org">xorg-devel@lists.x.org</a><br>
Cc: =?UTF-8?q?Nicolai=20H=C3=<wbr>A4hnle?= <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
Date: Fri, 27 Jan 2017 14:37:38 +0100<br>
<br>
From: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
<br>
Allow switching to another driver build without a full installation.<br>
<br>
Glamor already takes LIBGL_DRIVERS_PATH into account, so this change<br>
makes sure that the same driver is used in both parts of the server.<br>
<span class=""><br>
Signed-off-by: Nicolai Hähnle <<a href="mailto:nicolai.haehnle@amd.com">nicolai.haehnle@amd.com</a>><br>
---<br>
</span> glx/glxdricommon.c | 38 ++++++++++++++++++++++++++++++<wbr>++++----<br>
 1 file changed, 34 insertions(+), 4 deletions(-)<br>
<br>
diff --git a/glx/glxdricommon.c b/glx/glxdricommon.c<br>
index f6c6fcd..a370845 100644<br>
--- a/glx/glxdricommon.c<br>
+++ b/glx/glxdricommon.c<br>
@@ -241,28 +241,58 @@ static const char dri_driver_path[] = DRI_DRIVER_PATH;<br>
 void *<br>
 glxProbeDriver(const char *driverName,<br>
                void **coreExt, const char *coreName, int coreVersion,<br>
                void **renderExt, const char *renderName, int renderVersion)<br>
 {<br>
     int i;<br>
     void *driver;<br>
     char filename[PATH_MAX];<br>
     char *get_extensions_name;<br>
     const __DRIextension **extensions = NULL;<br>
+    const char *path = NULL;<br>
+<br>
+    /* Search in LIBGL_DRIVERS_PATH if we're not setuid. */<br>
+    if (!PrivsElevated())<br>
+        path = getenv("LIBGL_DRIVERS_PATH");<br>
+<br>
+    if (!path)<br>
+        path = dri_driver_path;<br>
+<br>
+    do {<br>
+        const char *next;<br>
+        int path_len;<br>
+<br>
+        next = strchr(path, ':');<br>
+        if (next) {<br>
+            path_len = next - path;<br>
+            next++;<br>
+        } else {<br>
+            path_len = strlen(path);<br>
+            next = NULL;<br>
+        }<br>
<br>
-    snprintf(filename, sizeof filename, "%s/%s_dri.so",<br>
-             dri_driver_path, driverName);<br>
+        snprintf(filename, sizeof filename, "%.*s/%s_dri.so", path_len, path,<br>
+                 driverName);<br>
+<br>
+        driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);<br>
+        if (driver != NULL)<br>
+            break;<br>
<br>
-    driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);<br>
-    if (driver == NULL) {<br>
         LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",<br>
                    filename, dlerror());<br>
+<br>
+        path = next;<br>
+    } while (path);<br>
+<br>
+    if (driver == NULL) {<br>
+        LogMessage(X_ERROR, "AIGLX error: unable to load driver %s\n",<br>
+                  driverName);<br>
         goto cleanup_failure;<br>
     }<br>
<br>
     if (asprintf(&get_extensions_<wbr>name, "%s_%s",<br>
                  __DRI_DRIVER_GET_EXTENSIONS, driverName) != -1) {<br>
         const __DRIextension **(*get_extensions)(void);<br>
<br>
         get_extensions = dlsym(driver, get_extensions_name);<br>
         if (get_extensions)<br>
             extensions = get_extensions();<br>
</blockquote></div><br></div>