Coverage Report

Created: 2025-11-24 06:21

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
6.08k
{
16
6.08k
  i_zero(fuzz_ctx);
17
6.08k
  if (!lib_is_initialized()) {
18
1
    lib_init();
19
1
    lib_signals_init();
20
1
    lib_signals_ignore(SIGPIPE, TRUE);
21
1
  }
22
6.08k
  fuzz_ctx->fd = -1;
23
6.08k
  fuzz_ctx->fd_pump = -1;
24
6.08k
}
25
26
void fuzzer_deinit(struct fuzzer_context *fuzz_ctx)
27
6.08k
{
28
6.08k
  iostream_pump_destroy(&fuzz_ctx->pump);
29
  /* ensure fd gets closed, we don't care
30
     if this fails. */
31
6.08k
  if (fuzz_ctx->fd > -1)
32
6.08k
    (void)close(fuzz_ctx->fd);
33
6.08k
  if (fuzz_ctx->fd_pump > -1)
34
6.08k
    (void)close(fuzz_ctx->fd_pump);
35
6.08k
  if (fuzz_ctx->ioloop != NULL)
36
6.08k
    io_loop_destroy(&fuzz_ctx->ioloop);
37
6.08k
}
38
39
static void pump_finished(enum iostream_pump_status status ATTR_UNUSED,
40
        struct fuzzer_context *fuzz_ctx)
41
6.06k
{
42
6.06k
  struct istream *input = iostream_pump_get_input(fuzz_ctx->pump);
43
6.06k
  struct ostream *output = iostream_pump_get_output(fuzz_ctx->pump);
44
45
6.06k
  switch (status) {
46
6.06k
  case IOSTREAM_PUMP_STATUS_INPUT_EOF:
47
6.06k
    break;
48
0
  case IOSTREAM_PUMP_STATUS_INPUT_ERROR:
49
0
    i_error("read(%s) failed: %s", i_stream_get_name(input),
50
0
      i_stream_get_error(input));
51
0
    break;
52
0
  case IOSTREAM_PUMP_STATUS_OUTPUT_ERROR:
53
0
    i_error("write(%s) failed: %s", o_stream_get_name(output),
54
0
      o_stream_get_error(output));
55
0
    break;
56
6.06k
  };
57
58
6.06k
  if (shutdown(o_stream_get_fd(output), SHUT_WR) < 0)
59
0
    i_fatal("shutdown() failed: %m");
60
6.06k
  iostream_pump_destroy(&fuzz_ctx->pump);
61
6.06k
}
62
63
int fuzzer_io_as_fd(struct fuzzer_context *fuzz_ctx,
64
       const uint8_t *data, size_t size)
65
6.08k
{
66
6.08k
  int sfd[2];
67
68
6.08k
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0)
69
0
    i_fatal("socketpair() failed: %m");
70
6.08k
  net_set_nonblock(sfd[0], TRUE);
71
6.08k
  net_set_nonblock(sfd[1], TRUE);
72
73
6.08k
  struct istream *input = i_stream_create_from_data(data, size);
74
6.08k
  struct ostream *output = o_stream_create_fd(sfd[0], IO_BLOCK_SIZE);
75
6.08k
  i_stream_set_name(input, "(fuzzer data)");
76
6.08k
  o_stream_set_name(output, "(fuzzer input to program)");
77
6.08k
  o_stream_set_no_error_handling(output, TRUE);
78
79
6.08k
  fuzz_ctx->pump = iostream_pump_create(input, output);
80
6.08k
  fuzz_ctx->fd_pump = sfd[0];
81
6.08k
  fuzz_ctx->fd = sfd[1];
82
6.08k
  iostream_pump_set_completion_callback(fuzz_ctx->pump, pump_finished,
83
6.08k
                fuzz_ctx);
84
6.08k
  i_stream_unref(&input);
85
6.08k
  o_stream_unref(&output);
86
6.08k
  iostream_pump_start(fuzz_ctx->pump);
87
6.08k
  return sfd[1];
88
6.08k
}
89
90
const char *fuzzer_t_strndup_replace_zero(
91
  const uint8_t *data, size_t size, char subst)
92
0
{
93
0
  char *out = t_malloc_no0(size + 1);
94
0
  for (size_t index = 0; index < size; ++index) {
95
0
    uint8_t ch = data[index];
96
0
    out[index] = ch == 0 ? subst : (char)ch;
97
0
  }
98
0
  out[size] = '\0';
99
0
  return out;
100
0
}