From b10721b89e3f3992b2476c55237a25dbeb0bce46 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 20 Feb 2017 06:11:43 -0500 Subject: [PATCH] Add initial support code for new IPC security --- include/sway/config.h | 8 ++++-- include/sway/security.h | 6 +++-- sway/commands/ipc.c | 12 ++++----- sway/commands/permit.c | 1 - sway/config.c | 2 +- sway/ipc-server.c | 45 +++------------------------------- sway/security.c | 54 ++++++++++++++++++++++++++++++++++++++--- 7 files changed, 70 insertions(+), 58 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index febde63d..c3a916b1 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -203,7 +203,6 @@ enum secure_feature { FEATURE_FULLSCREEN = 16, FEATURE_KEYBOARD = 32, FEATURE_MOUSE = 64, - FEATURE_IPC = 128, }; struct feature_policy { @@ -228,6 +227,11 @@ enum ipc_feature { IPC_FEATURE_EVENT_INPUT = 8192 }; +struct ipc_policy { + char *program; + uint32_t features; +}; + /** * The configuration struct. The result of loading a config file. */ @@ -300,7 +304,7 @@ struct sway_config { // Security list_t *command_policies; list_t *feature_policies; - uint32_t ipc_policy; + list_t *ipc_policies; }; void pid_workspace_add(struct pid_workspace *pw); diff --git a/include/sway/security.h b/include/sway/security.h index 1cc85bee..c3a5cfd4 100644 --- a/include/sway/security.h +++ b/include/sway/security.h @@ -3,12 +3,14 @@ #include #include "sway/config.h" -enum secure_feature get_feature_policy(pid_t pid); -enum command_context get_command_policy(const char *cmd); +uint32_t get_feature_policy(pid_t pid); +uint32_t get_ipc_policy(pid_t pid); +uint32_t get_command_policy(const char *cmd); const char *command_policy_str(enum command_context context); struct feature_policy *alloc_feature_policy(const char *program); +struct ipc_policy *alloc_ipc_policy(const char *program); struct command_policy *alloc_command_policy(const char *command); #endif diff --git a/sway/commands/ipc.c b/sway/commands/ipc.c index 113a975b..44d7a010 100644 --- a/sway/commands/ipc.c +++ b/sway/commands/ipc.c @@ -86,10 +86,10 @@ struct cmd_results *cmd_ipc_cmd(int argc, char **argv) { } if (enabled) { - config->ipc_policy |= type; - sway_log(L_DEBUG, "Enabled IPC %s feature", argv[-1]); + //config->ipc_policy |= type; + sway_log(L_DEBUG, "Enabled IPC %s feature %d", argv[-1], (int)type); } else { - config->ipc_policy &= ~type; + //config->ipc_policy &= ~type; sway_log(L_DEBUG, "Disabled IPC %s feature", argv[-1]); } @@ -134,10 +134,10 @@ struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) { } if (enabled) { - config->ipc_policy |= type; - sway_log(L_DEBUG, "Enabled IPC %s event", argv[-1]); + //config->ipc_policy |= type; + sway_log(L_DEBUG, "Enabled IPC %s event %d", argv[-1], (int)type); } else { - config->ipc_policy &= ~type; + //config->ipc_policy &= ~type; sway_log(L_DEBUG, "Disabled IPC %s event", argv[-1]); } diff --git a/sway/commands/permit.c b/sway/commands/permit.c index 1b2a30bf..6eb71816 100644 --- a/sway/commands/permit.c +++ b/sway/commands/permit.c @@ -19,7 +19,6 @@ static enum secure_feature get_features(int argc, char **argv, { "fullscreen", FEATURE_FULLSCREEN }, { "keyboard", FEATURE_KEYBOARD }, { "mouse", FEATURE_MOUSE }, - { "ipc", FEATURE_IPC }, }; for (int i = 1; i < argc; ++i) { diff --git a/sway/config.c b/sway/config.c index 9e758c90..4a3c953d 100644 --- a/sway/config.c +++ b/sway/config.c @@ -379,7 +379,7 @@ static void config_defaults(struct sway_config *config) { // Security if (!(config->command_policies = create_list())) goto cleanup; if (!(config->feature_policies = create_list())) goto cleanup; - config->ipc_policy = UINT32_MAX; + if (!(config->ipc_policies = create_list())) goto cleanup; return; cleanup: diff --git a/sway/ipc-server.c b/sway/ipc-server.c index be6e411a..dfe88ed6 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -125,6 +125,7 @@ struct sockaddr_un *ipc_user_sockaddr(void) { return ipc_sockaddr; } +/* static pid_t get_client_pid(int client_fd) { // FreeBSD supports getting uid/gid, but not pid #ifdef __linux__ @@ -140,6 +141,7 @@ static pid_t get_client_pid(int client_fd) { return -1; #endif } +*/ int ipc_handle_connection(int fd, uint32_t mask, void *data) { (void) fd; (void) data; @@ -159,17 +161,6 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { return 0; } - pid_t pid = get_client_pid(client_fd); - if (!(get_feature_policy(pid) & FEATURE_IPC)) { - sway_log(L_INFO, "Permission to connect to IPC socket denied to %d", pid); - const char *error = "{\"success\": false, \"message\": \"Permission denied\"}"; - if (write(client_fd, &error, sizeof(error)) < (int)sizeof(error)) { - sway_log(L_DEBUG, "Failed to write entire error"); - } - close(client_fd); - return 0; - } - struct ipc_client* client = malloc(sizeof(struct ipc_client)); if (!client) { sway_log(L_ERROR, "Unable to allocate ipc client"); @@ -351,9 +342,6 @@ void ipc_client_handle_command(struct ipc_client *client) { switch (client->current_command) { case IPC_COMMAND: { - if (!(config->ipc_policy & IPC_FEATURE_COMMAND)) { - goto exit_denied; - } struct cmd_results *results = handle_command(buf, CONTEXT_IPC); const char *json = cmd_results_to_json(results); char reply[256]; @@ -403,9 +391,6 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_WORKSPACES: { - if (!(config->ipc_policy & IPC_FEATURE_GET_WORKSPACES)) { - goto exit_denied; - } json_object *workspaces = json_object_new_array(); container_map(&root_container, ipc_get_workspaces_callback, workspaces); const char *json_string = json_object_to_json_string(workspaces); @@ -416,9 +401,6 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_INPUTS: { - if (!(config->ipc_policy & IPC_FEATURE_GET_INPUTS)) { - goto exit_denied; - } json_object *inputs = json_object_new_array(); if (input_devices) { for(int i=0; ilength; i++) { @@ -442,9 +424,6 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_OUTPUTS: { - if (!(config->ipc_policy & IPC_FEATURE_GET_OUTPUTS)) { - goto exit_denied; - } json_object *outputs = json_object_new_array(); container_map(&root_container, ipc_get_outputs_callback, outputs); const char *json_string = json_object_to_json_string(outputs); @@ -455,9 +434,6 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_TREE: { - if (!(config->ipc_policy & IPC_FEATURE_GET_TREE)) { - goto exit_denied; - } json_object *tree = ipc_json_describe_container_recursive(&root_container); const char *json_string = json_object_to_json_string(tree); ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); @@ -522,9 +498,6 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_BAR_CONFIG: { - if (!(config->ipc_policy & IPC_FEATURE_GET_BAR_CONFIG)) { - goto exit_denied; - } if (!buf[0]) { // Send list of configured bar IDs json_object *bars = json_object_new_array(); @@ -565,7 +538,7 @@ void ipc_client_handle_command(struct ipc_client *client) { goto exit_cleanup; } -exit_denied: +//exit_denied: ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); exit_cleanup: @@ -632,9 +605,6 @@ void ipc_send_event(const char *json_string, enum ipc_command_type event) { } void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { - if (!(config->ipc_policy & IPC_FEATURE_EVENT_WORKSPACE)) { - return; - } sway_log(L_DEBUG, "Sending workspace::%s event", change); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(change)); @@ -659,9 +629,6 @@ void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { } void ipc_event_window(swayc_t *window, const char *change) { - if (!(config->ipc_policy & IPC_FEATURE_EVENT_WINDOW)) { - return; - } sway_log(L_DEBUG, "Sending window::%s event", change); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(change)); @@ -687,9 +654,6 @@ void ipc_event_barconfig_update(struct bar_config *bar) { } void ipc_event_mode(const char *mode) { - if (!(config->ipc_policy & IPC_FEATURE_EVENT_MODE)) { - return; - } sway_log(L_DEBUG, "Sending mode::%s event", mode); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(mode)); @@ -715,9 +679,6 @@ void ipc_event_modifier(uint32_t modifier, const char *state) { } static void ipc_event_binding(json_object *sb_obj) { - if (!(config->ipc_policy & IPC_FEATURE_EVENT_BINDING)) { - return; - } sway_log(L_DEBUG, "Sending binding::run event"); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string("run")); diff --git a/sway/security.c b/sway/security.c index 41a3b94b..9dfc7d2d 100644 --- a/sway/security.c +++ b/sway/security.c @@ -27,6 +27,29 @@ struct feature_policy *alloc_feature_policy(const char *program) { return policy; } +struct ipc_policy *alloc_ipc_policy(const char *program) { + uint32_t default_policy = 0; + for (int i = 0; i < config->ipc_policies->length; ++i) { + struct ipc_policy *policy = config->ipc_policies->items[i]; + if (strcmp(policy->program, "*") == 0) { + default_policy = policy->features; + break; + } + } + + struct ipc_policy *policy = malloc(sizeof(struct ipc_policy)); + if (!policy) { + return NULL; + } + policy->program = strdup(program); + if (!policy->program) { + free(policy); + return NULL; + } + policy->features = default_policy; + return policy; +} + struct command_policy *alloc_command_policy(const char *command) { struct command_policy *policy = malloc(sizeof(struct command_policy)); if (!policy) { @@ -41,7 +64,7 @@ struct command_policy *alloc_command_policy(const char *command) { return policy; } -enum secure_feature get_feature_policy(pid_t pid) { +static const char *get_pid_exe(pid_t pid) { #ifdef __FreeBSD__ const char *fmt = "/proc/%d/file"; #else @@ -52,9 +75,8 @@ enum secure_feature get_feature_policy(pid_t pid) { if (path) { snprintf(path, pathlen + 1, fmt, pid); } - static char link[2048]; - uint32_t default_policy = 0; + static char link[2048]; ssize_t len = !path ? -1 : readlink(path, link, sizeof(link)); if (len < 0) { @@ -67,6 +89,13 @@ enum secure_feature get_feature_policy(pid_t pid) { } free(path); + return link; +} + +uint32_t get_feature_policy(pid_t pid) { + uint32_t default_policy = 0; + const char *link = get_pid_exe(pid); + for (int i = 0; i < config->feature_policies->length; ++i) { struct feature_policy *policy = config->feature_policies->items[i]; if (strcmp(policy->program, "*") == 0) { @@ -80,7 +109,24 @@ enum secure_feature get_feature_policy(pid_t pid) { return default_policy; } -enum command_context get_command_policy(const char *cmd) { +uint32_t get_ipc_policy(pid_t pid) { + uint32_t default_policy = 0; + const char *link = get_pid_exe(pid); + + for (int i = 0; i < config->ipc_policies->length; ++i) { + struct ipc_policy *policy = config->ipc_policies->items[i]; + if (strcmp(policy->program, "*") == 0) { + default_policy = policy->features; + } + if (strcmp(policy->program, link) == 0) { + return policy->features; + } + } + + return default_policy; +} + +uint32_t get_command_policy(const char *cmd) { uint32_t default_policy = 0; for (int i = 0; i < config->command_policies->length; ++i) {