Enforce IPC security policy

This commit is contained in:
Drew DeVault 2016-12-02 17:55:03 -05:00
parent c8dc4925d1
commit 62dad7148f
3 changed files with 65 additions and 13 deletions

View file

@ -209,6 +209,23 @@ struct feature_policy {
uint32_t features; uint32_t features;
}; };
enum ipc_feature {
IPC_FEATURE_COMMAND = 1,
IPC_FEATURE_GET_WORKSPACES = 2,
IPC_FEATURE_GET_OUTPUTS = 4,
IPC_FEATURE_GET_TREE = 8,
IPC_FEATURE_GET_MARKS = 16,
IPC_FEATURE_GET_BAR_CONFIG = 32,
IPC_FEATURE_GET_VERSION = 64,
IPC_FEATURE_GET_INPUTS = 128,
IPC_FEATURE_EVENT_WORKSPACE = 256,
IPC_FEATURE_EVENT_OUTPUT = 512,
IPC_FEATURE_EVENT_MODE = 1024,
IPC_FEATURE_EVENT_WINDOW = 2048,
IPC_FEATURE_EVENT_BINDING = 4096,
IPC_FEATURE_EVENT_INPUT = 8192
};
/** /**
* The configuration struct. The result of loading a config file. * The configuration struct. The result of loading a config file.
*/ */

View file

@ -62,13 +62,13 @@ struct cmd_results *cmd_ipc_cmd(int argc, char **argv) {
char *name; char *name;
enum ipc_command_type type; enum ipc_command_type type;
} types[] = { } types[] = {
{ "command", IPC_COMMAND }, { "command", IPC_FEATURE_COMMAND },
{ "workspaces", IPC_GET_WORKSPACES }, { "workspaces", IPC_FEATURE_GET_WORKSPACES },
{ "outputs", IPC_GET_OUTPUTS }, { "outputs", IPC_FEATURE_GET_OUTPUTS },
{ "tree", IPC_GET_TREE }, { "tree", IPC_FEATURE_GET_TREE },
{ "marks", IPC_GET_MARKS }, { "marks", IPC_FEATURE_GET_MARKS },
{ "bar-config", IPC_GET_BAR_CONFIG }, { "bar-config", IPC_FEATURE_GET_BAR_CONFIG },
{ "inputs", IPC_GET_INPUTS }, { "inputs", IPC_FEATURE_GET_INPUTS },
}; };
uint32_t type = 0; uint32_t type = 0;
@ -111,12 +111,12 @@ struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) {
char *name; char *name;
enum ipc_command_type type; enum ipc_command_type type;
} types[] = { } types[] = {
{ "workspace", event_mask(IPC_EVENT_WORKSPACE) }, { "workspace", IPC_FEATURE_EVENT_WORKSPACE },
{ "output", event_mask(IPC_EVENT_OUTPUT) }, { "output", IPC_FEATURE_EVENT_OUTPUT },
{ "mode", event_mask(IPC_EVENT_MODE) }, { "mode", IPC_FEATURE_EVENT_MODE },
{ "window", event_mask(IPC_EVENT_WINDOW) }, { "window", IPC_FEATURE_EVENT_WINDOW },
{ "binding", event_mask(IPC_EVENT_BINDING) }, { "binding", IPC_FEATURE_EVENT_BINDING },
{ "input", event_mask(IPC_EVENT_INPUT) }, { "input", IPC_FEATURE_EVENT_INPUT },
}; };
uint32_t type = 0; uint32_t type = 0;

View file

@ -307,9 +307,14 @@ void ipc_client_handle_command(struct ipc_client *client) {
} }
buf[client->payload_length] = '\0'; buf[client->payload_length] = '\0';
const char *error_denied = "{ \"success\": false, \"error\": \"Permission denied\" }";
switch (client->current_command) { switch (client->current_command) {
case IPC_COMMAND: case IPC_COMMAND:
{ {
if (!(config->ipc_policy & IPC_FEATURE_COMMAND)) {
goto exit_denied;
}
struct cmd_results *results = handle_command(buf, CONTEXT_IPC); struct cmd_results *results = handle_command(buf, CONTEXT_IPC);
const char *json = cmd_results_to_json(results); const char *json = cmd_results_to_json(results);
char reply[256]; char reply[256];
@ -359,6 +364,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_WORKSPACES: case IPC_GET_WORKSPACES:
{ {
if (!(config->ipc_policy & IPC_FEATURE_GET_WORKSPACES)) {
goto exit_denied;
}
json_object *workspaces = json_object_new_array(); json_object *workspaces = json_object_new_array();
container_map(&root_container, ipc_get_workspaces_callback, workspaces); container_map(&root_container, ipc_get_workspaces_callback, workspaces);
const char *json_string = json_object_to_json_string(workspaces); const char *json_string = json_object_to_json_string(workspaces);
@ -369,6 +377,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_INPUTS: case IPC_GET_INPUTS:
{ {
if (!(config->ipc_policy & IPC_FEATURE_GET_INPUTS)) {
goto exit_denied;
}
json_object *inputs = json_object_new_array(); json_object *inputs = json_object_new_array();
if (input_devices) { if (input_devices) {
for(int i=0; i<input_devices->length; i++) { for(int i=0; i<input_devices->length; i++) {
@ -388,6 +399,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_OUTPUTS: case IPC_GET_OUTPUTS:
{ {
if (!(config->ipc_policy & IPC_FEATURE_GET_OUTPUTS)) {
goto exit_denied;
}
json_object *outputs = json_object_new_array(); json_object *outputs = json_object_new_array();
container_map(&root_container, ipc_get_outputs_callback, outputs); container_map(&root_container, ipc_get_outputs_callback, outputs);
const char *json_string = json_object_to_json_string(outputs); const char *json_string = json_object_to_json_string(outputs);
@ -398,6 +412,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_TREE: 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); json_object *tree = ipc_json_describe_container_recursive(&root_container);
const char *json_string = json_object_to_json_string(tree); const char *json_string = json_object_to_json_string(tree);
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
@ -458,6 +475,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_BAR_CONFIG: case IPC_GET_BAR_CONFIG:
{ {
if (!(config->ipc_policy & IPC_FEATURE_GET_BAR_CONFIG)) {
goto exit_denied;
}
if (!buf[0]) { if (!buf[0]) {
// Send list of configured bar IDs // Send list of configured bar IDs
json_object *bars = json_object_new_array(); json_object *bars = json_object_new_array();
@ -498,6 +518,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
goto exit_cleanup; goto exit_cleanup;
} }
exit_denied:
ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied));
exit_cleanup: exit_cleanup:
client->payload_length = 0; client->payload_length = 0;
free(buf); free(buf);
@ -562,6 +585,9 @@ 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) { 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); sway_log(L_DEBUG, "Sending workspace::%s event", change);
json_object *obj = json_object_new_object(); json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(change)); json_object_object_add(obj, "change", json_object_new_string(change));
@ -586,6 +612,9 @@ void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) {
} }
void ipc_event_window(swayc_t *window, 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); sway_log(L_DEBUG, "Sending window::%s event", change);
json_object *obj = json_object_new_object(); json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(change)); json_object_object_add(obj, "change", json_object_new_string(change));
@ -611,6 +640,9 @@ void ipc_event_barconfig_update(struct bar_config *bar) {
} }
void ipc_event_mode(const char *mode) { 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); sway_log(L_DEBUG, "Sending mode::%s event", mode);
json_object *obj = json_object_new_object(); json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(mode)); json_object_object_add(obj, "change", json_object_new_string(mode));
@ -636,6 +668,9 @@ void ipc_event_modifier(uint32_t modifier, const char *state) {
} }
static void ipc_event_binding(json_object *sb_obj) { 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"); sway_log(L_DEBUG, "Sending binding::run event");
json_object *obj = json_object_new_object(); json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string("run")); json_object_object_add(obj, "change", json_object_new_string("run"));