1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2017, Intel Corporation
4  * All rights reserved.
5  */
6 #include <glib.h>
7 
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <inttypes.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/select.h>
16 #include <unistd.h>
17 
18 #include <setjmp.h>
19 #include <cmocka.h>
20 
21 #include "connection-manager.h"
22 #include "sink-interface.h"
23 #include "source-interface.h"
24 #include "command-attrs.h"
25 #include "command-source.h"
26 #include "tabrmd-defaults.h"
27 #include "tpm2-command.h"
28 #include "util.h"
29 
30 typedef struct source_test_data {
31     ConnectionManager *manager;
32     CommandAttrs   *command_attrs;
33     CommandSource *source;
34     Connection *connection;
35     gboolean match;
36 } source_test_data_t;
37 
38 
39 /* mock function to return TPM command attributes TPMA_CC */
40 TPMA_CC
__wrap_command_attrs_from_cc(CommandAttrs * attrs,TPM2_CC command_code)41 __wrap_command_attrs_from_cc (CommandAttrs *attrs,
42                               TPM2_CC        command_code)
43 {
44     UNUSED_PARAM(attrs);
45     UNUSED_PARAM(command_code);
46     return (TPMA_CC)mock_type (UINT32);
47 }
48 Connection*
__wrap_connection_manager_lookup_istream(ConnectionManager * manager,GInputStream * istream)49 __wrap_connection_manager_lookup_istream (ConnectionManager *manager,
50                                           GInputStream      *istream)
51 {
52     UNUSED_PARAM(manager);
53     UNUSED_PARAM(istream);
54     g_debug ("%s", __func__);
55     return CONNECTION (mock_ptr_type (GObject*));
56 }
57 gint
__wrap_connection_manager_remove(ConnectionManager * manager,Connection * connection)58 __wrap_connection_manager_remove      (ConnectionManager  *manager,
59                                        Connection         *connection)
60 {
61     UNUSED_PARAM(manager);
62     UNUSED_PARAM(connection);
63     return mock_type (int);
64 }
65 uint8_t*
__wrap_read_tpm_buffer_alloc(GSocket * socket,size_t * buf_size)66 __wrap_read_tpm_buffer_alloc (GSocket   *socket,
67                               size_t    *buf_size)
68 {
69     uint8_t *buf_src = mock_type (uint8_t*);
70     uint8_t *buf_dst = NULL;
71     size_t   size = mock_type (size_t);
72     UNUSED_PARAM(socket);
73 
74     g_debug ("%s", __func__);
75     buf_dst = g_malloc0 (size);
76     memcpy (buf_dst, buf_src, size);
77     *buf_size = size;
78 
79     return buf_dst;
80 }
81 void
__wrap_sink_enqueue(Sink * sink,GObject * obj)82 __wrap_sink_enqueue (Sink     *sink,
83                      GObject  *obj)
84 {
85     GObject **object;
86     UNUSED_PARAM(sink);
87 
88     g_debug ("%s", __func__);
89     object = mock_ptr_type (GObject**);
90 
91     *object = G_OBJECT (obj);
92     g_object_ref (*object);
93 }
94 /*
95  * This wrap function allows us to gain access to the data that will be
96  * passed to the source callback registered by the CommandSource object when
97  * a new Connection is added. Without this callback it's not possible to get
98  * access to the source_data_t structure created by the CommandSource insert
99  * function which is required for us to simulate the callback function.
100  */
101 void
__wrap_g_source_set_callback(GSource * source,GSourceFunc func,gpointer data,GDestroyNotify notify)102 __wrap_g_source_set_callback (GSource *source,
103                               GSourceFunc func,
104                               gpointer data,
105                               GDestroyNotify notify)
106 {
107     source_data_t *source_data = (source_data_t*)data;
108     source_data_t **source_data_param = mock_type (source_data_t**);
109     UNUSED_PARAM(source);
110     UNUSED_PARAM(func);
111     UNUSED_PARAM(notify);
112 
113     *source_data_param = source_data;
114 }
115 /* command_source_allocate_test begin
116  * Test to allocate and destroy a CommandSource.
117  */
118 static void
command_source_allocate_test(void ** state)119 command_source_allocate_test (void **state)
120 {
121     source_test_data_t *data = (source_test_data_t *)*state;
122 
123     data->command_attrs = command_attrs_new ();
124     data->source = command_source_new (data->manager,
125                                        data->command_attrs);
126     assert_non_null (data->source);
127 }
128 
129 static int
command_source_allocate_setup(void ** state)130 command_source_allocate_setup (void **state)
131 {
132     source_test_data_t *data;
133 
134     data = calloc (1, sizeof (source_test_data_t));
135     data->manager = connection_manager_new (TABRMD_CONNECTIONS_MAX_DEFAULT);
136 
137     *state = data;
138     return 0;
139 }
140 /* command_source_allocate end */
141 
142 /* command_source_start_test
143  * This is a basic usage flow test. Can it be started, canceled and joined.
144  * We're testing the underlying pthread usage ... mostly.
145  */
146 void
command_source_start_test(void ** state)147 command_source_start_test (void **state)
148 {
149     source_test_data_t *data;
150     gint ret;
151 
152     data = (source_test_data_t*)*state;
153     thread_start(THREAD (data->source));
154     sleep (1);
155     thread_cancel (THREAD (data->source));
156     ret = thread_join (THREAD (data->source));
157     assert_int_equal (ret, 0);
158 }
159 
160 static int
command_source_start_setup(void ** state)161 command_source_start_setup (void **state)
162 {
163     source_test_data_t *data;
164 
165     data = calloc (1, sizeof (source_test_data_t));
166     data->manager = connection_manager_new (TABRMD_CONNECTIONS_MAX_DEFAULT);
167     if (data->manager == NULL)
168         g_error ("failed to allocate new connection_manager");
169     data->command_attrs = command_attrs_new ();
170     data->source = command_source_new (data->manager,
171                                        data->command_attrs);
172     if (data->source == NULL)
173         g_error ("failed to allocate new command_source");
174 
175     *state = data;
176     return 0;
177 }
178 
179 static int
command_source_teardown(void ** state)180 command_source_teardown (void **state)
181 {
182     source_test_data_t *data = (source_test_data_t*)*state;
183 
184     g_clear_object (&data->source);
185     g_clear_object (&data->manager);
186     g_clear_object (&data->command_attrs);
187     g_clear_pointer (&data, g_free);
188     return 0;
189 }
190 /* command_source_start_test end */
191 
192 /* command_source_connection_insert_test begin
193  * In this test we create a connection source and all that that entails. We then
194  * create a new connection and insert it into the connection manager. We then signal
195  * to the source that there's a new connection in the manager by sending data to
196  * it over the send end of the wakeup pipe "wakeup_send_fd". We then check the
197  * receive_fdset in the source structure to be sure the receive end of the
198  * connection pipe is set. This is how we know that the source is now watching
199  * for data from the new connection.
200  */
201 static int
command_source_connection_setup(void ** state)202 command_source_connection_setup (void **state)
203 {
204     source_test_data_t *data;
205 
206     g_debug ("%s", __func__);
207     data = calloc (1, sizeof (source_test_data_t));
208     data->manager = connection_manager_new (TABRMD_CONNECTIONS_MAX_DEFAULT);
209     data->command_attrs = command_attrs_new ();
210     data->source = command_source_new (data->manager,
211                                        data->command_attrs);
212 
213     *state = data;
214     return 0;
215 }
216 static void
command_source_connection_insert_test(void ** state)217 command_source_connection_insert_test (void **state)
218 {
219     struct source_test_data *data = (struct source_test_data*)*state;
220     source_data_t *source_data;
221     CommandSource *source = data->source;
222     GIOStream     *iostream;
223     HandleMap     *handle_map;
224     Connection *connection;
225     gint ret, client_fd;
226 
227     g_debug ("%s", __func__);
228     handle_map = handle_map_new (TPM2_HT_TRANSIENT, MAX_ENTRIES_DEFAULT);
229     iostream = create_connection_iostream (&client_fd);
230     connection = connection_new (iostream, 5, handle_map);
231     g_object_unref (handle_map);
232     g_object_unref (iostream);
233     /* starts the main loop in the CommandSource */
234     ret = thread_start(THREAD (source));
235     will_return (__wrap_g_source_set_callback, &source_data);
236     assert_int_equal (ret, 0);
237     /* normally a callback from the connection manager but we fake it here */
238     sleep (1);
239     command_source_on_new_connection (data->manager, connection, source);
240     /* check internal state of the CommandSource*/
241     assert_int_equal (g_hash_table_size (source->istream_to_source_data_map),
242                       1);
243     thread_cancel (THREAD (source));
244     thread_join (THREAD (source));
245     g_object_unref (connection);
246 }
247 /* command_source_session_insert_test end */
248 
249 /**
250  * A test: Test the command_source_connection_responder function. We do this
251  * by creating a new Connection object, associating it with a new
252  * Tpm2Command object (that we populate with a command body), and then
253  * calling the command_source_connection_responder.
254  * This function will in turn call the connection_manager_lookup_fd,
255  * tpm2_command_new_from_fd, before finally calling the sink_enqueue function.
256  * We mock these 3 functions to control the flow through the function under
257  * test.
258  * The most tricky bit to this is the way the __wrap_sink_enqueue function
259  * works. Since this thing has no return value we pass it a reference to a
260  * Tpm2Command pointer. It sets this to the Tpm2Command that it receives.
261  * We determine success /failure for this test by verifying that the
262  * sink_enqueue function receives the same Tpm2Command that we passed to
263  * the command under test (command_source_connection_responder).
264  */
265 static void
command_source_on_io_ready_success_test(void ** state)266 command_source_on_io_ready_success_test (void **state)
267 {
268     struct source_test_data *data = (struct source_test_data*)*state;
269     GIOStream   *iostream;
270     HandleMap   *handle_map;
271     Connection *connection;
272     Tpm2Command *command_out;
273     gint client_fd;
274     guint8 data_in [] = { 0x80, 0x01, 0x0,  0x0,  0x0,  0x17,
275                           0x0,  0x0,  0x01, 0x7a, 0x0,  0x0,
276                           0x0,  0x06, 0x0,  0x0,  0x01, 0x0,
277                           0x0,  0x0,  0x0,  0x7f, 0x0a };
278 
279     handle_map = handle_map_new (TPM2_HT_TRANSIENT, MAX_ENTRIES_DEFAULT);
280     iostream = create_connection_iostream (&client_fd);
281     connection = connection_new (iostream, 0, handle_map);
282     g_object_unref (handle_map);
283     g_object_unref (iostream);
284         /* prime wraps */
285     will_return (__wrap_connection_manager_lookup_istream, connection);
286 
287     /* setup read of tpm buffer */
288     will_return (__wrap_read_tpm_buffer_alloc, data_in);
289     will_return (__wrap_read_tpm_buffer_alloc, sizeof (data_in));
290     /* setup query for command attributes */
291     will_return (__wrap_command_attrs_from_cc, 0);
292 
293     will_return (__wrap_sink_enqueue, &command_out);
294 
295     command_source_on_input_ready (NULL, data->source);
296 
297     assert_memory_equal (tpm2_command_get_buffer (command_out),
298                          data_in,
299                          sizeof (data_in));
300     g_object_unref (command_out);
301 }
302 /*
303  * This tests the CommandSource on_io_ready function for situations where
304  * the GSocket associated with a client connection is closed. This causes
305  * the attempt to read data from the socket to return an error indicating
306  * that the socket was closed. In this case the function should return a
307  * value telling GLib to remove the GSource from the main loop. Additionally
308  * the data held internally by the CommandSource must be freed.
309  */
310 static void
command_source_on_io_ready_eof_test(void ** state)311 command_source_on_io_ready_eof_test (void **state)
312 {
313     struct source_test_data *data = (struct source_test_data*)*state;
314     source_data_t *source_data;
315     GIOStream   *iostream;
316     HandleMap   *handle_map;
317     Connection *connection;
318     ControlMessage *msg;
319     gint client_fd, hash_table_size;
320     gboolean ret;
321 
322     handle_map = handle_map_new (TPM2_HT_TRANSIENT, MAX_ENTRIES_DEFAULT);
323     iostream = create_connection_iostream (&client_fd);
324     connection = connection_new (iostream, 0, handle_map);
325     g_object_unref (handle_map);
326     g_object_unref (iostream);
327         /* prime wraps */
328     will_return (__wrap_g_source_set_callback, &source_data);
329     will_return (__wrap_connection_manager_lookup_istream, connection);
330     will_return (__wrap_read_tpm_buffer_alloc, NULL);
331     will_return (__wrap_read_tpm_buffer_alloc, 0);
332     will_return (__wrap_sink_enqueue, &msg);
333     will_return (__wrap_connection_manager_remove, TRUE);
334 
335     command_source_on_new_connection (data->manager, connection, data->source);
336     ret = command_source_on_input_ready (g_io_stream_get_input_stream (connection->iostream), source_data);
337     assert_int_equal (ret, G_SOURCE_REMOVE);
338     hash_table_size = g_hash_table_size (data->source->istream_to_source_data_map);
339     assert_int_equal (hash_table_size, 0);
340     g_object_unref (msg);
341 }
342 /* command_source_connection_test end */
343 int
main(void)344 main (void)
345 {
346     const struct CMUnitTest tests[] = {
347         cmocka_unit_test_setup_teardown (command_source_allocate_test,
348                                          command_source_allocate_setup,
349                                          command_source_teardown),
350         cmocka_unit_test_setup_teardown (command_source_start_test,
351                                          command_source_start_setup,
352                                          command_source_teardown),
353         cmocka_unit_test_setup_teardown (command_source_connection_insert_test,
354                                          command_source_connection_setup,
355                                          command_source_teardown),
356         cmocka_unit_test_setup_teardown (command_source_on_io_ready_success_test,
357                                          command_source_connection_setup,
358                                          command_source_teardown),
359         cmocka_unit_test_setup_teardown (command_source_on_io_ready_eof_test,
360                                          command_source_connection_setup,
361                                          command_source_teardown),
362     };
363     return cmocka_run_group_tests (tests, NULL, NULL);
364 }
365