From 0e10afd27d4a9fb4e358ba29322dfbfee5972484 Mon Sep 17 00:00:00 2001 From: Ikey Doherty Date: Thu, 9 Nov 2017 22:43:12 +0000 Subject: [PATCH] intercept: Teach new snapd code how to handle NVIDIA issues This performs the necessary internal redirections for biarch NVIDIA libraries, as the primary directories do not contain the libraries. Solus libraries will typically be resolved through "secure execution mode", which is due to our security builds (full relro, etc.) This change allows LSI to safely redirect NVIDIA linking requests for the Steam client, using the hostfs libGL libraries dynamically. This supports the ongoing work for issue #30. Signed-off-by: Ikey Doherty --- src/intercept/intercept.h | 14 ++++++- src/intercept/main.c | 5 ++- src/intercept/snapd.c | 81 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/intercept/intercept.h b/src/intercept/intercept.h index 29ef0ff..edf6666 100644 --- a/src/intercept/intercept.h +++ b/src/intercept/intercept.h @@ -20,12 +20,22 @@ * @note This must run for all processes, as we handle libGL interception. * * @param name Original search name - * @param flag rtld-audit flags * @param soname Pointer to store the final soname in * * @returns True if we performed any redirection, to stop further processing. */ -bool lsi_override_snapd(const char *name, unsigned int flag, const char **soname); +bool lsi_override_snapd_gl(const char *name, const char **soname); + +/** + * Handle redirection of snapd NVIDIA libraries when they can't be found + * sanely due to compounded LD_LIBRARY_PATH abuse. + * + * @param name Original search name + * @param soname Pointer to store the final soname in + * + * @returns True if we performed any redirection, to stop further processing. + */ +bool lsi_override_snapd_nvidia(const char *name, const char **soname); /* * Editor modelines - https://www.wireshark.org/tools/modelines.html diff --git a/src/intercept/main.c b/src/intercept/main.c index 577ccf7..5715d1f 100644 --- a/src/intercept/main.c +++ b/src/intercept/main.c @@ -586,7 +586,10 @@ _nica_public_ char *la_objsearch(const char *name, __lsi_unused__ uintptr_t *coo const char *out_name = NULL; /* Only attempt snapd overrides if snapd support is enabled */ - if (lsi_override_snapd(name, flag, &out_name)) { + if (lsi_override_snapd_gl(name, &out_name)) { + return (char *)out_name; + } + if (lsi_override_snapd_nvidia(name, &out_name)) { return (char *)out_name; } #endif diff --git a/src/intercept/snapd.c b/src/intercept/snapd.c index 2899ac2..6b495fa 100644 --- a/src/intercept/snapd.c +++ b/src/intercept/snapd.c @@ -11,7 +11,9 @@ #define _GNU_SOURCE +#include #include +#include #include #include @@ -74,7 +76,84 @@ static const char *libgl_mesa_table[] = { #endif }; -bool lsi_override_snapd(const char *name, __lsi_unused__ unsigned int flag, const char **soname) +/** + * These are the NVIDIA libraries will attempt to redirect on demand. + */ +static const char *libgl_nvidia_matches[] = { + "libGLdispatch", "libnv", "NVIDIA", "nvidia.so", "cuda", "GLX", +}; + +bool lsi_override_snapd_nvidia(const char *name, const char **soname) +{ + const char *nvidia_target_dir = NULL; + static char path_lookup[PATH_MAX]; + static char path_copy[PATH_MAX]; + char *small_name = NULL; + bool match = false; + + /* Only mangle when we start looking for paths */ + if (!strstr(name, "/")) { + return false; + } + + /* Must be proper versioned libs */ + if (!strstr(name, ".so.")) { + return false; + } + + /* If this guy exists we don't actually care.. */ + if (lsi_file_exists(name)) { + return false; + } + + /* Check if we have some basic pattern for an NVIDIA library here */ + for (size_t i = 0; i < ARRAY_SIZE(libgl_nvidia_matches); i++) { + if (strstr(name, libgl_nvidia_matches[i])) { + match = true; + break; + } + } + + /* Unwanted library */ + if (!match) { + return false; + } + +#if UINTPTR_MAX == 0xffffffffffffffff + /* 64-bit libdir */ + nvidia_target_dir = "/var/lib/snapd/lib/gl"; +#else + /* 32-bit libdir */ + nvidia_target_dir = "/var/lib/snapd/lib/gl/32"; +#endif + + /* Grab the link name */ + if (!strcpy(path_copy, name)) { + return false; + } + small_name = basename(path_copy); + + if (snprintf(path_lookup, sizeof(path_lookup), "%s/%s", nvidia_target_dir, small_name) < + 0) { + return false; + } + + /* Sod all we can do here */ + if (!lsi_file_exists(path_lookup)) { + lsi_log_error("Missing NVIDIA file: %s (%s)", name, path_lookup); + return false; + } + + *soname = path_lookup; + lsi_log_debug( + "Enforcing NVIDIA snapd driver links: \033[31;1m%s\033[0m -> \033[34;1m%s\033[0m", + name, + path_lookup); + + return true; +} + +bool lsi_override_snapd_gl(const char *name, const char **soname) { for (size_t i = 0; i < ARRAY_SIZE(libgl_source_table); i++) { const char *source = libgl_source_table[i];