From 2383497282bbb1d2ecff921d4dac13bf36b0ec29 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Wed, 9 Dec 2020 17:30:28 +0000
Subject: [PATCH] pressure-vessel: Make graphics drivers outside $HOME
 available, if used

Since !173, we have been able to create symbolic links to graphics
drivers anywhere on the filesystem, but that didn't mean the graphics
driver would necessarily be usable, because the directory containing it
would not necessarily be visible in the container. Add these directories
to the list of directories to be "exported".

Manual test (Debian on on Intel hardware, adjust as required for
others):

* Modify /usr/share/vulkan/icd.d/intel_icd.i686.json
  to use /opt/moved-from-usr/lib/i386-linux-gnu/libvulkan_intel.so
* Move the real i386 libvulkan_intel.so to that location
* ./run --verbose -- steam-runtime-system-info 2>&1 | tee container.log

Resolves: #29
Resolves: https://github.com/ValveSoftware/steam-runtime/issues/313
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 pressure-vessel/exports.c   | 82 +++++++++++++++++++++++++++++++++++++
 pressure-vessel/exports.h   | 28 +++++++++++++
 pressure-vessel/meson.build |  2 +
 pressure-vessel/runtime.c   | 14 ++++++-
 pressure-vessel/runtime.h   |  2 +
 pressure-vessel/wrap.c      |  8 +++-
 6 files changed, 132 insertions(+), 4 deletions(-)
 create mode 100644 pressure-vessel/exports.c
 create mode 100644 pressure-vessel/exports.h

diff --git a/pressure-vessel/exports.c b/pressure-vessel/exports.c
new file mode 100644
index 000000000..4c1f845a9
--- /dev/null
+++ b/pressure-vessel/exports.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2017-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "exports.h"
+
+#include <ftw.h>
+
+/* nftw() doesn't have a user_data argument so we need to use a global
+ * variable :-( */
+static struct
+{
+  FlatpakExports *exports;
+} export_targets_data;
+
+static int
+export_targets_helper (const char *fpath,
+                       const struct stat *sb,
+                       int typeflag,
+                       struct FTW *ftwbuf)
+{
+  g_autofree gchar *target = NULL;
+
+  switch (typeflag)
+    {
+      case FTW_SL:
+        target = glnx_readlinkat_malloc (-1, fpath, NULL, NULL);
+
+        if (target[0] != '/')
+          break;
+
+        if (g_str_has_prefix (target, "/run/host/"))
+          break;
+
+        g_debug ("Exporting %s because %s points to it",
+                 target, fpath);
+        flatpak_exports_add_path_expose (export_targets_data.exports,
+                                         FLATPAK_FILESYSTEM_MODE_READ_ONLY,
+                                         target);
+        break;
+
+      default:
+        break;
+    }
+
+  return 0;
+}
+
+/**
+ * pv_export_symlink_targets:
+ * @exports: The #FlatpakExports
+ * @source: A copy of the overrides directory, for example
+ *  `/tmp/tmp12345678/overrides/lib`.
+ *
+ * For every symbolic link in @source, if the target is absolute, mark
+ * it to be exported in @exports.
+ */
+void
+pv_export_symlink_targets (FlatpakExports *exports,
+                           const char *source)
+{
+  g_return_if_fail (export_targets_data.exports == NULL);
+
+  export_targets_data.exports = exports;
+  nftw (source, export_targets_helper, 100, FTW_PHYS);
+  export_targets_data.exports = NULL;
+}
diff --git a/pressure-vessel/exports.h b/pressure-vessel/exports.h
new file mode 100644
index 000000000..97d92691c
--- /dev/null
+++ b/pressure-vessel/exports.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2017-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libglnx/libglnx.h"
+
+#include "flatpak-exports-private.h"
+#include "steam-runtime-tools/glib-backports-internal.h"
+
+void pv_export_symlink_targets (FlatpakExports *exports,
+                                const char *source);
diff --git a/pressure-vessel/meson.build b/pressure-vessel/meson.build
index df7460776..ed93e41b7 100644
--- a/pressure-vessel/meson.build
+++ b/pressure-vessel/meson.build
@@ -191,6 +191,8 @@ executable(
   sources : [
     'bwrap.c',
     'bwrap.h',
+    'exports.c',
+    'exports.h',
     'flatpak-common-types-private.h',
     'flatpak-context.c',
     'flatpak-context-private.h',
diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index 8af25be2b..d39e2e63e 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -36,6 +36,7 @@
 #include "bwrap-lock.h"
 #include "elf-utils.h"
 #include "enumtypes.h"
+#include "exports.h"
 #include "flatpak-run-private.h"
 #include "tree-copy.h"
 #include "utils.h"
@@ -1626,6 +1627,7 @@ bind_icd (PvRuntime *self,
 
 static gboolean
 bind_runtime (PvRuntime *self,
+              FlatpakExports *exports,
               FlatpakBwrap *bwrap,
               GHashTable *extra_locked_vars_to_unset,
               GHashTable *extra_locked_vars_to_inherit,
@@ -1817,6 +1819,8 @@ bind_runtime (PvRuntime *self,
         return FALSE;
     }
 
+  pv_export_symlink_targets (exports, self->overrides);
+
   if (self->mutable_sysroot == NULL)
     {
       /* self->overrides is in a temporary directory that will be
@@ -3615,6 +3619,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
 
 gboolean
 pv_runtime_bind (PvRuntime *self,
+                 FlatpakExports *exports,
                  FlatpakBwrap *bwrap,
                  GHashTable *extra_locked_vars_to_unset,
                  GHashTable *extra_locked_vars_to_inherit,
@@ -3623,13 +3628,18 @@ pv_runtime_bind (PvRuntime *self,
   g_autofree gchar *pressure_vessel_prefix = NULL;
 
   g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (exports != NULL, FALSE);
   g_return_val_if_fail (!pv_bwrap_was_finished (bwrap), FALSE);
   g_return_val_if_fail (extra_locked_vars_to_unset != NULL, FALSE);
   g_return_val_if_fail (extra_locked_vars_to_inherit != NULL, FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  if (!bind_runtime (self, bwrap, extra_locked_vars_to_unset,
-                     extra_locked_vars_to_inherit, error))
+  if (!bind_runtime (self,
+                     exports,
+                     bwrap,
+                     extra_locked_vars_to_unset,
+                     extra_locked_vars_to_inherit,
+                     error))
     return FALSE;
 
   pressure_vessel_prefix = g_path_get_dirname (self->tools_dir);
diff --git a/pressure-vessel/runtime.h b/pressure-vessel/runtime.h
index 0b3d2944a..1d8ede2ad 100644
--- a/pressure-vessel/runtime.h
+++ b/pressure-vessel/runtime.h
@@ -27,6 +27,7 @@
 #include "libglnx/libglnx.h"
 
 #include "flatpak-bwrap-private.h"
+#include "flatpak-exports-private.h"
 #include "flatpak-utils-base-private.h"
 
 /**
@@ -82,6 +83,7 @@ PvRuntime *pv_runtime_new (const char *source_files,
 gchar *pv_runtime_get_adverb (PvRuntime *self,
                               FlatpakBwrap *adverb_args);
 gboolean pv_runtime_bind (PvRuntime *self,
+                          FlatpakExports *exports,
                           FlatpakBwrap *bwrap,
                           GHashTable *extra_locked_vars_to_unset,
                           GHashTable *extra_locked_vars_to_inherit,
diff --git a/pressure-vessel/wrap.c b/pressure-vessel/wrap.c
index 5bfa3a7b3..0662960e2 100644
--- a/pressure-vessel/wrap.c
+++ b/pressure-vessel/wrap.c
@@ -1781,8 +1781,12 @@ main (int argc,
       if (runtime == NULL)
         goto out;
 
-      if (!pv_runtime_bind (runtime, bwrap, extra_locked_vars_to_unset,
-                            extra_locked_vars_to_inherit, error))
+      if (!pv_runtime_bind (runtime,
+                            exports,
+                            bwrap,
+                            extra_locked_vars_to_unset,
+                            extra_locked_vars_to_inherit,
+                            error))
         goto out;
     }
   else if (is_flatpak_env)
-- 
GitLab