tests: add request_bogus_size
This attempts to reproduce the error conditions from
https://gitlab.freedesktop.org/wayland/wayland/issues/52 and make it crash.
While the crash was repeatable in my tests, it depends on garbage on stack
leading to access of invalid memory, which is not guaranteed.
This is a FAIL_TEST, so that the following fix commit can be verified.
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Reviewed-by: Simon Ser <contact@emersion.fr>
Pekka Paalanen
5 years ago
751 | 751 | |
752 | 752 | display_destroy(d); |
753 | 753 | } |
754 | ||
755 | /** Raw read from socket expecting wl_display.error | |
756 | * | |
757 | * \param sockfd The socket to read from. | |
758 | * \param expected_error The expected wl_display error code. | |
759 | * | |
760 | * Reads the socket and manually parses one message, expecting it to be a | |
761 | * wl_display.error with the wl_display as the originating object. | |
762 | * Asserts that the received error code is expected_error. | |
763 | */ | |
764 | static void | |
765 | expect_error_recv(int sockfd, uint32_t expected_error) | |
766 | { | |
767 | uint32_t buf[1024]; | |
768 | ssize_t slen; | |
769 | uint32_t opcode; | |
770 | int str_len; | |
771 | ||
772 | slen = recv(sockfd, buf, sizeof buf, 0); | |
773 | assert(slen >= 2 * (ssize_t)sizeof (uint32_t)); | |
774 | opcode = buf[1] & 0xffff; | |
775 | fprintf(stderr, "Received %zd bytes, object %u, opcode %u\n", | |
776 | slen, buf[0], opcode); | |
777 | ||
778 | /* check error event */ | |
779 | assert(buf[0] == 1); | |
780 | assert(opcode == WL_DISPLAY_ERROR); | |
781 | ||
782 | str_len = buf[4]; | |
783 | assert(str_len > 0); | |
784 | assert(str_len <= slen - 5 * (ssize_t)sizeof (uint32_t)); | |
785 | fprintf(stderr, "Error event on object %u, code %u, message \"%*s\"\n", | |
786 | buf[2], buf[3], str_len, (const char *)&buf[5]); | |
787 | ||
788 | assert(buf[3] == expected_error); | |
789 | } | |
790 | ||
791 | /* A test for https://gitlab.freedesktop.org/wayland/wayland/issues/52 | |
792 | * trying to provoke a read from uninitialized memory in | |
793 | * wl_connection_demarshal() for sender_id and opcode. | |
794 | * | |
795 | * This test might not fail as is even with #52 unfixed, since there is no way | |
796 | * to detect what happens and the crash with zero size depends on stack content. | |
797 | * However, running under Valgrind would point out invalid reads and use of | |
798 | * uninitialized values. | |
799 | */ | |
800 | FAIL_TEST(request_bogus_size) | |
801 | { | |
802 | struct wl_display *display; | |
803 | struct wl_client *client; | |
804 | int s[2]; | |
805 | uint32_t msg[3]; | |
806 | int bogus_size; | |
807 | ||
808 | test_set_timeout(1); | |
809 | ||
810 | /* | |
811 | * The manufactured message has real size 12. Test all bogus sizes | |
812 | * smaller than that, and zero as the last one since wl_closure_init | |
813 | * handles zero specially and having garbage in the stack makes it more | |
814 | * likely to crash in wl_connection_demarshal. | |
815 | */ | |
816 | for (bogus_size = 11; bogus_size >= 0; bogus_size--) { | |
817 | fprintf(stderr, "* bogus size %d\n", bogus_size); | |
818 | ||
819 | assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); | |
820 | display = wl_display_create(); | |
821 | assert(display); | |
822 | client = wl_client_create(display, s[0]); | |
823 | assert(client); | |
824 | ||
825 | /* manufacture a request that lies about its size */ | |
826 | msg[0] = 1; /* sender id: wl_display */ | |
827 | msg[1] = (bogus_size << 16) | WL_DISPLAY_SYNC; /* size and opcode */ | |
828 | msg[2] = 2; /* sync argument: new_id for wl_callback */ | |
829 | ||
830 | assert(send(s[1], msg, sizeof msg, 0) == sizeof msg); | |
831 | ||
832 | wl_event_loop_dispatch(wl_display_get_event_loop(display), 0); | |
833 | ||
834 | expect_error_recv(s[1], WL_DISPLAY_ERROR_INVALID_METHOD); | |
835 | ||
836 | /* Do not wl_client_destroy, the error already caused it. */ | |
837 | close(s[1]); | |
838 | wl_display_destroy(display); | |
839 | } | |
840 | } |