aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Ashkan Kiani <ashkan.k.kiani@gmail.com>2019-04-16 17:35:39 -0700
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2019-04-16 23:48:44 -0400
commitaa4deef8a86ccddbd0d9a7d894e72ac329d8960d (patch)
treeed8912b35c93d3a2a259215cbbebc74d562369d7
parentDon't apply hide_edge_borders to floating windows (diff)
downloadsway-aa4deef8a86ccddbd0d9a7d894e72ac329d8960d.tar.gz
sway-aa4deef8a86ccddbd0d9a7d894e72ac329d8960d.tar.zst
sway-aa4deef8a86ccddbd0d9a7d894e72ac329d8960d.zip
Fix the payload type returned by IPC
If a client is subscribed and sends a subsequent ipc command which causes event updates, then those event updates override the `client->current_command` and send the incorrect type for the payload associated with the command. Example: SUBSCRIBE {window} RUN_COMMAND focus -> PAYLOAD_TYPE is 0x80000002 for window events Therefore, we decouple the `client->current_command` by passing it as an argument to the ipc_send_reply function, avoiding a data race. The same is done for the `client->payload_length` as a precautionary measure for the same reason.
-rw-r--r--sway/ipc-server.c136
1 files changed, 72 insertions, 64 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index e133a5bf..ca1c1b12 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -47,13 +47,14 @@ struct ipc_client {
47 struct wl_event_source *writable_event_source; 47 struct wl_event_source *writable_event_source;
48 struct sway_server *server; 48 struct sway_server *server;
49 int fd; 49 int fd;
50 uint32_t payload_length;
51 uint32_t security_policy; 50 uint32_t security_policy;
52 enum ipc_command_type current_command;
53 enum ipc_command_type subscribed_events; 51 enum ipc_command_type subscribed_events;
54 size_t write_buffer_len; 52 size_t write_buffer_len;
55 size_t write_buffer_size; 53 size_t write_buffer_size;
56 char *write_buffer; 54 char *write_buffer;
55 // The following are for storing data between event_loop calls
56 uint32_t pending_length;
57 enum ipc_command_type pending_type;
57}; 58};
58 59
59struct sockaddr_un *ipc_user_sockaddr(void); 60struct sockaddr_un *ipc_user_sockaddr(void);
@@ -61,8 +62,10 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data);
61int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); 62int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
62int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data); 63int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
63void ipc_client_disconnect(struct ipc_client *client); 64void ipc_client_disconnect(struct ipc_client *client);
64void ipc_client_handle_command(struct ipc_client *client); 65void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_length,
65bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); 66 enum ipc_command_type payload_type);
67bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_type,
68 const char *payload, uint32_t payload_length);
66 69
67static void handle_display_destroy(struct wl_listener *listener, void *data) { 70static void handle_display_destroy(struct wl_listener *listener, void *data) {
68 if (ipc_event_source) { 71 if (ipc_event_source) {
@@ -178,7 +181,7 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
178 return 0; 181 return 0;
179 } 182 }
180 client->server = server; 183 client->server = server;
181 client->payload_length = 0; 184 client->pending_length = 0;
182 client->fd = client_fd; 185 client->fd = client_fd;
183 client->subscribed_events = 0; 186 client->subscribed_events = 0;
184 client->event_source = wl_event_loop_add_fd(server->wl_event_loop, 187 client->event_source = wl_event_loop_add_fd(server->wl_event_loop,
@@ -224,9 +227,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
224 } 227 }
225 228
226 // Wait for the rest of the command payload in case the header has already been read 229 // Wait for the rest of the command payload in case the header has already been read
227 if (client->payload_length > 0) { 230 if (client->pending_length > 0) {
228 if ((uint32_t)read_available >= client->payload_length) { 231 if ((uint32_t)read_available >= client->pending_length) {
229 ipc_client_handle_command(client); 232 // Reset pending values.
233 uint32_t pending_length = client->pending_length;
234 enum ipc_command_type pending_type = client->pending_type;
235 client->pending_length = 0;
236 ipc_client_handle_command(client, pending_length, pending_type);
230 } 237 }
231 return 0; 238 return 0;
232 } 239 }
@@ -251,11 +258,15 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
251 return 0; 258 return 0;
252 } 259 }
253 260
254 memcpy(&client->payload_length, &buf32[0], sizeof(buf32[0])); 261 memcpy(&client->pending_length, &buf32[0], sizeof(buf32[0]));
255 memcpy(&client->current_command, &buf32[1], sizeof(buf32[1])); 262 memcpy(&client->pending_type, &buf32[1], sizeof(buf32[1]));
256 263
257 if (read_available - received >= (long)client->payload_length) { 264 if (read_available - received >= (long)client->pending_length) {
258 ipc_client_handle_command(client); 265 // Reset pending values.
266 uint32_t pending_length = client->pending_length;
267 enum ipc_command_type pending_type = client->pending_type;
268 client->pending_length = 0;
269 ipc_client_handle_command(client, pending_length, pending_type);
259 } 270 }
260 271
261 return 0; 272 return 0;
@@ -278,8 +289,8 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event)
278 if ((client->subscribed_events & event_mask(event)) == 0) { 289 if ((client->subscribed_events & event_mask(event)) == 0) {
279 continue; 290 continue;
280 } 291 }
281 client->current_command = event; 292 if (!ipc_send_reply(client, event, json_string,
282 if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) { 293 (uint32_t)strlen(json_string))) {
283 sway_log_errno(SWAY_INFO, "Unable to send reply to IPC client"); 294 sway_log_errno(SWAY_INFO, "Unable to send reply to IPC client");
284 /* ipc_send_reply destroys client on error, which also 295 /* ipc_send_reply destroys client on error, which also
285 * removes it from the list, so we need to process 296 * removes it from the list, so we need to process
@@ -567,20 +578,21 @@ static void ipc_get_marks_callback(struct sway_container *con, void *data) {
567 } 578 }
568} 579}
569 580
570void ipc_client_handle_command(struct ipc_client *client) { 581void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_length,
582 enum ipc_command_type payload_type) {
571 if (!sway_assert(client != NULL, "client != NULL")) { 583 if (!sway_assert(client != NULL, "client != NULL")) {
572 return; 584 return;
573 } 585 }
574 586
575 char *buf = malloc(client->payload_length + 1); 587 char *buf = malloc(payload_length + 1);
576 if (!buf) { 588 if (!buf) {
577 sway_log_errno(SWAY_INFO, "Unable to allocate IPC payload"); 589 sway_log_errno(SWAY_INFO, "Unable to allocate IPC payload");
578 ipc_client_disconnect(client); 590 ipc_client_disconnect(client);
579 return; 591 return;
580 } 592 }
581 if (client->payload_length > 0) { 593 if (payload_length > 0) {
582 // Payload should be fully available 594 // Payload should be fully available
583 ssize_t received = recv(client->fd, buf, client->payload_length, 0); 595 ssize_t received = recv(client->fd, buf, payload_length, 0);
584 if (received == -1) 596 if (received == -1)
585 { 597 {
586 sway_log_errno(SWAY_INFO, "Unable to receive payload from IPC client"); 598 sway_log_errno(SWAY_INFO, "Unable to receive payload from IPC client");
@@ -589,16 +601,15 @@ void ipc_client_handle_command(struct ipc_client *client) {
589 return; 601 return;
590 } 602 }
591 } 603 }
592 buf[client->payload_length] = '\0'; 604 buf[payload_length] = '\0';
593 605
594 bool client_valid = true; 606 switch (payload_type) {
595 switch (client->current_command) {
596 case IPC_COMMAND: 607 case IPC_COMMAND:
597 { 608 {
598 char *line = strtok(buf, "\n"); 609 char *line = strtok(buf, "\n");
599 while (line) { 610 while (line) {
600 size_t line_length = strlen(line); 611 size_t line_length = strlen(line);
601 if (line + line_length >= buf + client->payload_length) { 612 if (line + line_length >= buf + payload_length) {
602 break; 613 break;
603 } 614 }
604 line[line_length] = ';'; 615 line[line_length] = ';';
@@ -609,7 +620,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
609 transaction_commit_dirty(); 620 transaction_commit_dirty();
610 char *json = cmd_results_to_json(res_list); 621 char *json = cmd_results_to_json(res_list);
611 int length = strlen(json); 622 int length = strlen(json);
612 client_valid = ipc_send_reply(client, json, (uint32_t)length); 623 ipc_send_reply(client, payload_type, json, (uint32_t)length);
613 free(json); 624 free(json);
614 while (res_list->length) { 625 while (res_list->length) {
615 struct cmd_results *results = res_list->items[0]; 626 struct cmd_results *results = res_list->items[0];
@@ -623,7 +634,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
623 case IPC_SEND_TICK: 634 case IPC_SEND_TICK:
624 { 635 {
625 ipc_event_tick(buf); 636 ipc_event_tick(buf);
626 ipc_send_reply(client, "{\"success\": true}", 17); 637 ipc_send_reply(client, payload_type, "{\"success\": true}", 17);
627 goto exit_cleanup; 638 goto exit_cleanup;
628 } 639 }
629 640
@@ -656,8 +667,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
656 } 667 }
657 } 668 }
658 const char *json_string = json_object_to_json_string(outputs); 669 const char *json_string = json_object_to_json_string(outputs);
659 client_valid = 670 ipc_send_reply(client, payload_type, json_string,
660 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 671 (uint32_t)strlen(json_string));
661 json_object_put(outputs); // free 672 json_object_put(outputs); // free
662 goto exit_cleanup; 673 goto exit_cleanup;
663 } 674 }
@@ -667,8 +678,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
667 json_object *workspaces = json_object_new_array(); 678 json_object *workspaces = json_object_new_array();
668 root_for_each_workspace(ipc_get_workspaces_callback, workspaces); 679 root_for_each_workspace(ipc_get_workspaces_callback, workspaces);
669 const char *json_string = json_object_to_json_string(workspaces); 680 const char *json_string = json_object_to_json_string(workspaces);
670 client_valid = 681 ipc_send_reply(client, payload_type, json_string,
671 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 682 (uint32_t)strlen(json_string));
672 json_object_put(workspaces); // free 683 json_object_put(workspaces); // free
673 goto exit_cleanup; 684 goto exit_cleanup;
674 } 685 }
@@ -679,7 +690,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
679 struct json_object *request = json_tokener_parse(buf); 690 struct json_object *request = json_tokener_parse(buf);
680 if (request == NULL || !json_object_is_type(request, json_type_array)) { 691 if (request == NULL || !json_object_is_type(request, json_type_array)) {
681 const char msg[] = "{\"success\": false}"; 692 const char msg[] = "{\"success\": false}";
682 client_valid = ipc_send_reply(client, msg, strlen(msg)); 693 ipc_send_reply(client, payload_type, msg, strlen(msg));
683 sway_log(SWAY_INFO, "Failed to parse subscribe request"); 694 sway_log(SWAY_INFO, "Failed to parse subscribe request");
684 goto exit_cleanup; 695 goto exit_cleanup;
685 } 696 }
@@ -707,7 +718,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
707 is_tick = true; 718 is_tick = true;
708 } else { 719 } else {
709 const char msg[] = "{\"success\": false}"; 720 const char msg[] = "{\"success\": false}";
710 client_valid = ipc_send_reply(client, msg, strlen(msg)); 721 ipc_send_reply(client, payload_type, msg, strlen(msg));
711 json_object_put(request); 722 json_object_put(request);
712 sway_log(SWAY_INFO, "Unsupported event type in subscribe request"); 723 sway_log(SWAY_INFO, "Unsupported event type in subscribe request");
713 goto exit_cleanup; 724 goto exit_cleanup;
@@ -716,11 +727,11 @@ void ipc_client_handle_command(struct ipc_client *client) {
716 727
717 json_object_put(request); 728 json_object_put(request);
718 const char msg[] = "{\"success\": true}"; 729 const char msg[] = "{\"success\": true}";
719 client_valid = ipc_send_reply(client, msg, strlen(msg)); 730 ipc_send_reply(client, payload_type, msg, strlen(msg));
720 if (is_tick) { 731 if (is_tick) {
721 client->current_command = IPC_EVENT_TICK;
722 const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}"; 732 const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}";
723 ipc_send_reply(client, tickmsg, strlen(tickmsg)); 733 ipc_send_reply(client, IPC_EVENT_TICK, tickmsg,
734 strlen(tickmsg));
724 } 735 }
725 goto exit_cleanup; 736 goto exit_cleanup;
726 } 737 }
@@ -733,8 +744,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
733 json_object_array_add(inputs, ipc_json_describe_input(device)); 744 json_object_array_add(inputs, ipc_json_describe_input(device));
734 } 745 }
735 const char *json_string = json_object_to_json_string(inputs); 746 const char *json_string = json_object_to_json_string(inputs);
736 client_valid = 747 ipc_send_reply(client, payload_type, json_string,
737 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 748 (uint32_t)strlen(json_string));
738 json_object_put(inputs); // free 749 json_object_put(inputs); // free
739 goto exit_cleanup; 750 goto exit_cleanup;
740 } 751 }
@@ -747,8 +758,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
747 json_object_array_add(seats, ipc_json_describe_seat(seat)); 758 json_object_array_add(seats, ipc_json_describe_seat(seat));
748 } 759 }
749 const char *json_string = json_object_to_json_string(seats); 760 const char *json_string = json_object_to_json_string(seats);
750 client_valid = 761 ipc_send_reply(client, payload_type, json_string,
751 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 762 (uint32_t)strlen(json_string));
752 json_object_put(seats); // free 763 json_object_put(seats); // free
753 goto exit_cleanup; 764 goto exit_cleanup;
754 } 765 }
@@ -757,8 +768,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
757 { 768 {
758 json_object *tree = ipc_json_describe_node_recursive(&root->node); 769 json_object *tree = ipc_json_describe_node_recursive(&root->node);
759 const char *json_string = json_object_to_json_string(tree); 770 const char *json_string = json_object_to_json_string(tree);
760 client_valid = 771 ipc_send_reply(client, payload_type, json_string,
761 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); 772 (uint32_t)strlen(json_string));
762 json_object_put(tree); 773 json_object_put(tree);
763 goto exit_cleanup; 774 goto exit_cleanup;
764 } 775 }
@@ -768,8 +779,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
768 json_object *marks = json_object_new_array(); 779 json_object *marks = json_object_new_array();
769 root_for_each_container(ipc_get_marks_callback, marks); 780 root_for_each_container(ipc_get_marks_callback, marks);
770 const char *json_string = json_object_to_json_string(marks); 781 const char *json_string = json_object_to_json_string(marks);
771 client_valid = 782 ipc_send_reply(client, payload_type, json_string,
772 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 783 (uint32_t)strlen(json_string));
773 json_object_put(marks); 784 json_object_put(marks);
774 goto exit_cleanup; 785 goto exit_cleanup;
775 } 786 }
@@ -778,8 +789,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
778 { 789 {
779 json_object *version = ipc_json_get_version(); 790 json_object *version = ipc_json_get_version();
780 const char *json_string = json_object_to_json_string(version); 791 const char *json_string = json_object_to_json_string(version);
781 client_valid = 792 ipc_send_reply(client, payload_type, json_string,
782 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 793 (uint32_t)strlen(json_string));
783 json_object_put(version); // free 794 json_object_put(version); // free
784 goto exit_cleanup; 795 goto exit_cleanup;
785 } 796 }
@@ -794,9 +805,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
794 json_object_array_add(bars, json_object_new_string(bar->id)); 805 json_object_array_add(bars, json_object_new_string(bar->id));
795 } 806 }
796 const char *json_string = json_object_to_json_string(bars); 807 const char *json_string = json_object_to_json_string(bars);
797 client_valid = 808 ipc_send_reply(client, payload_type, json_string,
798 ipc_send_reply(client, json_string, 809 (uint32_t)strlen(json_string));
799 (uint32_t)strlen(json_string));
800 json_object_put(bars); // free 810 json_object_put(bars); // free
801 } else { 811 } else {
802 // Send particular bar's details 812 // Send particular bar's details
@@ -810,15 +820,14 @@ void ipc_client_handle_command(struct ipc_client *client) {
810 } 820 }
811 if (!bar) { 821 if (!bar) {
812 const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }"; 822 const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }";
813 client_valid = 823 ipc_send_reply(client, payload_type, error,
814 ipc_send_reply(client, error, (uint32_t)strlen(error)); 824 (uint32_t)strlen(error));
815 goto exit_cleanup; 825 goto exit_cleanup;
816 } 826 }
817 json_object *json = ipc_json_describe_bar_config(bar); 827 json_object *json = ipc_json_describe_bar_config(bar);
818 const char *json_string = json_object_to_json_string(json); 828 const char *json_string = json_object_to_json_string(json);
819 client_valid = 829 ipc_send_reply(client, payload_type, json_string,
820 ipc_send_reply(client, json_string, 830 (uint32_t)strlen(json_string));
821 (uint32_t)strlen(json_string));
822 json_object_put(json); // free 831 json_object_put(json); // free
823 } 832 }
824 goto exit_cleanup; 833 goto exit_cleanup;
@@ -832,8 +841,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
832 json_object_array_add(modes, json_object_new_string(mode->name)); 841 json_object_array_add(modes, json_object_new_string(mode->name));
833 } 842 }
834 const char *json_string = json_object_to_json_string(modes); 843 const char *json_string = json_object_to_json_string(modes);
835 client_valid = 844 ipc_send_reply(client, payload_type, json_string,
836 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 845 (uint32_t)strlen(json_string));
837 json_object_put(modes); // free 846 json_object_put(modes); // free
838 goto exit_cleanup; 847 goto exit_cleanup;
839 } 848 }
@@ -843,34 +852,32 @@ void ipc_client_handle_command(struct ipc_client *client) {
843 json_object *json = json_object_new_object(); 852 json_object *json = json_object_new_object();
844 json_object_object_add(json, "config", json_object_new_string(config->current_config)); 853 json_object_object_add(json, "config", json_object_new_string(config->current_config));
845 const char *json_string = json_object_to_json_string(json); 854 const char *json_string = json_object_to_json_string(json);
846 client_valid = 855 ipc_send_reply(client, payload_type, json_string,
847 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 856 (uint32_t)strlen(json_string));
848 json_object_put(json); // free 857 json_object_put(json); // free
849 goto exit_cleanup; 858 goto exit_cleanup;
850 } 859 }
851 860
852 case IPC_SYNC: 861 case IPC_SYNC:
853 { 862 {
854 // It was decided sway will not support this, just return success:false 863 // It was decided sway will not support this, just return success:false
855 const char msg[] = "{\"success\": false}"; 864 const char msg[] = "{\"success\": false}";
856 ipc_send_reply(client, msg, strlen(msg)); 865 ipc_send_reply(client, payload_type, msg, strlen(msg));
857 goto exit_cleanup; 866 goto exit_cleanup;
858 } 867 }
859 868
860 default: 869 default:
861 sway_log(SWAY_INFO, "Unknown IPC command type %i", client->current_command); 870 sway_log(SWAY_INFO, "Unknown IPC command type %x", payload_type);
862 goto exit_cleanup; 871 goto exit_cleanup;
863 } 872 }
864 873
865exit_cleanup: 874exit_cleanup:
866 if (client_valid) {
867 client->payload_length = 0;
868 }
869 free(buf); 875 free(buf);
870 return; 876 return;
871} 877}
872 878
873bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length) { 879bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_type,
880 const char *payload, uint32_t payload_length) {
874 assert(payload); 881 assert(payload);
875 882
876 char data[IPC_HEADER_SIZE]; 883 char data[IPC_HEADER_SIZE];
@@ -878,7 +885,7 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
878 885
879 memcpy(data, ipc_magic, sizeof(ipc_magic)); 886 memcpy(data, ipc_magic, sizeof(ipc_magic));
880 memcpy(&data32[0], &payload_length, sizeof(payload_length)); 887 memcpy(&data32[0], &payload_length, sizeof(payload_length));
881 memcpy(&data32[1], &client->current_command, sizeof(client->current_command)); 888 memcpy(&data32[1], &payload_type, sizeof(payload_type));
882 889
883 while (client->write_buffer_len + IPC_HEADER_SIZE + payload_length >= 890 while (client->write_buffer_len + IPC_HEADER_SIZE + payload_length >=
884 client->write_buffer_size) { 891 client->write_buffer_size) {
@@ -910,6 +917,7 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
910 ipc_client_handle_writable, client); 917 ipc_client_handle_writable, client);
911 } 918 }
912 919
913 sway_log(SWAY_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); 920 sway_log(SWAY_DEBUG, "Added IPC reply of type 0x%x to client %d queue: %s",
921 payload_type, client->fd, payload);
914 return true; 922 return true;
915} 923}