Browse Source

Implement supervisor features using new config variables

	This allows direct control over who can make requests on behalf of other processes

	require_supervisor can also be used to allow a supervisor to take direct control of gamemode on the system (perhaps a GUI, or game launcher)
Marc Di Luzio 6 years ago
parent
commit
1430c0b831
4 changed files with 130 additions and 8 deletions
  1. 61 0
      daemon/daemon_config.c
  2. 7 0
      daemon/daemon_config.h
  3. 52 8
      daemon/gamemode.c
  4. 10 0
      example/gamemode.ini

+ 61 - 0
daemon/daemon_config.c

@@ -94,6 +94,10 @@ struct GameModeConfig {
 		long nv_perf_level;
 		long amd_core_clock_percentage;
 		long amd_mem_clock_percentage;
+
+		long require_supervisor;
+		char supervisor_whitelist[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
+		char supervisor_blacklist[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
 	} values;
 };
 
@@ -261,6 +265,15 @@ static int inih_handler(void *user, const char *section, const char *name, const
 		} else if (strcmp(name, "amd_mem_clock_percentage") == 0) {
 			valid = get_long_value(name, value, &self->values.amd_mem_clock_percentage);
 		}
+	} else if (strcmp(section, "supervisor") == 0) {
+		/* Supervisor subsection */
+		if (strcmp(name, "supervisor_whitelist") == 0) {
+			valid = append_value_to_list(name, value, self->values.supervisor_whitelist);
+		} else if (strcmp(name, "supervisor_blacklist") == 0) {
+			valid = append_value_to_list(name, value, self->values.supervisor_blacklist);
+		} else if (strcmp(name, "require_supervisor") == 0) {
+			valid = get_long_value(name, value, &self->values.require_supervisor);
+		}
 	} else if (strcmp(section, "custom") == 0) {
 		/* Custom subsection */
 		if (strcmp(name, "start") == 0) {
@@ -568,3 +581,51 @@ DEFINE_CONFIG_GET(nv_mem_clock_mhz_offset)
 DEFINE_CONFIG_GET(nv_perf_level)
 DEFINE_CONFIG_GET(amd_core_clock_percentage)
 DEFINE_CONFIG_GET(amd_mem_clock_percentage)
+
+/*
+        char supervisor_whitelist[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
+        char supervisor_blacklist[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
+*/
+DEFINE_CONFIG_GET(require_supervisor)
+
+/*
+ * Checks if the supervisor is whitelisted
+ */
+bool config_get_supervisor_whitelisted(GameModeConfig *self, const char *supervisor)
+{
+	/* Take the read lock for the internal data */
+	pthread_rwlock_rdlock(&self->rwlock);
+
+	/* If the whitelist is empty then everything passes */
+	bool found = true;
+	if (self->values.supervisor_whitelist[0][0]) {
+		/*
+		 * Check if the value is found in our whitelist
+		 * Currently is a simple strstr check, but could be modified for wildcards etc.
+		 */
+		found = config_string_list_contains(supervisor, self->values.supervisor_whitelist);
+	}
+
+	/* release the lock */
+	pthread_rwlock_unlock(&self->rwlock);
+	return found;
+}
+
+/*
+ * Checks if the supervisor is blacklisted
+ */
+bool config_get_supervisor_blacklisted(GameModeConfig *self, const char *supervisor)
+{
+	/* Take the read lock for the internal data */
+	pthread_rwlock_rdlock(&self->rwlock);
+
+	/*
+	 * Check if the value is found in our whitelist
+	 * Currently is a simple strstr check, but could be modified for wildcards etc.
+	 */
+	bool found = config_string_list_contains(supervisor, self->values.supervisor_blacklist);
+
+	/* release the lock */
+	pthread_rwlock_unlock(&self->rwlock);
+	return found;
+}

+ 7 - 0
daemon/daemon_config.h

@@ -141,3 +141,10 @@ long config_get_nv_mem_clock_mhz_offset(GameModeConfig *self);
 long config_get_nv_perf_level(GameModeConfig *self);
 long config_get_amd_core_clock_percentage(GameModeConfig *self);
 long config_get_amd_mem_clock_percentage(GameModeConfig *self);
+
+/**
+ * Functions to get supervisor config permissions
+ */
+long config_get_require_supervisor(GameModeConfig *self);
+bool config_get_supervisor_whitelisted(GameModeConfig *self, const char *supervisor);
+bool config_get_supervisor_blacklisted(GameModeConfig *self, const char *supervisor);

+ 52 - 8
daemon/gamemode.c

@@ -504,13 +504,36 @@ int game_mode_context_query_status(GameModeContext *self, pid_t client)
 
 /**
  * Stub to register on behalf of caller
+ * TODO: long config_get_require_supervisor(GameModeConfig *self);
  */
 int game_mode_context_register_by_pid(GameModeContext *self, pid_t callerpid, pid_t gamepid)
 {
-	(void)self;
-	(void)callerpid;
-	(void)gamepid;
-	return 0;
+	int status = 0;
+
+	/* Lookup the executable first */
+	char *executable = game_mode_context_find_exe(callerpid);
+	if (!executable) {
+		status = -1;
+		goto error_cleanup;
+	}
+
+	/* Check our blacklist and whitelist */
+	if (!config_get_supervisor_whitelisted(self->config, executable)) {
+		LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
+		status = -2;
+		goto error_cleanup;
+	} else if (config_get_supervisor_blacklisted(self->config, executable)) {
+		LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
+		status = -2;
+		goto error_cleanup;
+	}
+
+	/* Checks cleared, try and register the game */
+	return game_mode_context_register(self, gamepid);
+
+error_cleanup:
+	free(executable);
+	return status;
 }
 
 /**
@@ -518,10 +541,31 @@ int game_mode_context_register_by_pid(GameModeContext *self, pid_t callerpid, pi
  */
 int game_mode_context_unregister_by_pid(GameModeContext *self, pid_t callerpid, pid_t gamepid)
 {
-	(void)self;
-	(void)callerpid;
-	(void)gamepid;
-	return 0;
+	int status = 0;
+
+	/* Lookup the executable first */
+	char *executable = game_mode_context_find_exe(callerpid);
+	if (!executable) {
+		status = -1;
+		goto error_cleanup;
+	}
+
+	/* Check our blacklist and whitelist */
+	if (!config_get_supervisor_whitelisted(self->config, executable)) {
+		LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
+		status = -2;
+		goto error_cleanup;
+	} else if (config_get_supervisor_blacklisted(self->config, executable)) {
+		LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
+		status = -2;
+		goto error_cleanup;
+	}
+	/* Checks cleared, try and register the game */
+	return game_mode_context_unregister(self, gamepid);
+
+error_cleanup:
+	free(executable);
+	return status;
 }
 
 /**

+ 10 - 0
example/gamemode.ini

@@ -61,6 +61,16 @@ inhibit_screensaver=1
 ;amd_core_clock_percentage=0
 ;amd_mem_clock_percentage=0
 
+[supervisor]
+; This section controls the new gamemode functions gamemode_request_start_for and gamemode_request_end_for
+; The whilelist and blacklist control which supervisor programs are allowed to make the above requests
+;supervisor_whitelist=
+;supervisor_blacklist=
+
+; In case you want to allow a supervisor to take full control of gamemode, this option can be set
+; This will only allow gamemode clients to be registered by using the above functions by a supervisor client
+;require_supervisor=0
+
 [custom]
 ; Custom scripts (executed using the shell) when gamemode starts and ends
 ;start=notify-send "GameMode started"