Coverage Report

Created: 2026-06-09 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/testsuite/fuzzsuite.c
Line
Count
Source
1
/* Copyright (c) 2020-2025 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "fuzzer.h"
6
#include "lib-signals.h"
7
#include "ioloop.h"
8
#include "env-util.h"
9
#include "istream.h"
10
#include "hostpid.h"
11
#include "settings.h"
12
13
#include "sieve.h"
14
#include "sieve-extensions.h"
15
#include "sieve-script.h"
16
#include "sieve-storage.h"
17
#include "sieve-binary.h"
18
#include "sieve-result.h"
19
#include "sieve-interpreter.h"
20
21
#include "sieve-settings.h"
22
23
#include "sieve-tool.h"
24
25
#include "testsuite-common.h"
26
#include "testsuite-log.h"
27
#include "testsuite-settings.h"
28
#include "testsuite-result.h"
29
#include "testsuite-message.h"
30
#include "testsuite-script.h"
31
#include "testsuite-smtp.h"
32
#include "testsuite-mailstore.h"
33
34
#include <stdio.h>
35
#include <unistd.h>
36
#include <fcntl.h>
37
#include <pwd.h>
38
#include <sysexits.h>
39
40
//#define FUZZSUITE_DEBUG
41
42
const struct sieve_script_env *testsuite_scriptenv;
43
44
/*
45
 * Configuration
46
 */
47
48
extern const struct setting_parser_info ext_duplicate_setting_parser_info;
49
extern const struct setting_parser_info ext_editheader_header_setting_parser_info;
50
extern const struct setting_parser_info ext_editheader_setting_parser_info;
51
extern const struct setting_parser_info ext_extlists_list_setting_parser_info;
52
extern const struct setting_parser_info ext_extlists_setting_parser_info;
53
extern const struct setting_parser_info ext_include_setting_parser_info;
54
extern const struct setting_parser_info ext_spamtest_setting_parser_info;
55
extern const struct setting_parser_info ext_virustest_setting_parser_info;
56
extern const struct setting_parser_info ext_subaddress_setting_parser_info;
57
extern const struct setting_parser_info ext_vacation_setting_parser_info;
58
extern const struct setting_parser_info ext_variables_setting_parser_info;
59
extern const struct setting_parser_info ext_vnd_environment_setting_parser_info;
60
extern const struct setting_parser_info ext_report_setting_parser_info;
61
extern const struct setting_parser_info ntfy_mailto_setting_parser_info;
62
extern const struct setting_parser_info sieve_dict_storage_setting_parser_info;
63
extern const struct setting_parser_info sieve_file_storage_setting_parser_info;
64
extern const struct setting_parser_info sieve_setting_parser_info;
65
extern const struct setting_parser_info sieve_storage_setting_parser_info;
66
67
static const struct setting_parser_info *set_infos[] = {
68
  &ext_duplicate_setting_parser_info,
69
  &ext_editheader_header_setting_parser_info,
70
  &ext_editheader_setting_parser_info,
71
  &ext_extlists_list_setting_parser_info,
72
  &ext_extlists_setting_parser_info,
73
  &ext_include_setting_parser_info,
74
  &ext_spamtest_setting_parser_info,
75
  &ext_subaddress_setting_parser_info,
76
  &ext_vacation_setting_parser_info,
77
  &ext_variables_setting_parser_info,
78
  &ext_virustest_setting_parser_info,
79
  &ext_vnd_environment_setting_parser_info,
80
  &ext_report_setting_parser_info,
81
  &ntfy_mailto_setting_parser_info,
82
83
  &sieve_file_storage_setting_parser_info,
84
  &sieve_dict_storage_setting_parser_info,
85
86
  &sieve_setting_parser_info,
87
  &sieve_storage_setting_parser_info,
88
};
89
unsigned int set_infos_count = N_ELEMENTS(set_infos);
90
91
/*
92
 * Testsuite execution
93
 */
94
95
static void
96
fuzz_die(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
97
0
{
98
0
  printf("COMMAND LINE INTERRUPT\n");
99
100
0
  testsuite_tmp_dir_deinit();
101
102
  /* No delays, no fuzzer reports: be gone already */
103
0
  _exit(0);
104
0
}
105
106
FUZZ_BEGIN_DATA(const unsigned char *data, size_t size)
107
{
108
  static bool first_run = TRUE;
109
  struct sieve_instance *svinst;
110
  struct sieve_binary *sbin;
111
  const char *sieve_dir = ".", *error;
112
  unsigned int i;
113
  bool log_stdout = FALSE;
114
  int ret;
115
116
  if (first_run) {
117
#ifndef FUZZSUITE_DEBUG
118
    testsuite_silent = (getenv("DEBUG") == NULL);
119
#endif
120
    first_run = FALSE;
121
  }
122
123
  sieve_tool = sieve_tool_init_fuzzer("fuzzsuite");
124
125
  /* Allow quick command line termination when developing. This is not
126
     expected in a normal fuzzer run. */
127
  lib_signals_set_handler(SIGINT, 0, fuzz_die, NULL);
128
129
#ifdef FUZZSUITE_DEBUG
130
  struct sieve_trace_config trace_config;
131
132
  i_zero(&trace_config);
133
  trace_config.level = SIEVE_TRLVL_MATCHING;
134
135
  log_stdout = TRUE;
136
#endif
137
138
  // FIXME: very very ugly
139
  master_service_parse_option(
140
    master_service, 'o',
141
    "postmaster_address=postmaster@example.com");
142
  master_service_parse_option(master_service, 'o', "mail_uid=");
143
  master_service_parse_option(master_service, 'o', "mail_gid=");
144
  master_service_parse_option(master_service, 'o', "default_internal_group=");
145
146
  /* Register settings manually */
147
  for (i = 0; i < set_infos_count; i++)
148
    settings_info_register(set_infos[i]);
149
150
  /* Finish testsuite initialization */
151
  svinst = sieve_tool_init_finish(sieve_tool, FALSE, FALSE);
152
#ifdef FUZZSUITE_DEBUG
153
  event_set_forced_debug(sieve_get_event(svinst), TRUE);
154
#endif
155
  testsuite_init(svinst, sieve_dir, sieve_tool_get_homedir(sieve_tool),
156
           log_stdout);
157
158
  if (!testsuite_silent)
159
    printf("Fuzz case:\n\n");
160
161
  struct settings_instance *set_instance =
162
    settings_instance_find(svinst->event);
163
164
  /* Configure personal storage */
165
  settings_override(set_instance, "sieve_script+", "included",
166
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
167
  settings_override(set_instance,
168
        "sieve_script/included/sieve_script_storage",
169
        "included",
170
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
171
  settings_override(set_instance,
172
        "sieve_script/included/sieve_script_type",
173
        SIEVE_STORAGE_TYPE_PERSONAL,
174
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
175
  settings_override(set_instance,
176
        "sieve_script/included/sieve_script_driver",
177
        "file", SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
178
  settings_override(set_instance,
179
        "sieve_script/included/sieve_script_path",
180
        t_strdup_printf("%s/included", sieve_dir),
181
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
182
183
  /* Configure global storage */
184
  settings_override(set_instance, "sieve_script+", "included-global",
185
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
186
  settings_override(set_instance,
187
        "sieve_script/included-global/sieve_script_storage",
188
        "included-global",
189
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
190
  settings_override(set_instance,
191
        "sieve_script/included-global/sieve_script_type",
192
        SIEVE_STORAGE_TYPE_GLOBAL,
193
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
194
  settings_override(set_instance,
195
        "sieve_script/included-global/sieve_script_driver",
196
        "file", SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
197
  settings_override(set_instance,
198
        "sieve_script/included-global/sieve_script_path",
199
        t_strdup_printf("%s/included-global", sieve_dir),
200
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
201
202
  /* Construct Sieve script */
203
  struct sieve_script *script;
204
  struct istream *input;
205
206
  input = i_stream_create_from_data(data, size);
207
  script = sieve_data_script_create_from_input(
208
    svinst, SIEVE_SCRIPT_CAUSE_ANY, "fuzzsuite-main", input);
209
210
  /* Compile Sieve script */
211
  if (sieve_compile_script(script, testsuite_log_main_ehandler, 0,
212
         &sbin, NULL) < 0) {
213
    testsuite_testcase_fail("failed to compile testcase script");
214
  } else {
215
#ifdef FUZZSUITE_DEBUG
216
    struct sieve_trace_log *trace_log = NULL;
217
218
    sieve_tool_dump_binary_to(sbin, "-", FALSE);
219
    (void)sieve_trace_log_create(svinst, NULL, &trace_log);
220
#endif
221
222
    struct sieve_exec_status exec_status;
223
    struct sieve_script_env scriptenv;
224
225
    testsuite_mailstore_init();
226
    testsuite_message_init();
227
228
    if (sieve_script_env_init(&scriptenv,
229
            testsuite_mailstore_get_user(),
230
            &error) < 0) {
231
      i_fatal("Failed to initialize script execution: %s",
232
        error);
233
    }
234
235
    i_zero(&exec_status);
236
237
    scriptenv.default_mailbox = "INBOX";
238
    scriptenv.smtp_start = testsuite_smtp_start;
239
    scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt;
240
    scriptenv.smtp_send = testsuite_smtp_send;
241
    scriptenv.smtp_abort = testsuite_smtp_abort;
242
    scriptenv.smtp_finish = testsuite_smtp_finish;
243
#ifdef FUZZSUITE_DEBUG
244
    scriptenv.trace_log = trace_log;
245
    scriptenv.trace_config = trace_config;
246
#endif
247
    scriptenv.exec_status = &exec_status;
248
249
    testsuite_scriptenv = &scriptenv;
250
251
    testsuite_result_init();
252
253
    /* Fuzz the test */
254
    ret = testsuite_run(sbin, testsuite_log_main_ehandler);
255
256
    switch (ret) {
257
    case SIEVE_EXEC_OK:
258
      break;
259
    case SIEVE_EXEC_FAILURE:
260
    case SIEVE_EXEC_KEEP_FAILED:
261
    case SIEVE_EXEC_TEMP_FAILURE:
262
      testsuite_testcase_fail(
263
        "test script execution aborted due to error");
264
      break;
265
    case SIEVE_EXEC_BIN_CORRUPT:
266
      i_panic("BUG: compiled test script binary is corrupt");
267
      break;
268
    case SIEVE_EXEC_RESOURCE_LIMIT:
269
      i_panic("BUG: resource limit exceeded");
270
      break;
271
    }
272
273
    sieve_close(&sbin);
274
275
    /* De-initialize message environment */
276
    testsuite_result_deinit();
277
    testsuite_message_deinit();
278
    testsuite_mailstore_deinit();
279
280
#ifdef FUZZSUITE_DEBUG
281
    if (trace_log != NULL)
282
      sieve_trace_log_free(&trace_log);
283
#endif
284
285
    testsuite_scriptenv = NULL;
286
  }
287
288
  sieve_script_unref(&script);
289
  i_stream_destroy(&input);
290
291
  /* De-initialize testsuite */
292
  testsuite_deinit();
293
294
  sieve_tool_deinit(&sieve_tool);
295
296
  testsuite_testcase_result(FALSE);
297
}
298
FUZZ_END