Change how security config is loaded
This commit is contained in:
parent
14d9200e4e
commit
1172566d4e
|
@ -373,4 +373,9 @@ struct bar_config *default_bar_config(void);
|
||||||
*/
|
*/
|
||||||
extern struct sway_config *config;
|
extern struct sway_config *config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config file currently being read.
|
||||||
|
*/
|
||||||
|
extern const char *current_config_path;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
#
|
#
|
||||||
# You MUST read this man page if you intend to attempt to secure your sway
|
# You MUST read this man page if you intend to attempt to secure your sway
|
||||||
# installation.
|
# installation.
|
||||||
|
#
|
||||||
|
# This file should live at __SYSCONFDIR__/sway/security and will be
|
||||||
|
# automatically read by sway.
|
||||||
|
|
||||||
# Configures which programs are allowed to use which sway features
|
# Configures which programs are allowed to use which sway features
|
||||||
permit * fullscreen keyboard mouse ipc
|
permit * fullscreen keyboard mouse ipc
|
||||||
|
@ -40,11 +43,4 @@ commands {
|
||||||
bindsym config
|
bindsym config
|
||||||
exit binding
|
exit binding
|
||||||
kill binding
|
kill binding
|
||||||
|
|
||||||
# You should not change these unless you know what you're doing - it could
|
|
||||||
# cripple your security
|
|
||||||
reload binding
|
|
||||||
permit config
|
|
||||||
reject config
|
|
||||||
ipc config
|
|
||||||
}
|
}
|
|
@ -91,7 +91,7 @@ function(add_config name source destination)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_config(config config sway)
|
add_config(config config sway)
|
||||||
add_config(security config.d/security sway/config.d)
|
add_config(security security sway)
|
||||||
|
|
||||||
add_manpage(sway 1)
|
add_manpage(sway 1)
|
||||||
add_manpage(sway 5)
|
add_manpage(sway 5)
|
||||||
|
|
|
@ -19,5 +19,10 @@ struct cmd_results *cmd_commands(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_FAILURE, "commands", "Can only be used in config file.");
|
return cmd_results_new(CMD_FAILURE, "commands", "Can only be used in config file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "permit",
|
||||||
|
"This command is only permitted to run from " SYSCONFDIR "/sway/security");
|
||||||
|
}
|
||||||
|
|
||||||
return cmd_results_new(CMD_BLOCK_COMMANDS, NULL, NULL);
|
return cmd_results_new(CMD_BLOCK_COMMANDS, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,11 @@ struct cmd_results *cmd_ipc(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_FAILURE, "ipc", "Can only be used in config file.");
|
return cmd_results_new(CMD_FAILURE, "ipc", "Can only be used in config file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "permit",
|
||||||
|
"This command is only permitted to run from " SYSCONFDIR "/sway/security");
|
||||||
|
}
|
||||||
|
|
||||||
return cmd_results_new(CMD_BLOCK_IPC, NULL, NULL);
|
return cmd_results_new(CMD_BLOCK_IPC, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,11 @@ struct cmd_results *cmd_permit(int argc, char **argv) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "permit",
|
||||||
|
"This command is only permitted to run from " SYSCONFDIR "/sway/security");
|
||||||
|
}
|
||||||
|
|
||||||
struct feature_policy *policy = get_policy(argv[0]);
|
struct feature_policy *policy = get_policy(argv[0]);
|
||||||
policy->features |= get_features(argc, argv, &error);
|
policy->features |= get_features(argc, argv, &error);
|
||||||
|
|
||||||
|
@ -83,6 +88,11 @@ struct cmd_results *cmd_reject(int argc, char **argv) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "permit",
|
||||||
|
"This command is only permitted to run from " SYSCONFDIR "/sway/security");
|
||||||
|
}
|
||||||
|
|
||||||
struct feature_policy *policy = get_policy(argv[0]);
|
struct feature_policy *policy = get_policy(argv[0]);
|
||||||
policy->features &= ~get_features(argc, argv, &error);
|
policy->features &= ~get_features(argc, argv, &error);
|
||||||
|
|
||||||
|
|
|
@ -452,8 +452,11 @@ static char *get_config_path(void) {
|
||||||
return NULL; // Not reached
|
return NULL; // Not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *current_config_path;
|
||||||
|
|
||||||
static bool load_config(const char *path, struct sway_config *config) {
|
static bool load_config(const char *path, struct sway_config *config) {
|
||||||
sway_log(L_INFO, "Loading config from %s", path);
|
sway_log(L_INFO, "Loading config from %s", path);
|
||||||
|
current_config_path = path;
|
||||||
|
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||||
|
@ -474,11 +477,11 @@ static bool load_config(const char *path, struct sway_config *config) {
|
||||||
bool config_load_success = read_config(f, config);
|
bool config_load_success = read_config(f, config);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
|
||||||
if (!config_load_success) {
|
if (!config_load_success) {
|
||||||
sway_log(L_ERROR, "Error(s) loading config!");
|
sway_log(L_ERROR, "Error(s) loading config!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_config_path = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,7 +512,8 @@ bool load_main_config(const char *file, bool is_active) {
|
||||||
list_add(config->config_chain, path);
|
list_add(config->config_chain, path);
|
||||||
|
|
||||||
config->reading = true;
|
config->reading = true;
|
||||||
bool success = load_config(path, config);
|
bool success = load_config(SYSCONFDIR "/sway/security", config);
|
||||||
|
success = success && load_config(path, config);
|
||||||
|
|
||||||
if (is_active) {
|
if (is_active) {
|
||||||
config->reloading = false;
|
config->reloading = false;
|
||||||
|
|
31
sway/main.c
31
sway/main.c
|
@ -179,37 +179,6 @@ static void security_sanity_check() {
|
||||||
"!! DANGER !! " SYSCONFDIR "/sway is not secure! It should be owned by root and set to 0755 at the minimum");
|
"!! DANGER !! " SYSCONFDIR "/sway is not secure! It should be owned by root and set to 0755 at the minimum");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct {
|
|
||||||
char *command;
|
|
||||||
enum command_context context;
|
|
||||||
bool checked;
|
|
||||||
} expected[] = {
|
|
||||||
{ "reload", CONTEXT_BINDING, false },
|
|
||||||
{ "permit", CONTEXT_CONFIG, false },
|
|
||||||
{ "reject", CONTEXT_CONFIG, false },
|
|
||||||
{ "ipc", CONTEXT_CONFIG, false },
|
|
||||||
};
|
|
||||||
int expected_len = 4;
|
|
||||||
for (int i = 0; i < config->command_policies->length; ++i) {
|
|
||||||
struct command_policy *policy = config->command_policies->items[i];
|
|
||||||
for (int j = 0; j < expected_len; ++j) {
|
|
||||||
if (strcmp(expected[j].command, policy->command) == 0) {
|
|
||||||
expected[j].checked = true;
|
|
||||||
if (expected[j].context != policy->context) {
|
|
||||||
sway_log(L_ERROR,
|
|
||||||
"!! DANGER !! Command security policy for %s should be set to %s",
|
|
||||||
expected[j].command, command_policy_str(expected[j].context));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int j = 0; j < expected_len; ++j) {
|
|
||||||
if (!expected[j].checked) {
|
|
||||||
sway_log(L_ERROR,
|
|
||||||
"!! DANGER !! Command security policy for %s should be set to %s",
|
|
||||||
expected[j].command, command_policy_str(expected[j].context));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
|
@ -19,22 +19,8 @@ usually best suited to a distro maintainer who wants to ship a secure sway
|
||||||
environment in their distro. Sway provides a number of means of securing it but
|
environment in their distro. Sway provides a number of means of securing it but
|
||||||
you must make a few changes external to sway first.
|
you must make a few changes external to sway first.
|
||||||
|
|
||||||
Configuration security
|
Security-related configuration is only valid in /etc/sway/config (or whatever path
|
||||||
----------------------
|
is appropriate for your system).
|
||||||
|
|
||||||
Many of Sway's security features are configurable. It's important that a possibly
|
|
||||||
untrusted program is not able to edit this. Security rules are kept in
|
|
||||||
_/etc/sway/config.d/security_ (usually), which should only be writable by root.
|
|
||||||
However, configuration of security rules is not limited to this file - any config
|
|
||||||
file that sway loads (including i.e. _~/.config/sway/config_) should not be editable
|
|
||||||
by the user you intend to run programs as. One simple strategy is to use
|
|
||||||
/etc/sway/config instead of a config file in your home directory, but that doesn't
|
|
||||||
work well for multi-user systems. A more robust strategy is to run untrusted
|
|
||||||
programs as another user, or in a sandbox. Configuring this is up to you.
|
|
||||||
|
|
||||||
Note that _/etc/sway/config.d/*_ must be included explicitly from your config file.
|
|
||||||
This is done by default in /etc/sway/config but you must check your own config if
|
|
||||||
you choose to place it in other locations.
|
|
||||||
|
|
||||||
Environment security
|
Environment security
|
||||||
--------------------
|
--------------------
|
||||||
|
|
Loading…
Reference in a new issue