github.com/rigado/snapd@v2.42.5-go-mod+incompatible/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  	"libcuda.so*",
   100  	"libcudart.so*",
   101  	"libnvcuvid.so*",
   102  	"libnvidia-cfg.so*",
   103  	"libnvidia-compiler.so*",
   104  	"libnvidia-eglcore.so*",
   105  	"libnvidia-egl-wayland*",
   106  	"libnvidia-encode.so*",
   107  	"libnvidia-fatbinaryloader.so*",
   108  	"libnvidia-fbc.so*",
   109  	"libnvidia-glcore.so*",
   110  	"libnvidia-glsi.so*",
   111  	"libnvidia-glvkspirv.so*",
   112  	"libnvidia-ifr.so*",
   113  	"libnvidia-ml.so*",
   114  	"libnvidia-opencl.so*",
   115  	"libnvidia-ptxjitcompiler.so*",
   116  	"libnvidia-tls.so*",
   117  	"tls/libnvidia-tls.so*",
   118  	"vdpau/libvdpau_nvidia.so*",
   119  };
   120  
   121  static const size_t nvidia_globs_len =
   122      sizeof nvidia_globs / sizeof *nvidia_globs;
   123  
   124  #define LIBNVIDIA_GLCORE_SO_PATTERN "libnvidia-glcore.so.%d.%d"
   125  
   126  #endif				// defined(NVIDIA_BIARCH) || defined(NVIDIA_MULTIARCH)
   127  
   128  // Populate libgl_dir with a symlink farm to files matching glob_list.
   129  //
   130  // The symbolic links are made in one of two ways. If the library found is a
   131  // file a regular symlink "$libname" -> "/path/to/hostfs/$libname" is created.
   132  // If the library is a symbolic link then relative links are kept as-is but
   133  // absolute links are translated to have "/path/to/hostfs" up front so that
   134  // they work after the pivot_root elsewhere.
   135  //
   136  // The glob list passed to us is produced with paths relative to source dir,
   137  // to simplify the various tie-in points with this function.
   138  static void sc_populate_libgl_with_hostfs_symlinks(const char *libgl_dir,
   139  						   const char *source_dir,
   140  						   const char *glob_list[],
   141  						   size_t glob_list_len)
   142  {
   143  	size_t source_dir_len = strlen(source_dir);
   144  	glob_t glob_res SC_CLEANUP(globfree) = {
   145  		.gl_pathv = NULL
   146  	};
   147  	// Find all the entries matching the list of globs
   148  	for (size_t i = 0; i < glob_list_len; ++i) {
   149  		const char *glob_pattern = glob_list[i];
   150  		char glob_pattern_full[512] = { 0 };
   151  		sc_must_snprintf(glob_pattern_full, sizeof glob_pattern_full,
   152  				 "%s/%s", source_dir, glob_pattern);
   153  
   154  		int err = glob(glob_pattern_full, i ? GLOB_APPEND : 0, NULL,
   155  			       &glob_res);
   156  		// Not all of the files have to be there (they differ depending on the
   157  		// driver version used). Ignore all errors that are not GLOB_NOMATCH.
   158  		if (err != 0 && err != GLOB_NOMATCH) {
   159  			die("cannot search using glob pattern %s: %d",
   160  			    glob_pattern_full, err);
   161  		}
   162  	}
   163  	// Symlink each file found
   164  	for (size_t i = 0; i < glob_res.gl_pathc; ++i) {
   165  		char symlink_name[512] = { 0 };
   166  		char symlink_target[512] = { 0 };
   167  		char prefix_dir[512] = { 0 };
   168  		const char *pathname = glob_res.gl_pathv[i];
   169  		char *pathname_copy1
   170  		    SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname);
   171  		char *pathname_copy2
   172  		    SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname);
   173  		// POSIX dirname() and basename() may modify their input arguments
   174  		char *filename = basename(pathname_copy1);
   175  		char *directory_name = dirname(pathname_copy2);
   176  		sc_must_snprintf(prefix_dir, sizeof prefix_dir, "%s",
   177  				 libgl_dir);
   178  
   179  		if (strlen(directory_name) > source_dir_len) {
   180  			// Additional path elements between source_dir and dirname, meaning the
   181  			// actual file is not placed directly under source_dir but under one or
   182  			// more directories below source_dir. Make sure to recreate the whole
   183  			// prefix
   184  			sc_must_snprintf(prefix_dir, sizeof prefix_dir,
   185  					 "%s%s", libgl_dir,
   186  					 &directory_name[source_dir_len]);
   187  			if (sc_nonfatal_mkpath(prefix_dir, 0755) != 0) {
   188  				die("failed to create prefix path: %s",
   189  				    prefix_dir);
   190  			}
   191  		}
   192  
   193  		struct stat stat_buf;
   194  		int err = lstat(pathname, &stat_buf);
   195  		if (err != 0) {
   196  			die("cannot stat file %s", pathname);
   197  		}
   198  		switch (stat_buf.st_mode & S_IFMT) {
   199  		case S_IFLNK:;
   200  			// Read the target of the symbolic link
   201  			char hostfs_symlink_target[512];
   202  			ssize_t num_read;
   203  			hostfs_symlink_target[0] = 0;
   204  			num_read =
   205  			    readlink(pathname, hostfs_symlink_target,
   206  				     sizeof hostfs_symlink_target);
   207  			if (num_read == -1) {
   208  				die("cannot read symbolic link %s", pathname);
   209  			}
   210  			hostfs_symlink_target[num_read] = 0;
   211  			if (hostfs_symlink_target[0] == '/') {
   212  				sc_must_snprintf(symlink_target,
   213  						 sizeof symlink_target,
   214  						 "/var/lib/snapd/hostfs%s",
   215  						 hostfs_symlink_target);
   216  			} else {
   217  				// Keep relative symlinks as-is, so that they point to -> libfoo.so.0.123
   218  				sc_must_snprintf(symlink_target,
   219  						 sizeof symlink_target, "%s",
   220  						 hostfs_symlink_target);
   221  			}
   222  			break;
   223  		case S_IFREG:
   224  			sc_must_snprintf(symlink_target,
   225  					 sizeof symlink_target,
   226  					 "/var/lib/snapd/hostfs%s", pathname);
   227  			break;
   228  		default:
   229  			debug("ignoring unsupported entry: %s", pathname);
   230  			continue;
   231  		}
   232  		sc_must_snprintf(symlink_name, sizeof symlink_name,
   233  				 "%s/%s", prefix_dir, filename);
   234  		debug("creating symbolic link %s -> %s", symlink_name,
   235  		      symlink_target);
   236  
   237  		// Make sure we don't have some link already (merged GLVND systems)
   238  		if (lstat(symlink_name, &stat_buf) == 0) {
   239  			if (unlink(symlink_name) != 0) {
   240  				die("cannot remove symbolic link target %s",
   241  				    symlink_name);
   242  			}
   243  		}
   244  
   245  		if (symlink(symlink_target, symlink_name) != 0) {
   246  			die("cannot create symbolic link %s -> %s",
   247  			    symlink_name, symlink_target);
   248  		}
   249  	}
   250  }
   251  
   252  static void sc_mkdir_and_mount_and_glob_files(const char *rootfs_dir,
   253  					      const char *source_dir[],
   254  					      size_t source_dir_len,
   255  					      const char *tgt_dir,
   256  					      const char *glob_list[],
   257  					      size_t glob_list_len)
   258  {
   259  	// Bind mount a tmpfs on $rootfs_dir/$tgt_dir (i.e. /var/lib/snapd/lib/gl)
   260  	char buf[512] = { 0 };
   261  	sc_must_snprintf(buf, sizeof(buf), "%s%s", rootfs_dir, tgt_dir);
   262  	const char *libgl_dir = buf;
   263  
   264  	int res = mkdir(libgl_dir, 0755);
   265  	if (res != 0 && errno != EEXIST) {
   266  		die("cannot create tmpfs target %s", libgl_dir);
   267  	}
   268  	if (res == 0 && (chown(libgl_dir, 0, 0) < 0)) {
   269  		// Adjust the ownership only if we created the directory.
   270  		die("cannot change ownership of %s", libgl_dir);
   271  	}
   272  
   273  	debug("mounting tmpfs at %s", libgl_dir);
   274  	if (mount("none", libgl_dir, "tmpfs", MS_NODEV | MS_NOEXEC, NULL) != 0) {
   275  		die("cannot mount tmpfs at %s", libgl_dir);
   276  	};
   277  
   278  	for (size_t i = 0; i < source_dir_len; i++) {
   279  		// Populate libgl_dir with symlinks to libraries from hostfs
   280  		sc_populate_libgl_with_hostfs_symlinks(libgl_dir, source_dir[i],
   281  						       glob_list,
   282  						       glob_list_len);
   283  	}
   284  	// Remount $tgt_dir (i.e. .../lib/gl) read only
   285  	debug("remounting tmpfs as read-only %s", libgl_dir);
   286  	if (mount(NULL, buf, NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) != 0) {
   287  		die("cannot remount %s as read-only", buf);
   288  	}
   289  }
   290  
   291  #ifdef NVIDIA_BIARCH
   292  
   293  // Expose host NVIDIA drivers to the snap on biarch systems.
   294  //
   295  // Order is absolutely imperative here. We'll attempt to find the
   296  // primary files for the architecture in the main directory, and end
   297  // up copying any files across. However it is possible we're using a
   298  // GLVND enabled host, in which case we copied libGL* to the farm.
   299  // The next step in the list is to look within the private nvidia
   300  // directory, exposed using ld.so.conf tricks within the host OS.
   301  // In some distros (i.e. Solus) only the private libGL/libEGL files
   302  // may be found here, and they'll clobber the existing GLVND files from
   303  // the previous run.
   304  // In other distros (like Fedora) all NVIDIA libraries are contained
   305  // within the private directory, so we clobber the GLVND files and we
   306  // also grab all the private NVIDIA libraries.
   307  //
   308  // In non GLVND cases we just copy across the exposed libGLs and NVIDIA
   309  // libraries from wherever we find, and clobbering is also harmless.
   310  static void sc_mount_nvidia_driver_biarch(const char *rootfs_dir)
   311  {
   312  
   313  	const char *native_sources[] = {
   314  		NATIVE_LIBDIR,
   315  		NATIVE_LIBDIR "/nvidia*",
   316  	};
   317  	const size_t native_sources_len =
   318  	    sizeof native_sources / sizeof *native_sources;
   319  
   320  #if UINTPTR_MAX == 0xffffffffffffffff
   321  	// Alternative 32-bit support
   322  	const char *lib32_sources[] = {
   323  		LIB32_DIR,
   324  		LIB32_DIR "/nvidia*",
   325  	};
   326  	const size_t lib32_sources_len =
   327  	    sizeof lib32_sources / sizeof *lib32_sources;
   328  #endif
   329  
   330  	// Primary arch
   331  	sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   332  					  native_sources, native_sources_len,
   333  					  SC_LIBGL_DIR, nvidia_globs,
   334  					  nvidia_globs_len);
   335  
   336  #if UINTPTR_MAX == 0xffffffffffffffff
   337  	// Alternative 32-bit support
   338  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, lib32_sources,
   339  					  lib32_sources_len, SC_LIBGL32_DIR,
   340  					  nvidia_globs, nvidia_globs_len);
   341  #endif
   342  }
   343  
   344  #endif				// ifdef NVIDIA_BIARCH
   345  
   346  #ifdef NVIDIA_MULTIARCH
   347  
   348  struct sc_nvidia_driver {
   349  	int major_version;
   350  	int minor_version;
   351  };
   352  
   353  static void sc_probe_nvidia_driver(struct sc_nvidia_driver *driver)
   354  {
   355  	FILE *file SC_CLEANUP(sc_cleanup_file) = NULL;
   356  	debug("opening file describing nvidia driver version");
   357  	file = fopen(SC_NVIDIA_DRIVER_VERSION_FILE, "rt");
   358  	if (file == NULL) {
   359  		if (errno == ENOENT) {
   360  			debug("nvidia driver version file doesn't exist");
   361  			driver->major_version = 0;
   362  			driver->minor_version = 0;
   363  			return;
   364  		}
   365  		die("cannot open file describing nvidia driver version");
   366  	}
   367  	// Driver version format is MAJOR.MINOR where both MAJOR and MINOR are
   368  	// integers. We can use sscanf to parse this data.
   369  	if (fscanf
   370  	    (file, "%d.%d", &driver->major_version,
   371  	     &driver->minor_version) != 2) {
   372  		die("cannot parse nvidia driver version string");
   373  	}
   374  	debug("parsed nvidia driver version: %d.%d", driver->major_version,
   375  	      driver->minor_version);
   376  }
   377  
   378  static void sc_mkdir_and_mount_and_bind(const char *rootfs_dir,
   379  					const char *src_dir,
   380  					const char *tgt_dir)
   381  {
   382  	struct sc_nvidia_driver driver;
   383  
   384  	// Probe sysfs to get the version of the driver that is currently inserted.
   385  	sc_probe_nvidia_driver(&driver);
   386  
   387  	// If there's driver in the kernel then don't mount userspace.
   388  	if (driver.major_version == 0) {
   389  		return;
   390  	}
   391  	// Construct the paths for the driver userspace libraries
   392  	// and for the gl directory.
   393  	char src[PATH_MAX] = { 0 };
   394  	char dst[PATH_MAX] = { 0 };
   395  	sc_must_snprintf(src, sizeof src, "%s-%d", src_dir,
   396  			 driver.major_version);
   397  	sc_must_snprintf(dst, sizeof dst, "%s%s", rootfs_dir, tgt_dir);
   398  
   399  	// If there is no userspace driver available then don't try to mount it.
   400  	// This can happen for any number of reasons but one interesting one is
   401  	// that that snapd runs in a lxd container on a host that uses nvidia. In
   402  	// that case the container may not have the userspace library installed but
   403  	// the kernel will still have the module around.
   404  	if (access(src, F_OK) != 0) {
   405  		return;
   406  	}
   407  	int res = mkdir(dst, 0755);
   408  	if (res != 0 && errno != EEXIST) {
   409  		die("cannot create directory %s", dst);
   410  	}
   411  	if (res == 0 && (chown(dst, 0, 0) < 0)) {
   412  		// Adjust the ownership only if we created the directory.
   413  		die("cannot change ownership of %s", dst);
   414  	}
   415  	// Bind mount the binary nvidia driver into $tgt_dir (i.e. /var/lib/snapd/lib/gl).
   416  	debug("bind mounting nvidia driver %s -> %s", src, dst);
   417  	if (mount(src, dst, NULL, MS_BIND, NULL) != 0) {
   418  		die("cannot bind mount nvidia driver %s -> %s", src, dst);
   419  	}
   420  }
   421  
   422  static int sc_mount_nvidia_is_driver_in_dir(const char *dir)
   423  {
   424  	char driver_path[512] = { 0 };
   425  
   426  	struct sc_nvidia_driver driver;
   427  
   428  	// Probe sysfs to get the version of the driver that is currently inserted.
   429  	sc_probe_nvidia_driver(&driver);
   430  
   431  	// If there's no driver then we should not bother ourselves with finding the
   432  	// matching library
   433  	if (driver.major_version == 0) {
   434  		return 0;
   435  	}
   436  	// Probe if a well known library is found in directory dir
   437  	sc_must_snprintf(driver_path, sizeof driver_path,
   438  			 "%s/" LIBNVIDIA_GLCORE_SO_PATTERN, dir,
   439  			 driver.major_version, driver.minor_version);
   440  
   441  	if (access(driver_path, F_OK) == 0) {
   442  		debug("nvidia library detected at path %s", driver_path);
   443  		return 1;
   444  	}
   445  	return 0;
   446  }
   447  
   448  static void sc_mount_nvidia_driver_multiarch(const char *rootfs_dir)
   449  {
   450  	const char *native_libdir = NATIVE_LIBDIR "/" HOST_ARCH_TRIPLET;
   451  	const char *lib32_libdir = NATIVE_LIBDIR "/" HOST_ARCH32_TRIPLET;
   452  
   453  	if ((strlen(HOST_ARCH_TRIPLET) > 0) &&
   454  	    (sc_mount_nvidia_is_driver_in_dir(native_libdir) == 1)) {
   455  
   456  		// sc_mkdir_and_mount_and_glob_files() takes an array of strings, so
   457  		// initialize native_sources accordingly, but calculate the array length
   458  		// dynamically to make adjustments to native_sources easier.
   459  		const char *native_sources[] = { native_libdir };
   460  		const size_t native_sources_len =
   461  		    sizeof native_sources / sizeof *native_sources;
   462  		// Primary arch
   463  		sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   464  						  native_sources,
   465  						  native_sources_len,
   466  						  SC_LIBGL_DIR, nvidia_globs,
   467  						  nvidia_globs_len);
   468  
   469  		// Alternative 32-bit support
   470  		if ((strlen(HOST_ARCH32_TRIPLET) > 0) &&
   471  		    (sc_mount_nvidia_is_driver_in_dir(lib32_libdir) == 1)) {
   472  
   473  			// sc_mkdir_and_mount_and_glob_files() takes an array of strings, so
   474  			// initialize lib32_sources accordingly, but calculate the array length
   475  			// dynamically to make adjustments to lib32_sources easier.
   476  			const char *lib32_sources[] = { lib32_libdir };
   477  			const size_t lib32_sources_len =
   478  			    sizeof lib32_sources / sizeof *lib32_sources;
   479  			sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   480  							  lib32_sources,
   481  							  lib32_sources_len,
   482  							  SC_LIBGL32_DIR,
   483  							  nvidia_globs,
   484  							  nvidia_globs_len);
   485  		}
   486  	} else {
   487  		// Attempt mount of both the native and 32-bit variants of the driver if they exist
   488  		sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib/nvidia",
   489  					    SC_LIBGL_DIR);
   490  		// Alternative 32-bit support
   491  		sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib32/nvidia",
   492  					    SC_LIBGL32_DIR);
   493  	}
   494  }
   495  
   496  #endif				// ifdef NVIDIA_MULTIARCH
   497  
   498  static void sc_mount_vulkan(const char *rootfs_dir)
   499  {
   500  	const char *vulkan_sources[] = {
   501  		SC_VULKAN_SOURCE_DIR,
   502  	};
   503  	const size_t vulkan_sources_len =
   504  	    sizeof vulkan_sources / sizeof *vulkan_sources;
   505  
   506  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, vulkan_sources,
   507  					  vulkan_sources_len, SC_VULKAN_DIR,
   508  					  vulkan_globs, vulkan_globs_len);
   509  }
   510  
   511  static void sc_mount_egl(const char *rootfs_dir)
   512  {
   513  	const char *egl_vendor_sources[] = { SC_EGL_VENDOR_SOURCE_DIR };
   514  	const size_t egl_vendor_sources_len =
   515  	    sizeof egl_vendor_sources / sizeof *egl_vendor_sources;
   516  
   517  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, egl_vendor_sources,
   518  					  egl_vendor_sources_len, SC_GLVND_DIR,
   519  					  egl_vendor_globs,
   520  					  egl_vendor_globs_len);
   521  }
   522  
   523  void sc_mount_nvidia_driver(const char *rootfs_dir)
   524  {
   525  	/* If NVIDIA module isn't loaded, don't attempt to mount the drivers */
   526  	if (access(SC_NVIDIA_DRIVER_VERSION_FILE, F_OK) != 0) {
   527  		return;
   528  	}
   529  
   530  	int res = mkdir(SC_LIB, 0755);
   531  	if (res != 0 && errno != EEXIST) {
   532  		die("cannot create " SC_LIB);
   533  	}
   534  	if (res == 0 && (chown(SC_LIB, 0, 0) < 0)) {
   535  		// Adjust the ownership only if we created the directory.
   536  		die("cannot change ownership of " SC_LIB);
   537  	}
   538  #ifdef NVIDIA_MULTIARCH
   539  	sc_mount_nvidia_driver_multiarch(rootfs_dir);
   540  #endif				// ifdef NVIDIA_MULTIARCH
   541  #ifdef NVIDIA_BIARCH
   542  	sc_mount_nvidia_driver_biarch(rootfs_dir);
   543  #endif				// ifdef NVIDIA_BIARCH
   544  
   545  	// Common for both driver mechanisms
   546  	sc_mount_vulkan(rootfs_dir);
   547  	sc_mount_egl(rootfs_dir);
   548  }