1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 
method_something(Varlink * v,JsonVariant * p,VarlinkMethodFlags flags,void * userdata)15 static int method_something(Varlink *v, JsonVariant *p, VarlinkMethodFlags flags, void *userdata) {
16         json_variant_dump(p, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, null, NULL);
17         return 0;
18 }
19 
reply_callback(Varlink * v,JsonVariant * p,const char * error_id,VarlinkReplyFlags flags,void * userdata)20 static int reply_callback(Varlink *v, JsonVariant *p, const char *error_id, VarlinkReplyFlags flags, void *userdata) {
21         json_variant_dump(p, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, null, NULL);
22         return 0;
23 }
24 
io_callback(sd_event_source * s,int fd,uint32_t revents,void * userdata)25 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
26         struct iovec *iov = userdata;
27         bool write_eof = false, read_eof = false;
28 
29         assert(s);
30         assert(fd >= 0);
31         assert(iov);
32 
33         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                 n = send(fd, iov->iov_base, MIN(iov->iov_len, 143U), MSG_NOSIGNAL|MSG_DONTWAIT);
39                 if (n < 0) {
40                         if (ERRNO_IS_DISCONNECT(errno))
41                                 write_eof = true;
42                         else
43                                 assert_se(errno == EAGAIN);
44                 } else
45                         IOVEC_INCREMENT(iov, 1, n);
46         }
47 
48         if (revents & EPOLLIN) {
49                 char c[137];
50                 ssize_t n;
51 
52                 n = recv(fd, c, sizeof(c), MSG_DONTWAIT);
53                 if (n < 0) {
54                         if (ERRNO_IS_DISCONNECT(errno))
55                                 read_eof = true;
56                         else
57                                 assert_se(errno == EAGAIN);
58                 } else if (n == 0)
59                         read_eof = true;
60                 else
61                         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         if (write_eof || iov->iov_len == 0) {
67 
68                 if (read_eof)
69                         assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
70                 else
71                         assert_se(sd_event_source_set_io_events(s, EPOLLIN) >= 0);
72         }
73 
74         return 0;
75 }
76 
idle_callback(sd_event_source * s,void * userdata)77 static int idle_callback(sd_event_source *s, void *userdata) {
78         assert(s);
79 
80         /* Called as idle callback when there's nothing else to do anymore */
81         sd_event_exit(sd_event_source_get_event(s), 0);
82         return 0;
83 }
84 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)85 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
86         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         _cleanup_close_pair_ int server_pair[2] = { -1, -1 }, client_pair[2] = { -1, -1 };
90         _cleanup_(sd_event_source_unrefp) sd_event_source *idle_event_source = NULL,
91                 *server_event_source = NULL, *client_event_source = NULL;
92         _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
93         _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
94         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
95 
96         log_set_max_level(LOG_CRIT);
97         log_parse_environment();
98 
99         assert_se(null = fopen("/dev/null", "we"));
100 
101         assert_se(sd_event_default(&e) >= 0);
102 
103         /* Test one: write the data as method call to a server */
104         assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, server_pair) >= 0);
105         assert_se(varlink_server_new(&s, 0) >= 0);
106         assert_se(varlink_server_set_description(s, "myserver") >= 0);
107         assert_se(varlink_server_attach_event(s, e, 0) >= 0);
108         assert_se(varlink_server_add_connection(s, server_pair[0], NULL) >= 0);
109         TAKE_FD(server_pair[0]);
110         assert_se(varlink_server_bind_method(s, "io.test.DoSomething", method_something) >= 0);
111         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         assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, client_pair) >= 0);
115         assert_se(varlink_connect_fd(&c, client_pair[0]) >= 0);
116         TAKE_FD(client_pair[0]);
117         assert_se(varlink_set_description(c, "myclient") >= 0);
118         assert_se(varlink_attach_event(c, e, 0) >= 0);
119         assert_se(varlink_bind_reply(c, reply_callback) >= 0);
120         assert_se(varlink_invoke(c, "io.test.DoSomething", NULL) >= 0);
121         assert_se(sd_event_add_io(e, &client_event_source, client_pair[1], EPOLLIN|EPOLLOUT, io_callback, &client_iov) >= 0);
122 
123         assert_se(sd_event_add_defer(e, &idle_event_source, idle_callback, NULL) >= 0);
124         assert_se(sd_event_source_set_priority(idle_event_source, SD_EVENT_PRIORITY_IDLE) >= 0);
125 
126         assert_se(sd_event_loop(e) >= 0);
127 
128         null = safe_fclose(null);
129 
130         return 0;
131 }
132