github.com/tompreston/snapd@v0.0.0-20210817193607-954edfcb9611/cmd/snap-confine/mount-support-nvidia.c (about)

     1  /*
     2   * Copyright (C) 2015 Canonical Ltd
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License version 3 as
     6   * published by the Free Software Foundation.
     7   *
     8   * This program is distributed in the hope that it will be useful,
     9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11   * GNU General Public License for more details.
    12   *
    13   * You should have received a copy of the GNU General Public License
    14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15   *
    16   */
    17  
    18  #include "config.h"
    19  #include "mount-support-nvidia.h"
    20  
    21  #include <errno.h>
    22  #include <fcntl.h>
    23  #include <glob.h>
    24  #include <stdlib.h>
    25  #include <string.h>
    26  #include <sys/mount.h>
    27  #include <sys/stat.h>
    28  #include <sys/types.h>
    29  #include <stdint.h>
    30  #include <unistd.h>
    31  /* POSIX version of basename() and dirname() */
    32  #include <libgen.h>
    33  
    34  #include "../libsnap-confine-private/classic.h"
    35  #include "../libsnap-confine-private/cleanup-funcs.h"
    36  #include "../libsnap-confine-private/string-utils.h"
    37  #include "../libsnap-confine-private/utils.h"
    38  
    39  #define SC_NVIDIA_DRIVER_VERSION_FILE "/sys/module/nvidia/version"
    40  
    41  // note: if the parent dir changes to something other than
    42  // the current /var/lib/snapd/lib then sc_mkdir_and_mount_and_bind
    43  // and sc_mkdir_and_mount_and_bind need updating.
    44  #define SC_LIB "/var/lib/snapd/lib"
    45  #define SC_LIBGL_DIR   SC_LIB "/gl"
    46  #define SC_LIBGL32_DIR SC_LIB "/gl32"
    47  #define SC_VULKAN_DIR  SC_LIB "/vulkan"
    48  #define SC_GLVND_DIR  SC_LIB "/glvnd"
    49  
    50  #define SC_VULKAN_SOURCE_DIR "/usr/share/vulkan"
    51  #define SC_EGL_VENDOR_SOURCE_DIR "/usr/share/glvnd"
    52  
    53  // Location for NVIDIA vulkan files (including _wayland)
    54  static const char *vulkan_globs[] = {
    55  	"icd.d/*nvidia*.json",
    56  };
    57  
    58  static const size_t vulkan_globs_len =
    59      sizeof vulkan_globs / sizeof *vulkan_globs;
    60  
    61  // Location of EGL vendor files
    62  static const char *egl_vendor_globs[] = {
    63  	"egl_vendor.d/*nvidia*.json",
    64  };
    65  
    66  static const size_t egl_vendor_globs_len =
    67      sizeof egl_vendor_globs / sizeof *egl_vendor_globs;
    68  
    69  #if defined(NVIDIA_BIARCH) || defined(NVIDIA_MULTIARCH)
    70  
    71  // List of globs that describe nvidia userspace libraries.
    72  // This list was compiled from the following packages.
    73  //
    74  // https://www.archlinux.org/packages/extra/x86_64/nvidia-304xx-libgl/files/
    75  // https://www.archlinux.org/packages/extra/x86_64/nvidia-304xx-utils/files/
    76  // https://www.archlinux.org/packages/extra/x86_64/nvidia-340xx-libgl/files/
    77  // https://www.archlinux.org/packages/extra/x86_64/nvidia-340xx-utils/files/
    78  // https://www.archlinux.org/packages/extra/x86_64/nvidia-libgl/files/
    79  // https://www.archlinux.org/packages/extra/x86_64/nvidia-utils/files/
    80  //
    81  // FIXME: this doesn't yet work with libGLX and libglvnd redirector
    82  // FIXME: this still doesn't work with the 361 driver
    83  static const char *nvidia_globs[] = {
    84  	"libEGL.so*",
    85  	"libEGL_nvidia.so*",
    86  	"libGL.so*",
    87  	"libOpenGL.so*",
    88  	"libGLESv1_CM.so*",
    89  	"libGLESv1_CM_nvidia.so*",
    90  	"libGLESv2.so*",
    91  	"libGLESv2_nvidia.so*",
    92  	"libGLX_indirect.so*",
    93  	"libGLX_nvidia.so*",
    94  	"libGLX.so*",
    95  	"libGLdispatch.so*",
    96  	"libGLU.so*",
    97  	"libXvMCNVIDIA.so*",
    98  	"libXvMCNVIDIA_dynamic.so*",
    99  	"libnvidia-cfg.so*",
   100  	"libnvidia-compiler.so*",
   101  	"libnvidia-eglcore.so*",
   102  	"libnvidia-egl-wayland*",
   103  	"libnvidia-encode.so*",
   104  	"libnvidia-fatbinaryloader.so*",
   105  	"libnvidia-fbc.so*",
   106  	"libnvidia-glcore.so*",
   107  	"libnvidia-glsi.so*",
   108  	"libnvidia-glvkspirv.so*",
   109  	"libnvidia-ifr.so*",
   110  	"libnvidia-ml.so*",
   111  	"libnvidia-opencl.so*",
   112  	"libnvidia-opticalflow.so*",
   113  	"libnvidia-ptxjitcompiler.so*",
   114  	"libnvidia-rtcore.so*",
   115  	"libnvidia-tls.so*",
   116  	"libnvoptix.so*",
   117  	"tls/libnvidia-tls.so*",
   118  	"vdpau/libvdpau_nvidia.so*",
   119  
   120  	// additional libraries for Tegra
   121  	// https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide/manifest_tx2_tx2i.html
   122  	"libnvdc.so*",
   123  	"libnvos.so*",
   124  	"libnvrm_gpu.so*",
   125  	"libnvimp.so*",
   126  	"libnvrm.so*",
   127  	"libnvrm_graphics.so*",
   128  	// CUDA
   129  	// https://docs.nvidia.com/cuda/#cuda-api-references
   130  	"libcuda.so*",
   131  	"libcudart.so*",
   132  	"libnvcuvid.so*",
   133  	"libcufft.so*",
   134  	"libcublas.so*",
   135  	"libcublasLt.so*",
   136  	"libcusolver.so*",
   137  	"libcuparse.so*",
   138  	"libcurand.so*",
   139  	"libnppc.so*",
   140  	"libnppig.so*",
   141  	"libnppial.so*",
   142  	"libnppicc.so*",
   143  	"libnppidei.so*",
   144  	"libnppist.so*",
   145  	"libnppcif.so*",
   146  	"libnppim.so*",
   147  	"libnppitc.so*",
   148  	"libnvrtc*",
   149  	"libnvrtc-builtins*",
   150  	"libnvToolsExt.so*",
   151  	// libraries for CUDA DNN
   152  	// https://docs.nvidia.com/deeplearning/cudnn/api/index.html
   153  	// https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html
   154  	"libcudnn_adv_infer*",
   155  	"libcudnn_adv_train*",
   156  	"libcudnn_cnn_infer*",
   157  	"libcudnn_cnn_train*",
   158  	"libcudnn_ops_infer*",
   159  	"libcudnn_ops_train*",
   160  };
   161  
   162  static const size_t nvidia_globs_len =
   163      sizeof nvidia_globs / sizeof *nvidia_globs;
   164  
   165  #endif				// defined(NVIDIA_BIARCH) || defined(NVIDIA_MULTIARCH)
   166  
   167  // Populate libgl_dir with a symlink farm to files matching glob_list.
   168  //
   169  // The symbolic links are made in one of two ways. If the library found is a
   170  // file a regular symlink "$libname" -> "/path/to/hostfs/$libname" is created.
   171  // If the library is a symbolic link then relative links are kept as-is but
   172  // absolute links are translated to have "/path/to/hostfs" up front so that
   173  // they work after the pivot_root elsewhere.
   174  //
   175  // The glob list passed to us is produced with paths relative to source dir,
   176  // to simplify the various tie-in points with this function.
   177  static void sc_populate_libgl_with_hostfs_symlinks(const char *libgl_dir,
   178  						   const char *source_dir,
   179  						   const char *glob_list[],
   180  						   size_t glob_list_len)
   181  {
   182  	size_t source_dir_len = strlen(source_dir);
   183  	glob_t glob_res SC_CLEANUP(globfree) = {
   184  		.gl_pathv = NULL
   185  	};
   186  	// Find all the entries matching the list of globs
   187  	for (size_t i = 0; i < glob_list_len; ++i) {
   188  		const char *glob_pattern = glob_list[i];
   189  		char glob_pattern_full[512] = { 0 };
   190  		sc_must_snprintf(glob_pattern_full, sizeof glob_pattern_full,
   191  				 "%s/%s", source_dir, glob_pattern);
   192  
   193  		int err = glob(glob_pattern_full, i ? GLOB_APPEND : 0, NULL,
   194  			       &glob_res);
   195  		// Not all of the files have to be there (they differ depending on the
   196  		// driver version used). Ignore all errors that are not GLOB_NOMATCH.
   197  		if (err != 0 && err != GLOB_NOMATCH) {
   198  			die("cannot search using glob pattern %s: %d",
   199  			    glob_pattern_full, err);
   200  		}
   201  	}
   202  	// Symlink each file found
   203  	for (size_t i = 0; i < glob_res.gl_pathc; ++i) {
   204  		char symlink_name[512] = { 0 };
   205  		char symlink_target[512] = { 0 };
   206  		char prefix_dir[512] = { 0 };
   207  		const char *pathname = glob_res.gl_pathv[i];
   208  		char *pathname_copy1
   209  		    SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname);
   210  		char *pathname_copy2
   211  		    SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname);
   212  		// POSIX dirname() and basename() may modify their input arguments
   213  		char *filename = basename(pathname_copy1);
   214  		char *directory_name = dirname(pathname_copy2);
   215  		sc_must_snprintf(prefix_dir, sizeof prefix_dir, "%s",
   216  				 libgl_dir);
   217  
   218  		if (strlen(directory_name) > source_dir_len) {
   219  			// Additional path elements between source_dir and dirname, meaning the
   220  			// actual file is not placed directly under source_dir but under one or
   221  			// more directories below source_dir. Make sure to recreate the whole
   222  			// prefix
   223  			sc_must_snprintf(prefix_dir, sizeof prefix_dir,
   224  					 "%s%s", libgl_dir,
   225  					 &directory_name[source_dir_len]);
   226  			sc_identity old =
   227  			    sc_set_effective_identity(sc_root_group_identity());
   228  			if (sc_nonfatal_mkpath(prefix_dir, 0755) != 0) {
   229  				die("failed to create prefix path: %s",
   230  				    prefix_dir);
   231  			}
   232  			(void)sc_set_effective_identity(old);
   233  		}
   234  
   235  		struct stat stat_buf;
   236  		int err = lstat(pathname, &stat_buf);
   237  		if (err != 0) {
   238  			die("cannot stat file %s", pathname);
   239  		}
   240  		switch (stat_buf.st_mode & S_IFMT) {
   241  		case S_IFLNK:;
   242  			// Read the target of the symbolic link
   243  			char hostfs_symlink_target[512] = { 0 };
   244  			ssize_t num_read;
   245  			hostfs_symlink_target[0] = 0;
   246  			num_read =
   247  			    readlink(pathname, hostfs_symlink_target,
   248  				     sizeof hostfs_symlink_target - 1);
   249  			if (num_read == -1) {
   250  				die("cannot read symbolic link %s", pathname);
   251  			}
   252  			hostfs_symlink_target[num_read] = 0;
   253  			if (hostfs_symlink_target[0] == '/') {
   254  				sc_must_snprintf(symlink_target,
   255  						 sizeof symlink_target,
   256  						 "/var/lib/snapd/hostfs%s",
   257  						 hostfs_symlink_target);
   258  			} else {
   259  				// Keep relative symlinks as-is, so that they point to -> libfoo.so.0.123
   260  				sc_must_snprintf(symlink_target,
   261  						 sizeof symlink_target, "%s",
   262  						 hostfs_symlink_target);
   263  			}
   264  			break;
   265  		case S_IFREG:
   266  			sc_must_snprintf(symlink_target,
   267  					 sizeof symlink_target,
   268  					 "/var/lib/snapd/hostfs%s", pathname);
   269  			break;
   270  		default:
   271  			debug("ignoring unsupported entry: %s", pathname);
   272  			continue;
   273  		}
   274  		sc_must_snprintf(symlink_name, sizeof symlink_name,
   275  				 "%s/%s", prefix_dir, filename);
   276  		debug("creating symbolic link %s -> %s", symlink_name,
   277  		      symlink_target);
   278  
   279  		// Make sure we don't have some link already (merged GLVND systems)
   280  		if (lstat(symlink_name, &stat_buf) == 0) {
   281  			if (unlink(symlink_name) != 0) {
   282  				die("cannot remove symbolic link target %s",
   283  				    symlink_name);
   284  			}
   285  		}
   286  
   287  		if (symlink(symlink_target, symlink_name) != 0) {
   288  			die("cannot create symbolic link %s -> %s",
   289  			    symlink_name, symlink_target);
   290  		}
   291  	}
   292  }
   293  
   294  static void sc_mkdir_and_mount_and_glob_files(const char *rootfs_dir,
   295  					      const char *source_dir[],
   296  					      size_t source_dir_len,
   297  					      const char *tgt_dir,
   298  					      const char *glob_list[],
   299  					      size_t glob_list_len)
   300  {
   301  	// Bind mount a tmpfs on $rootfs_dir/$tgt_dir (i.e. /var/lib/snapd/lib/gl)
   302  	char buf[512] = { 0 };
   303  	sc_must_snprintf(buf, sizeof(buf), "%s%s", rootfs_dir, tgt_dir);
   304  	const char *libgl_dir = buf;
   305  
   306  	sc_identity old = sc_set_effective_identity(sc_root_group_identity());
   307  	int res = mkdir(libgl_dir, 0755);
   308  	if (res != 0 && errno != EEXIST) {
   309  		die("cannot create tmpfs target %s", libgl_dir);
   310  	}
   311  	if (res == 0 && (chown(libgl_dir, 0, 0) < 0)) {
   312  		// Adjust the ownership only if we created the directory.
   313  		die("cannot change ownership of %s", libgl_dir);
   314  	}
   315  	(void)sc_set_effective_identity(old);
   316  
   317  	debug("mounting tmpfs at %s", libgl_dir);
   318  	if (mount("none", libgl_dir, "tmpfs", MS_NODEV | MS_NOEXEC, NULL) != 0) {
   319  		die("cannot mount tmpfs at %s", libgl_dir);
   320  	};
   321  
   322  	for (size_t i = 0; i < source_dir_len; i++) {
   323  		// Populate libgl_dir with symlinks to libraries from hostfs
   324  		sc_populate_libgl_with_hostfs_symlinks(libgl_dir, source_dir[i],
   325  						       glob_list,
   326  						       glob_list_len);
   327  	}
   328  	// Remount $tgt_dir (i.e. .../lib/gl) read only
   329  	debug("remounting tmpfs as read-only %s", libgl_dir);
   330  	if (mount(NULL, buf, NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) != 0) {
   331  		die("cannot remount %s as read-only", buf);
   332  	}
   333  }
   334  
   335  #ifdef NVIDIA_BIARCH
   336  
   337  // Expose host NVIDIA drivers to the snap on biarch systems.
   338  //
   339  // Order is absolutely imperative here. We'll attempt to find the
   340  // primary files for the architecture in the main directory, and end
   341  // up copying any files across. However it is possible we're using a
   342  // GLVND enabled host, in which case we copied libGL* to the farm.
   343  // The next step in the list is to look within the private nvidia
   344  // directory, exposed using ld.so.conf tricks within the host OS.
   345  // In some distros (i.e. Solus) only the private libGL/libEGL files
   346  // may be found here, and they'll clobber the existing GLVND files from
   347  // the previous run.
   348  // In other distros (like Fedora) all NVIDIA libraries are contained
   349  // within the private directory, so we clobber the GLVND files and we
   350  // also grab all the private NVIDIA libraries.
   351  //
   352  // In non GLVND cases we just copy across the exposed libGLs and NVIDIA
   353  // libraries from wherever we find, and clobbering is also harmless.
   354  static void sc_mount_nvidia_driver_biarch(const char *rootfs_dir)
   355  {
   356  
   357  	const char *native_sources[] = {
   358  		NATIVE_LIBDIR,
   359  		NATIVE_LIBDIR "/nvidia*",
   360  	};
   361  	const size_t native_sources_len =
   362  	    sizeof native_sources / sizeof *native_sources;
   363  
   364  #if UINTPTR_MAX == 0xffffffffffffffff
   365  	// Alternative 32-bit support
   366  	const char *lib32_sources[] = {
   367  		LIB32_DIR,
   368  		LIB32_DIR "/nvidia*",
   369  	};
   370  	const size_t lib32_sources_len =
   371  	    sizeof lib32_sources / sizeof *lib32_sources;
   372  #endif
   373  
   374  	// Primary arch
   375  	sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   376  					  native_sources, native_sources_len,
   377  					  SC_LIBGL_DIR, nvidia_globs,
   378  					  nvidia_globs_len);
   379  
   380  #if UINTPTR_MAX == 0xffffffffffffffff
   381  	// Alternative 32-bit support
   382  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, lib32_sources,
   383  					  lib32_sources_len, SC_LIBGL32_DIR,
   384  					  nvidia_globs, nvidia_globs_len);
   385  #endif
   386  }
   387  
   388  #endif				// ifdef NVIDIA_BIARCH
   389  
   390  #ifdef NVIDIA_MULTIARCH
   391  
   392  typedef struct {
   393  	int major;
   394  	// Driver version format is MAJOR.MINOR[.MICRO] but we only care about the
   395  	// major version and the full version string. The micro component has been
   396  	// seen with relevant leading zeros (e.g. "440.48.02").
   397  	char raw[128]; // The size was picked as "big enough" for version strings.
   398  } sc_nv_version;
   399  
   400  static void sc_probe_nvidia_driver(sc_nv_version * version)
   401  {
   402  	memset(version, 0, sizeof *version);
   403  
   404  	FILE *file SC_CLEANUP(sc_cleanup_file) = NULL;
   405  	debug("opening file describing nvidia driver version");
   406  	file = fopen(SC_NVIDIA_DRIVER_VERSION_FILE, "rt");
   407  	if (file == NULL) {
   408  		if (errno == ENOENT) {
   409  			debug("nvidia driver version file doesn't exist");
   410  			return;
   411  		}
   412  		die("cannot open file describing nvidia driver version");
   413  	}
   414  	int nread = fread(version->raw, 1, sizeof version->raw - 1, file);
   415  	if (nread < 0) {
   416  		die("cannot read nvidia driver version string");
   417  	}
   418  	if (nread == sizeof version->raw - 1 && !feof(file)) {
   419  		die("cannot fit entire nvidia driver version string");
   420  	}
   421  	version->raw[nread] = '\0';
   422  	if (nread > 0 && version->raw[nread - 1] == '\n') {
   423  		version->raw[nread - 1] = '\0';
   424  	}
   425  	if (sscanf(version->raw, "%d.", &version->major) != 1) {
   426  		die("cannot parse major version from nvidia driver version string");
   427  	}
   428  }
   429  
   430  static void sc_mkdir_and_mount_and_bind(const char *rootfs_dir,
   431  					const char *src_dir,
   432  					const char *tgt_dir)
   433  {
   434  	sc_nv_version version;
   435  
   436  	// Probe sysfs to get the version of the driver that is currently inserted.
   437  	sc_probe_nvidia_driver(&version);
   438  
   439  	// If there's driver in the kernel then don't mount userspace.
   440  	if (version.major == 0) {
   441  		return;
   442  	}
   443  	// Construct the paths for the driver userspace libraries
   444  	// and for the gl directory.
   445  	char src[PATH_MAX] = { 0 };
   446  	char dst[PATH_MAX] = { 0 };
   447  	sc_must_snprintf(src, sizeof src, "%s-%d", src_dir, version.major);
   448  	sc_must_snprintf(dst, sizeof dst, "%s%s", rootfs_dir, tgt_dir);
   449  
   450  	// If there is no userspace driver available then don't try to mount it.
   451  	// This can happen for any number of reasons but one interesting one is
   452  	// that that snapd runs in a lxd container on a host that uses nvidia. In
   453  	// that case the container may not have the userspace library installed but
   454  	// the kernel will still have the module around.
   455  	if (access(src, F_OK) != 0) {
   456  		return;
   457  	}
   458  	sc_identity old = sc_set_effective_identity(sc_root_group_identity());
   459  	int res = mkdir(dst, 0755);
   460  	if (res != 0 && errno != EEXIST) {
   461  		die("cannot create directory %s", dst);
   462  	}
   463  	if (res == 0 && (chown(dst, 0, 0) < 0)) {
   464  		// Adjust the ownership only if we created the directory.
   465  		die("cannot change ownership of %s", dst);
   466  	}
   467  	(void)sc_set_effective_identity(old);
   468  	// Bind mount the binary nvidia driver into $tgt_dir (i.e. /var/lib/snapd/lib/gl).
   469  	debug("bind mounting nvidia driver %s -> %s", src, dst);
   470  	if (mount(src, dst, NULL, MS_BIND, NULL) != 0) {
   471  		die("cannot bind mount nvidia driver %s -> %s", src, dst);
   472  	}
   473  }
   474  
   475  static int sc_mount_nvidia_is_driver_in_dir(const char *dir)
   476  {
   477  	char driver_path[512] = { 0 };
   478  
   479  	sc_nv_version version;
   480  
   481  	// Probe sysfs to get the version of the driver that is currently inserted.
   482  	sc_probe_nvidia_driver(&version);
   483  
   484  	// If there's no driver then we should not bother ourselves with finding the
   485  	// matching library
   486  	if (version.major == 0) {
   487  		return 0;
   488  	}
   489  
   490  	// Probe if a well known library is found in directory dir. We must use the
   491  	// raw version because it may contain more than just major.minor. In
   492  	// practice the micro version may have leading zeros that are relevant.
   493  	sc_must_snprintf(driver_path, sizeof driver_path,
   494  			 "%s/libnvidia-glcore.so.%s", dir, version.raw);
   495  
   496  	debug("looking for nvidia canary file %s", driver_path);
   497  	if (access(driver_path, F_OK) == 0) {
   498  		debug("nvidia library detected at path %s", driver_path);
   499  		return 1;
   500  	}
   501  	return 0;
   502  }
   503  
   504  static void sc_mount_nvidia_driver_multiarch(const char *rootfs_dir)
   505  {
   506  	const char *native_libdir = NATIVE_LIBDIR "/" HOST_ARCH_TRIPLET;
   507  	const char *lib32_libdir = NATIVE_LIBDIR "/" HOST_ARCH32_TRIPLET;
   508  
   509  	if ((strlen(HOST_ARCH_TRIPLET) > 0) &&
   510  	    (sc_mount_nvidia_is_driver_in_dir(native_libdir) == 1)) {
   511  
   512  		// sc_mkdir_and_mount_and_glob_files() takes an array of strings, so
   513  		// initialize native_sources accordingly, but calculate the array length
   514  		// dynamically to make adjustments to native_sources easier.
   515  		const char *native_sources[] = { native_libdir };
   516  		const size_t native_sources_len =
   517  		    sizeof native_sources / sizeof *native_sources;
   518  		// Primary arch
   519  		sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   520  						  native_sources,
   521  						  native_sources_len,
   522  						  SC_LIBGL_DIR, nvidia_globs,
   523  						  nvidia_globs_len);
   524  
   525  		// Alternative 32-bit support
   526  		if ((strlen(HOST_ARCH32_TRIPLET) > 0) &&
   527  		    (sc_mount_nvidia_is_driver_in_dir(lib32_libdir) == 1)) {
   528  
   529  			// sc_mkdir_and_mount_and_glob_files() takes an array of strings, so
   530  			// initialize lib32_sources accordingly, but calculate the array length
   531  			// dynamically to make adjustments to lib32_sources easier.
   532  			const char *lib32_sources[] = { lib32_libdir };
   533  			const size_t lib32_sources_len =
   534  			    sizeof lib32_sources / sizeof *lib32_sources;
   535  			sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   536  							  lib32_sources,
   537  							  lib32_sources_len,
   538  							  SC_LIBGL32_DIR,
   539  							  nvidia_globs,
   540  							  nvidia_globs_len);
   541  		}
   542  	} else {
   543  		// Attempt mount of both the native and 32-bit variants of the driver if they exist
   544  		sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib/nvidia",
   545  					    SC_LIBGL_DIR);
   546  		// Alternative 32-bit support
   547  		sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib32/nvidia",
   548  					    SC_LIBGL32_DIR);
   549  	}
   550  }
   551  
   552  #endif				// ifdef NVIDIA_MULTIARCH
   553  
   554  static void sc_mount_vulkan(const char *rootfs_dir)
   555  {
   556  	const char *vulkan_sources[] = {
   557  		SC_VULKAN_SOURCE_DIR,
   558  	};
   559  	const size_t vulkan_sources_len =
   560  	    sizeof vulkan_sources / sizeof *vulkan_sources;
   561  
   562  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, vulkan_sources,
   563  					  vulkan_sources_len, SC_VULKAN_DIR,
   564  					  vulkan_globs, vulkan_globs_len);
   565  }
   566  
   567  static void sc_mount_egl(const char *rootfs_dir)
   568  {
   569  	const char *egl_vendor_sources[] = { SC_EGL_VENDOR_SOURCE_DIR };
   570  	const size_t egl_vendor_sources_len =
   571  	    sizeof egl_vendor_sources / sizeof *egl_vendor_sources;
   572  
   573  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, egl_vendor_sources,
   574  					  egl_vendor_sources_len, SC_GLVND_DIR,
   575  					  egl_vendor_globs,
   576  					  egl_vendor_globs_len);
   577  }
   578  
   579  void sc_mount_nvidia_driver(const char *rootfs_dir)
   580  {
   581  	/* If NVIDIA module isn't loaded, don't attempt to mount the drivers */
   582  	if (access(SC_NVIDIA_DRIVER_VERSION_FILE, F_OK) != 0) {
   583  		return;
   584  	}
   585  
   586  	sc_identity old = sc_set_effective_identity(sc_root_group_identity());
   587  	int res = mkdir(SC_LIB, 0755);
   588  	if (res != 0 && errno != EEXIST) {
   589  		die("cannot create " SC_LIB);
   590  	}
   591  	if (res == 0 && (chown(SC_LIB, 0, 0) < 0)) {
   592  		// Adjust the ownership only if we created the directory.
   593  		die("cannot change ownership of " SC_LIB);
   594  	}
   595  	(void)sc_set_effective_identity(old);
   596  #ifdef NVIDIA_MULTIARCH
   597  	sc_mount_nvidia_driver_multiarch(rootfs_dir);
   598  #endif				// ifdef NVIDIA_MULTIARCH
   599  #ifdef NVIDIA_BIARCH
   600  	sc_mount_nvidia_driver_biarch(rootfs_dir);
   601  #endif				// ifdef NVIDIA_BIARCH
   602  
   603  	// Common for both driver mechanisms
   604  	sc_mount_vulkan(rootfs_dir);
   605  	sc_mount_egl(rootfs_dir);
   606  }