From feb948ed64a17ae7189f64586fee84cfeb422362 Mon Sep 17 00:00:00 2001 From: Simon McVittie <smcv@collabora.com> Date: Mon, 17 Feb 2020 19:43:25 +0000 Subject: [PATCH] wrap: Add the ability to unshare the pid namespace This improves isolation between the host system and the game, and can be used in conjunction with bwrap's init/reaper process to make game termination fully reliable (unlike subreapers, killing the init process automatically kills the entire pid namespace). One major down-side of doing this is that if the game uses process-ID-oriented APIs, for example older versions of <https://github.com/FeralInteractive/gamemode>, then they will not work, because the process ID inside the container is not the same as the process ID outside the container. Unfortunately, Steam's own tracking of the processes that belong to a game is one of the process-ID-oriented APIs that this harms, so this branch does not unshare the pid namespace by default, only when requested. We can use this to test whether it can be done without breaking Steam; We will probably need to cope with separate pid namespaces if we create new containers from inside a Flatpak environment. Also add an option to unload the gameoverlayrenderer.so module, which is not acceptable for production use, but at least works around this well enough to unblock further testing. Signed-off-by: Simon McVittie <smcv@collabora.com> --- pressure-vessel-test-ui | 52 +++++++++++++++++++++++++++++++++++++++++ src/wrap.c | 39 +++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/pressure-vessel-test-ui b/pressure-vessel-test-ui index ba82ee2a6..c8f354e40 100755 --- a/pressure-vessel-test-ui +++ b/pressure-vessel-test-ui @@ -211,6 +211,48 @@ class Gui: self.grid.attach(label, 1, row, 1, 1) row += 1 + self.unshare_pid_check = Gtk.CheckButton.new_with_label( + 'Create a new process ID namespace' + ) + share_pid = boolean_environment('PRESSURE_VESSEL_SHARE_PID', True) + self.unshare_pid_check.set_active(not share_pid) + self.grid.attach(self.unshare_pid_check, 1, row, 1, 1) + row += 1 + + label = Gtk.Label.new('') + label.set_markup( + '<small><i>' + "Creating a new process ID namespace is very experimental, " + "and is known to break Steam's tracking of running games." + '</i></small>' + ) + label.set_halign(Gtk.Align.START) + label.set_line_wrap(True) + self.grid.attach(label, 1, row, 1, 1) + row += 1 + + self.keep_game_overlay_check = Gtk.CheckButton.new_with_label( + 'Allow Steam Overlay' + ) + remove = boolean_environment( + 'PRESSURE_VESSEL_REMOVE_GAME_OVERLAY', False + ) + self.keep_game_overlay_check.set_active(not remove) + self.grid.attach(self.keep_game_overlay_check, 1, row, 1, 1) + row += 1 + + label = Gtk.Label.new('') + label.set_markup( + '<small><i>' + 'Disabling this seems to work around some of the issues with ' + 'process ID namespaces, but will break various Steam features.' + '</i></small>' + ) + label.set_halign(Gtk.Align.START) + label.set_line_wrap(True) + self.grid.attach(label, 1, row, 1, 1) + row += 1 + self.xterm_check = Gtk.CheckButton.new_with_label('Run in an xterm') self.xterm_check.set_active(False) self.grid.attach(self.xterm_check, 1, row, 1, 1) @@ -420,6 +462,16 @@ class Gui: else: argv.append('--share-home') + if self.unshare_pid_check.get_active(): + argv.append('--unshare-pid') + else: + argv.append('--share-pid') + + if self.keep_game_overlay_check.get_active(): + argv.append('--keep-game-overlay') + else: + argv.append('--remove-game-overlay') + if self.xterm_check.get_active(): argv.append('--terminal=xterm') else: diff --git a/src/wrap.c b/src/wrap.c index f70843a12..1d903d813 100644 --- a/src/wrap.c +++ b/src/wrap.c @@ -323,11 +323,13 @@ static char *opt_steam_app_id = NULL; static char *opt_home = NULL; static gboolean opt_host_fallback = FALSE; static gboolean opt_host_graphics = TRUE; +static gboolean opt_remove_game_overlay = FALSE; static PvShell opt_shell = PV_SHELL_NONE; static GPtrArray *opt_ld_preload = NULL; static char *opt_runtime_base = NULL; static char *opt_runtime = NULL; static Tristate opt_share_home = TRISTATE_MAYBE; +static gboolean opt_share_pid = TRUE; static gboolean opt_verbose = FALSE; static gboolean opt_version = FALSE; static gboolean opt_version_only = FALSE; @@ -517,6 +519,16 @@ static GOptionEntry options[] = G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, &opt_host_ld_preload_cb, "Add MODULE from the host system to LD_PRELOAD when executing COMMAND.", "MODULE" }, + { "remove-game-overlay", '\0', + G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_remove_game_overlay, + "Disable the Steam Overlay. " + "[Default if $PRESSURE_VESSEL_REMOVE_GAME_OVERLAY is 1]", + NULL }, + { "keep-game-overlay", '\0', + G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt_remove_game_overlay, + "Do not disable the Steam Overlay. " + "[Default unless $PRESSURE_VESSEL_REMOVE_GAME_OVERLAY is 1]", + NULL }, { "runtime", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME, &opt_runtime, "Mount the given sysroot or merged /usr in the container, and augment " @@ -541,6 +553,16 @@ static GOptionEntry options[] = "[Default if $PRESSURE_VESSEL_HOME is set or " "$PRESSURE_VESSEL_SHARE_HOME is 0]", NULL }, + { "share-pid", '\0', + G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_share_pid, + "Do not create a new process ID namespace for the app. " + "[Default, unless $PRESSURE_VESSEL_SHARE_PID is 0]", + NULL }, + { "unshare-pid", '\0', + G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt_share_pid, + "Create a new process ID namespace for the app. " + "[Default if $PRESSURE_VESSEL_SHARE_PID is 0]", + NULL }, { "shell", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, opt_shell_cb, "--shell=after is equivalent to --shell-after, and so on. " @@ -700,9 +722,12 @@ main (int argc, if (opt_home != NULL && opt_home[0] == '\0') g_clear_pointer (&opt_home, g_free); + opt_remove_game_overlay = boolean_environment ("PRESSURE_VESSEL_REMOVE_GAME_OVERLAY", + FALSE); opt_share_home = tristate_environment ("PRESSURE_VESSEL_SHARE_HOME"); opt_host_graphics = boolean_environment ("PRESSURE_VESSEL_HOST_GRAPHICS", TRUE); + opt_share_pid = boolean_environment ("PRESSURE_VESSEL_SHARE_PID", TRUE); opt_verbose = boolean_environment ("PRESSURE_VESSEL_VERBOSE", FALSE); if (!opt_shell_cb ("$PRESSURE_VESSEL_SHELL", @@ -1078,6 +1103,13 @@ main (int argc, goto out; } + if (!opt_share_pid) + { + g_warning ("Unsharing process ID namespace. This is not expected " + "to work..."); + flatpak_bwrap_add_arg (bwrap, "--unshare-pid"); + } + g_debug ("Adjusting LD_PRELOAD..."); /* We need the LD_PRELOADs from Steam visible at the paths that were @@ -1102,6 +1134,13 @@ main (int argc, if (g_file_test (preload, G_FILE_TEST_EXISTS)) { + if (opt_remove_game_overlay + && g_str_has_suffix (preload, "/gameoverlayrenderer.so")) + { + g_debug ("Disabling Steam Overlay: %s", preload); + continue; + } + if (runtime != NULL && (g_str_has_prefix (preload, "/usr/") || g_str_has_prefix (preload, "/lib"))) -- GitLab