Coverage Report

Created: 2026-06-15 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-test/fuzzer.c
Line
Count
Source
1
/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "lib-signals.h"
5
#include "net.h"
6
#include "istream.h"
7
#include "ostream.h"
8
#include "iostream-pump.h"
9
#include "fuzzer.h"
10
11
#include <sys/socket.h>
12
#include <unistd.h>
13
14
void fuzzer_init(struct fuzzer_context *fuzz_ctx)
15
5.63k
{
16
5.63k
  i_zero(fuzz_ctx);
17
5.63k
  if (!lib_is_initialized()) {
18
5.63k
    lib_init();
19
5.63k
    lib_signals_init();
20
5.63k
    lib_signals_ignore(SIGPIPE, TRUE);
21
5.63k
    fuzz_ctx->lib_initialized = TRUE;
22
5.63k
  }
23
5.63k
  fuzz_ctx->fd = -1;
24
5.63k
  fuzz_ctx->fd_pump = -1;
25
5.63k
}
26
27
void fuzzer_deinit(struct fuzzer_context *fuzz_ctx)
28
5.63k
{
29
5.63k
  iostream_pump_destroy(&fuzz_ctx->pump);
30
  /* ensure fd gets closed, we don't care
31
     if this fails. */
32
5.63k
  if (fuzz_ctx->fd > -1)
33
5.63k
    (void)close(fuzz_ctx->fd);
34
5.63k
  if (fuzz_ctx->fd_pump > -1)
35
5.63k
    (void)close(fuzz_ctx->fd_pump);
36
5.63k
  if (fuzz_ctx->ioloop != NULL)
37
5.63k
    io_loop_destroy(&fuzz_ctx->ioloop);
38
5.63k
  if (fuzz_ctx->lib_initialized) {
39
5.63k
    lib_signals_deinit();
40
5.63k
    lib_deinit();
41
5.63k
  }
42
5.63k
}
43
44
static void pump_finished(enum iostream_pump_status status ATTR_UNUSED,
45
        struct fuzzer_context *fuzz_ctx)
46
5.61k
{
47
5.61k
  struct istream *input = iostream_pump_get_input(fuzz_ctx->pump);
48
5.61k
  struct ostream *output = iostream_pump_get_output(fuzz_ctx->pump);
49
50
5.61k
  switch (status) {
51
5.61k
  case IOSTREAM_PUMP_STATUS_INPUT_EOF:
52
5.61k
    break;
53
0
  case IOSTREAM_PUMP_STATUS_INPUT_ERROR:
54
0
    i_error("read(%s) failed: %s", i_stream_get_name(input),
55
0
      i_stream_get_error(input));
56
0
    break;
57
0
  case IOSTREAM_PUMP_STATUS_OUTPUT_ERROR:
58
0
    i_error("write(%s) failed: %s", o_stream_get_name(output),
59
0
      o_stream_get_error(output));
60
0
    break;
61
5.61k
  };
62
63
5.61k
  if (shutdown(o_stream_get_fd(output), SHUT_WR) < 0)
64
0
    i_fatal("shutdown() failed: %m");
65
5.61k
  iostream_pump_destroy(&fuzz_ctx->pump);
66
5.61k
}
67
68
int fuzzer_io_as_fd(struct fuzzer_context *fuzz_ctx,
69
       const uint8_t *data, size_t size)
70
5.63k
{
71
5.63k
  int sfd[2];
72
73
5.63k
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0)
74
0
    i_fatal("socketpair() failed: %m");
75
5.63k
  net_set_nonblock(sfd[0], TRUE);
76
5.63k
  net_set_nonblock(sfd[1], TRUE);
77
78
5.63k
  struct istream *input = i_stream_create_from_data(data, size);
79
5.63k
  struct ostream *output = o_stream_create_fd(sfd[0], IO_BLOCK_SIZE);
80
5.63k
  i_stream_set_name(input, "(fuzzer data)");
81
5.63k
  o_stream_set_name(output, "(fuzzer input to program)");
82
5.63k
  o_stream_set_no_error_handling(output, TRUE);
83
84
5.63k
  fuzz_ctx->pump = iostream_pump_create(input, output);
85
5.63k
  fuzz_ctx->fd_pump = sfd[0];
86
5.63k
  fuzz_ctx->fd = sfd[1];
87
5.63k
  iostream_pump_set_completion_callback(fuzz_ctx->pump, pump_finished,
88
5.63k
                fuzz_ctx);
89
5.63k
  i_stream_unref(&input);
90
5.63k
  o_stream_unref(&output);
91
5.63k
  iostream_pump_start(fuzz_ctx->pump);
92
5.63k
  return sfd[1];
93
5.63k
}
94
95
const char *fuzzer_t_strndup_replace_zero(
96
  const uint8_t *data, size_t size, char subst)
97
0
{
98
0
  char *out = t_malloc_no0(size + 1);
99
0
  for (size_t index = 0; index < size; ++index) {
100
0
    uint8_t ch = data[index];
101
0
    out[index] = ch == 0 ? subst : (char)ch;
102
0
  }
103
0
  out[size] = '\0';
104
0
  return out;
105
0
}