diff --git a/daemon/gamemode-proc.c b/daemon/gamemode-proc.c new file mode 100644 index 0000000..74d083d --- /dev/null +++ b/daemon/gamemode-proc.c @@ -0,0 +1,61 @@ +/* + +Copyright (c) 2017-2018, Feral Interactive +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Feral Interactive nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + */ + +#define _GNU_SOURCE + +#include "gamemode.h" +#include "helpers.h" + +#include +#include +#include + +/** + * Opens the process environment for a specific PID and returns + * a file descriptor to the directory /proc/PID. Doing it that way prevents + * the directory going MIA when a process exits while we are looking at it + * and allows us to handle fewer error cases. + */ +procfd_t game_mode_open_proc(const pid_t pid) +{ + char buffer[PATH_MAX]; + const char *proc_path = buffered_snprintf(buffer, "/proc/%d", pid); + + return proc_path ? open(proc_path, O_RDONLY | O_CLOEXEC) : INVALID_PROCFD; +} + +/** + * Closes the process environment. + */ +int game_mode_close_proc(const procfd_t procfd) +{ + return close(procfd); +} diff --git a/daemon/gamemode.c b/daemon/gamemode.c index b89219c..e2578a2 100644 --- a/daemon/gamemode.c +++ b/daemon/gamemode.c @@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include #include #include @@ -50,7 +49,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include /* SCHED_ISO may not be defined as it is a reserved value not yet @@ -725,7 +723,7 @@ GameModeContext *game_mode_context_instance() * Lookup the process environment for a specific variable or return NULL. * Requires an open directory FD from /proc/PID. */ -static char *game_mode_lookup_proc_env(int proc_fd, const char *var) +static char *game_mode_lookup_proc_env(const procfd_t proc_fd, const char *var) { char *environ = NULL; @@ -785,18 +783,11 @@ static char *game_mode_resolve_wine_preloader(pid_t pid) { char buffer[PATH_MAX]; char *proc_path = NULL, *wine_exe = NULL, *wineprefix = NULL; - int proc_fd = -1; - - /* We could use the buffered_snprintf() helper here but it may potentially - * overwrite proc_path when the buffer is re-used later and usage of - * proc_path has not been discarded yet (i.e., it's used in the fail path). - * Let's not introduce this non-obvious pitfall. - */ - if (!(proc_path = safe_snprintf(buffer, "/proc/%d", pid))) - goto fail; /* Open the directory, we are potentially reading multiple files from it */ - if (-1 == (proc_fd = open(proc_path, O_RDONLY | O_CLOEXEC))) + procfd_t proc_fd = game_mode_open_proc(pid); + + if (proc_fd == INVALID_PROCFD) goto fail_proc; /* Open the command line */ @@ -868,7 +859,7 @@ static char *game_mode_resolve_wine_preloader(pid_t pid) goto fail; error_cleanup: - close(proc_fd); + game_mode_close_proc(proc_fd); free(wineprefix); free(proc_path); return wine_exe; diff --git a/daemon/gamemode.h b/daemon/gamemode.h index 681f50a..81f68b7 100644 --- a/daemon/gamemode.h +++ b/daemon/gamemode.h @@ -34,6 +34,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#define INVALID_PROCFD -1 + +typedef int procfd_t; + /** * Opaque context */ @@ -83,3 +87,10 @@ bool game_mode_context_unregister(GameModeContext *self, pid_t pid); * 2 if gamemode is active and the client is registered */ int game_mode_context_query_status(GameModeContext *self, pid_t pid); + +/** gamemode-proc.c + * Provides internal API functions specific to working with process + * environments. + */ +procfd_t game_mode_open_proc(const pid_t pid); +int game_mode_close_proc(const procfd_t procfd); diff --git a/daemon/meson.build b/daemon/meson.build index 9f5f280..34d8caf 100644 --- a/daemon/meson.build +++ b/daemon/meson.build @@ -18,6 +18,7 @@ link_daemon_common = declare_dependency( daemon_sources = [ 'main.c', 'gamemode.c', + 'gamemode-proc.c', 'daemonize.c', 'dbus_messaging.c', 'governors.c',