misc: binary api fuzz test fixes
[vpp.git] / src / plugins / unittest / api_fuzz_test.c
1 /*
2  *------------------------------------------------------------------
3  * api_fuzz_test.c - Binary API fuzz hook
4  *
5  * Copyright (c) 2020 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 #include <vppinfra/format.h>
20 #include <vppinfra/byte_order.h>
21 #include <vppinfra/error.h>
22 #include <vlib/vlib.h>
23 #include <vlib/unix/unix.h>
24 #include <vlibapi/api.h>
25
26 static u32 fuzz_seed = 0xdeaddabe;
27 static u16 fuzz_first;
28 static u16 fuzz_cli_first, fuzz_cli_last;
29
30 extern void (*vl_msg_api_fuzz_hook) (u16, void *);
31
32 static void
33 fuzz_hook (u16 id, void *the_msg)
34 {
35   /*
36    * Fuzz (aka screw up) this message? Leave connection establishment
37    * messages alone as well as CLI messages.
38    */
39   if ((id > fuzz_first) && !(id >= fuzz_cli_first && id < fuzz_cli_last))
40     {
41       msgbuf_t *mb;
42       u8 *limit, *start;
43
44       mb = (msgbuf_t *) (((u8 *) the_msg) - offsetof (msgbuf_t, data));
45
46       limit = (u8 *) (mb->data + ntohl (mb->data_len));
47
48       /*
49        * Leave the first 14 octets alone, aka msg_id, client_index,
50        * context, sw_if_index
51        */
52
53       start = ((u8 *) the_msg) + 14;
54
55       for (; start < limit; start++)
56         *start ^= (random_u32 (&fuzz_seed) & 0xFF);
57     }
58 }
59
60 static void
61 default_fuzz_config (void)
62 {
63   fuzz_first = vl_msg_api_get_msg_index
64     ((u8 *) "memclnt_keepalive_reply_e8d4e804");
65   fuzz_cli_first = vl_msg_api_get_msg_index ((u8 *) "cli_23bfbfff");
66   fuzz_cli_last = vl_msg_api_get_msg_index
67     ((u8 *) "cli_inband_reply_05879051");
68 }
69
70 static clib_error_t *
71 test_api_fuzz_command_fn (vlib_main_t * vm,
72                           unformat_input_t * input, vlib_cli_command_t * cmd)
73 {
74   u32 tmp;
75
76   default_fuzz_config ();
77
78   if (fuzz_first == 0xFFFF)
79     {
80       vlib_cli_output (vm, "Couldn't find 'memclnt_keepalive_reply' ID");
81       vlib_cli_output
82         (vm, "Manual setting required, use 'show api message table'");
83     }
84
85   if (fuzz_cli_first == 0xFFFF)
86     {
87       vlib_cli_output (vm, "Couldn't find 'cli' ID");
88       vlib_cli_output
89         (vm, "Manual setting required, use 'show api message table'");
90     }
91
92   if (fuzz_cli_last == 0xFFFF)
93     {
94       vlib_cli_output (vm, "Couldn't find 'cli_inband_reply' ID");
95       vlib_cli_output
96         (vm, "Manual setting required, use 'show api message table'");
97     }
98
99   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
100     {
101       if (unformat (input, "seed %d", &fuzz_seed))
102         ;
103       else if (unformat (input, "disable") | unformat (input, "off"))
104         fuzz_first = ~0;
105       else if (unformat (input, "fuzz-first %d", &tmp))
106         fuzz_first = (u16) tmp;
107       else if (unformat (input, "fuzz-cli-first %d", &tmp))
108         fuzz_cli_first = (u16) tmp;
109       else if (unformat (input, "fuzz-cli-last %d", &tmp))
110         fuzz_cli_last = (u16) tmp;
111       else
112         break;
113     }
114
115   if (fuzz_first == 0xFFFF)
116     {
117       vl_msg_api_fuzz_hook = 0;
118       return clib_error_return (0, "fuzz_first is ~0, fuzzing disabled");
119     }
120   vl_msg_api_fuzz_hook = fuzz_hook;
121
122   vlib_cli_output (vm, "Fuzzing enabled: first %d, skip cli range %d - %d",
123                    (u32) fuzz_first, (u32) fuzz_cli_first,
124                    (u32) fuzz_cli_last);
125
126   return 0;
127 }
128
129 /* *INDENT-OFF* */
130 VLIB_CLI_COMMAND (test_api_fuzz, static) = {
131    .path = "test api fuzz",
132    .short_help = "test api fuzz [disable][seed nnn]\n"
133    "           [fuzz-first nn][fuzz-cli-first nn][fuzz-cli-last nn]",
134    .function = test_api_fuzz_command_fn,
135   };
136 /* *INDENT-ON* */
137
138 static u8 main_loop_enter_enable_api_fuzz;
139
140 static clib_error_t *
141 api_fuzz_config (vlib_main_t * vm, unformat_input_t * input)
142 {
143   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
144     {
145       if (unformat (input, "off")
146           || unformat (input, "disable") || unformat (input, "no"))
147         ;                       /* ok, no action */
148       else if (unformat (input, "on")
149                || unformat (input, "enable") || unformat (input, "yes"))
150         main_loop_enter_enable_api_fuzz = 1;
151       else
152         return clib_error_return (0, "unknown input '%U'",
153                                   format_unformat_error, input);
154     }
155   return 0;
156 }
157
158 VLIB_CONFIG_FUNCTION (api_fuzz_config, "api-fuzz");
159
160 static clib_error_t *
161 api_fuzz_api_init (vlib_main_t * vm)
162 {
163   /* Are we supposed to fuzz API messages? */
164   if (main_loop_enter_enable_api_fuzz == 0)
165     return 0;
166
167   default_fuzz_config ();
168
169   if (fuzz_first == 0xFFFF)
170     {
171       return clib_error_return
172         (0, "Couldn't find 'memclnt_keepalive_reply' ID");
173     }
174   /* Turn on fuzzing */
175   vl_msg_api_fuzz_hook = fuzz_hook;
176   return 0;
177 }
178
179 VLIB_API_INIT_FUNCTION (api_fuzz_api_init);
180
181 /*
182  * fd.io coding-style-patch-verification: ON
183  *
184  * Local Variables:
185  * eval: (c-set-style "gnu")
186  * End:
187  */