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)
This commit is contained in:
Marc Di Luzio 2019-02-09 15:49:46 +00:00
parent d60ac23daa
commit 1430c0b831
4 changed files with 130 additions and 8 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
/**

View File

@ -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"