/src/librabbitmq/fuzz/fuzz_server.c
Line | Count | Source |
1 | | // Copyright 2007 - 2022, Alan Antonuk and the rabbitmq-c contributors. |
2 | | // SPDX-License-Identifier: mit |
3 | | |
4 | | #include <stdint.h> |
5 | | #include <stdlib.h> |
6 | | #include <string.h> |
7 | | |
8 | | #include <rabbitmq-c/amqp.h> |
9 | | #include <rabbitmq-c/framing.h> |
10 | | |
11 | | #include "amqp_private.h" |
12 | | #include "amqp_socket.h" |
13 | | |
14 | | // In-memory socket: feeds the fuzz buffer to the client as the bytes a broker |
15 | | // would send, with no real socket or thread, so amqp_login() drives the full |
16 | | // client handshake (Connection.Start -> Tune -> Open -> OpenOk) from the input. |
17 | | |
18 | | struct fuzz_socket_t { |
19 | | const struct amqp_socket_class_t *klass; |
20 | | const uint8_t *data; |
21 | | size_t size; |
22 | | size_t offset; |
23 | | }; |
24 | | |
25 | | static ssize_t fuzz_socket_send(AMQP_UNUSED void *base, |
26 | | AMQP_UNUSED const void *buf, size_t len, |
27 | 44 | AMQP_UNUSED int flags) { |
28 | 44 | return (ssize_t)len; |
29 | 44 | } |
30 | | |
31 | | static ssize_t fuzz_socket_recv(void *base, void *buf, size_t len, |
32 | 49 | AMQP_UNUSED int flags) { |
33 | 49 | struct fuzz_socket_t *self = (struct fuzz_socket_t *)base; |
34 | 49 | size_t remaining = self->size - self->offset; |
35 | 49 | size_t n; |
36 | | |
37 | 49 | if (remaining == 0) { |
38 | 5 | return AMQP_STATUS_CONNECTION_CLOSED; |
39 | 5 | } |
40 | 44 | n = remaining < len ? remaining : len; |
41 | 44 | memcpy(buf, self->data + self->offset, n); |
42 | 44 | self->offset += n; |
43 | 44 | return (ssize_t)n; |
44 | 49 | } |
45 | | |
46 | | static int fuzz_socket_open(AMQP_UNUSED void *base, AMQP_UNUSED const char *host, |
47 | | AMQP_UNUSED int port, |
48 | 0 | AMQP_UNUSED const struct timeval *timeout) { |
49 | 0 | return AMQP_STATUS_OK; |
50 | 0 | } |
51 | | |
52 | | static int fuzz_socket_close(AMQP_UNUSED void *base, |
53 | 44 | AMQP_UNUSED amqp_socket_close_enum force) { |
54 | 44 | return AMQP_STATUS_OK; |
55 | 44 | } |
56 | | |
57 | 5 | static int fuzz_socket_get_sockfd(AMQP_UNUSED void *base) { |
58 | 5 | return 0; /* must be >= 0; -1 is treated as a closed connection */ |
59 | 5 | } |
60 | | |
61 | 44 | static void fuzz_socket_delete(void *base) { free(base); } |
62 | | |
63 | | static const struct amqp_socket_class_t fuzz_socket_class = { |
64 | | fuzz_socket_send, fuzz_socket_recv, fuzz_socket_open, |
65 | | fuzz_socket_close, fuzz_socket_get_sockfd, fuzz_socket_delete}; |
66 | | |
67 | 44 | extern int LLVMFuzzerTestOneInput(const char *data, size_t size) { |
68 | 44 | amqp_connection_state_t conn; |
69 | 44 | struct fuzz_socket_t *sock; |
70 | | |
71 | 44 | if (size == 0) { |
72 | 0 | return 0; |
73 | 0 | } |
74 | | |
75 | 44 | conn = amqp_new_connection(); |
76 | 44 | if (conn == NULL) { |
77 | 0 | return 0; |
78 | 0 | } |
79 | | |
80 | 44 | sock = (struct fuzz_socket_t *)calloc(1, sizeof(*sock)); |
81 | 44 | if (sock == NULL) { |
82 | 0 | amqp_destroy_connection(conn); |
83 | 0 | return 0; |
84 | 0 | } |
85 | 44 | sock->klass = &fuzz_socket_class; |
86 | 44 | sock->data = (const uint8_t *)data; |
87 | 44 | sock->size = size; |
88 | | |
89 | | // Takes ownership; amqp_destroy_connection frees it via fuzz_socket_delete. |
90 | 44 | amqp_set_socket(conn, (amqp_socket_t *)sock); |
91 | | |
92 | 44 | amqp_login(conn, "/", 0, AMQP_DEFAULT_FRAME_SIZE, 0, AMQP_SASL_METHOD_PLAIN, |
93 | 44 | "guest", "guest"); |
94 | | |
95 | 44 | amqp_destroy_connection(conn); |
96 | 44 | return 0; |
97 | 44 | } |