Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <unistd.h>
4 : :
5 : : #include "errno-util.h"
6 : : #include "fd-util.h"
7 : : #include "fuzz.h"
8 : : #include "hexdecoct.h"
9 : : #include "io-util.h"
10 : : #include "varlink.h"
11 : : #include "log.h"
12 : :
13 : : static FILE *null = NULL;
14 : :
15 : 0 : static int method_something(Varlink *v, JsonVariant *p, VarlinkMethodFlags flags, void *userdata) {
16 : 0 : json_variant_dump(p, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, null, NULL);
17 : 0 : return 0;
18 : : }
19 : :
20 : 0 : static int reply_callback(Varlink *v, JsonVariant *p, const char *error_id, VarlinkReplyFlags flags, void *userdata) {
21 : 0 : json_variant_dump(p, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, null, NULL);
22 : 0 : return 0;
23 : : }
24 : :
25 : 0 : static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
26 : 0 : struct iovec *iov = userdata;
27 : 0 : bool write_eof = false, read_eof = false;
28 : :
29 [ # # ]: 0 : assert(s);
30 [ # # ]: 0 : assert(fd >= 0);
31 [ # # ]: 0 : assert(iov);
32 : :
33 [ # # # # ]: 0 : if ((revents & (EPOLLOUT|EPOLLHUP|EPOLLERR)) && iov->iov_len > 0) {
34 : : ssize_t n;
35 : :
36 : : /* never write more than 143 bytes a time, to make broken up recv()s on the other side more
37 : : * likely, and thus test some additional code paths. */
38 : 0 : n = send(fd, iov->iov_base, MIN(iov->iov_len, 143U), MSG_NOSIGNAL|MSG_DONTWAIT);
39 [ # # ]: 0 : if (n < 0) {
40 [ # # ]: 0 : if (ERRNO_IS_DISCONNECT(errno))
41 : 0 : write_eof = true;
42 : : else
43 [ # # ]: 0 : assert_se(errno == EAGAIN);
44 : : } else
45 : 0 : IOVEC_INCREMENT(iov, 1, n);
46 : : }
47 : :
48 [ # # ]: 0 : if (revents & EPOLLIN) {
49 : : char c[137];
50 : : ssize_t n;
51 : :
52 : 0 : n = recv(fd, c, sizeof(c), MSG_DONTWAIT);
53 [ # # ]: 0 : if (n < 0) {
54 [ # # ]: 0 : if (ERRNO_IS_DISCONNECT(errno))
55 : 0 : read_eof = true;
56 : : else
57 [ # # ]: 0 : assert_se(errno == EAGAIN);
58 [ # # ]: 0 : } else if (n == 0)
59 : 0 : read_eof = true;
60 : : else
61 : 0 : hexdump(null, c, (size_t) n);
62 : : }
63 : :
64 : : /* After we wrote everything we could turn off EPOLLOUT. And if we reached read EOF too turn off the
65 : : * whole thing. */
66 [ # # # # ]: 0 : if (write_eof || iov->iov_len == 0) {
67 : :
68 [ # # ]: 0 : if (read_eof)
69 [ # # ]: 0 : assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
70 : : else
71 [ # # ]: 0 : assert_se(sd_event_source_set_io_events(s, EPOLLIN) >= 0);
72 : : }
73 : :
74 : 0 : return 0;
75 : : }
76 : :
77 : 0 : static int idle_callback(sd_event_source *s, void *userdata) {
78 [ # # ]: 0 : assert(s);
79 : :
80 : : /* Called as idle callback when there's nothing else to do anymore */
81 : 0 : sd_event_exit(sd_event_source_get_event(s), 0);
82 : 0 : return 0;
83 : : }
84 : :
85 : 0 : int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
86 : 0 : struct iovec server_iov = IOVEC_MAKE((void*) data, size), client_iov = IOVEC_MAKE((void*) data, size);
87 : : /* Important: the declaration order matters here! we want that the fds are closed on return after the
88 : : * event sources, hence we declare the fds first, the event sources second */
89 : 0 : _cleanup_close_pair_ int server_pair[2] = { -1, -1 }, client_pair[2] = { -1, -1 };
90 : 0 : _cleanup_(sd_event_source_unrefp) sd_event_source *idle_event_source = NULL,
91 : 0 : *server_event_source = NULL, *client_event_source = NULL;
92 : 0 : _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
93 : 0 : _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
94 : 0 : _cleanup_(sd_event_unrefp) sd_event *e = NULL;
95 : :
96 : 0 : log_set_max_level(LOG_CRIT);
97 : 0 : log_parse_environment();
98 : :
99 [ # # ]: 0 : assert_se(null = fopen("/dev/null", "we"));
100 : :
101 [ # # ]: 0 : assert_se(sd_event_default(&e) >= 0);
102 : :
103 : : /* Test one: write the data as method call to a server */
104 [ # # ]: 0 : assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, server_pair) >= 0);
105 [ # # ]: 0 : assert_se(varlink_server_new(&s, 0) >= 0);
106 [ # # ]: 0 : assert_se(varlink_server_set_description(s, "myserver") >= 0);
107 [ # # ]: 0 : assert_se(varlink_server_attach_event(s, e, 0) >= 0);
108 [ # # ]: 0 : assert_se(varlink_server_add_connection(s, server_pair[0], NULL) >= 0);
109 : 0 : TAKE_FD(server_pair[0]);
110 [ # # ]: 0 : assert_se(varlink_server_bind_method(s, "io.test.DoSomething", method_something) >= 0);
111 [ # # ]: 0 : assert_se(sd_event_add_io(e, &server_event_source, server_pair[1], EPOLLIN|EPOLLOUT, io_callback, &server_iov) >= 0);
112 : :
113 : : /* Test two: write the data as method response to a client */
114 [ # # ]: 0 : assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, client_pair) >= 0);
115 [ # # ]: 0 : assert_se(varlink_connect_fd(&c, client_pair[0]) >= 0);
116 : 0 : TAKE_FD(client_pair[0]);
117 [ # # ]: 0 : assert_se(varlink_set_description(c, "myclient") >= 0);
118 [ # # ]: 0 : assert_se(varlink_attach_event(c, e, 0) >= 0);
119 [ # # ]: 0 : assert_se(varlink_bind_reply(c, reply_callback) >= 0);
120 [ # # ]: 0 : assert_se(varlink_invoke(c, "io.test.DoSomething", NULL) >= 0);
121 [ # # ]: 0 : assert_se(sd_event_add_io(e, &client_event_source, client_pair[1], EPOLLIN|EPOLLOUT, io_callback, &client_iov) >= 0);
122 : :
123 [ # # ]: 0 : assert_se(sd_event_add_defer(e, &idle_event_source, idle_callback, NULL) >= 0);
124 [ # # ]: 0 : assert_se(sd_event_source_set_priority(idle_event_source, SD_EVENT_PRIORITY_IDLE) >= 0);
125 : :
126 [ # # ]: 0 : assert_se(sd_event_loop(e) >= 0);
127 : :
128 : 0 : null = safe_fclose(null);
129 : :
130 : 0 : return 0;
131 : : }
|