Coverage Report

Created: 2026-10-13 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pupnp/fuzzer/FuzzWebServer.c
Line
Count
Source
1
#include "config.h"
2
3
#include "httpparser.h"
4
#include "httpreadwrite.h"
5
#include "sock.h"
6
#include "statcodes.h"
7
#include "upnpapi.h"
8
#include "webserver.h"
9
10
#if EXCLUDE_GENA == 0
11
  #include "gena.h"
12
#endif
13
#if defined(INCLUDE_DEVICE_APIS) && EXCLUDE_SOAP == 0
14
  #include "soaplib.h"
15
#endif
16
17
#include <arpa/inet.h>
18
#include <netinet/in.h>
19
#include <stddef.h>
20
#include <stdint.h>
21
#include <stdlib.h>
22
#include <string.h>
23
#include <sys/socket.h>
24
#include <unistd.h>
25
26
/* Keeps the whole input within the socket buffer, so the single write()
27
 * below never blocks. */
28
6.49k
#define MAX_INPUT_SIZE 65536
29
30
static const char description[] =
31
  "<?xml version=\"1.0\"?>\r\n"
32
  "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
33
  "<specVersion><major>1</major><minor>0</minor></specVersion>"
34
  "<device>"
35
  "<deviceType>urn:schemas-upnp-org:device:tvdevice:1</deviceType>"
36
  "<friendlyName>fuzz</friendlyName>"
37
  "<UDN>uuid:fuzz-0000-0000-0000-000000000001</UDN>"
38
  "</device>"
39
  "</root>\r\n";
40
41
/* Mirrors dispatch_request() in miniserver.c. */
42
static void dispatch(SOCKINFO *info, http_parser_t *parser)
43
4.69k
{
44
4.69k
  http_message_t *request = &parser->msg;
45
46
  /* The miniserver drops requests without a HOST header. */
47
4.69k
  if (httpmsg_find_hdr(request, HDR_HOST, NULL) == NULL) {
48
492
    return;
49
492
  }
50
51
4.20k
  switch (request->method) {
52
0
#if defined(INCLUDE_DEVICE_APIS) && EXCLUDE_SOAP == 0
53
1
  case SOAPMETHOD_POST:
54
2
  case HTTPMETHOD_MPOST:
55
2
    soap_device_callback(parser, request, info);
56
2
    break;
57
0
#endif
58
0
#if EXCLUDE_GENA == 0
59
2.92k
  case HTTPMETHOD_NOTIFY:
60
2.98k
  case HTTPMETHOD_SUBSCRIBE:
61
3.00k
  case HTTPMETHOD_UNSUBSCRIBE:
62
3.00k
    genaCallback(parser, request, info);
63
3.00k
    break;
64
0
#endif
65
0
#if EXCLUDE_WEB_SERVER == 0
66
1.18k
  case HTTPMETHOD_GET:
67
1.19k
  case HTTPMETHOD_POST:
68
1.19k
  case HTTPMETHOD_HEAD:
69
1.19k
  case HTTPMETHOD_SIMPLEGET:
70
1.19k
    web_server_callback(parser, request, info);
71
1.19k
    break;
72
0
#endif
73
1
  default:
74
1
    http_SendStatusResponse(info,
75
1
      HTTP_INTERNAL_SERVER_ERROR,
76
1
      request->major_version,
77
1
      request->minor_version);
78
1
    break;
79
4.20k
  }
80
4.20k
}
81
82
int LLVMFuzzerInitialize(int *argc, char ***argv)
83
2
{
84
2
  (void)argc;
85
2
  (void)argv;
86
87
2
  ithread_initialize_library();
88
2
  ithread_rwlock_init(&GlobalHndRWLock, NULL);
89
2
#if EXCLUDE_WEB_SERVER == 0
90
2
  if (web_server_init() == UPNP_E_SUCCESS) {
91
    /* The web server takes ownership of the alias content. */
92
2
    char *doc = malloc(sizeof(description) - 1);
93
94
2
    if (doc) {
95
2
      memcpy(doc, description, sizeof(description) - 1);
96
2
      if (web_server_set_alias("description.xml",
97
2
            doc,
98
2
            sizeof(description) - 1,
99
2
            0) != UPNP_E_SUCCESS) {
100
0
        free(doc);
101
0
      }
102
2
    }
103
2
  }
104
2
#endif
105
106
2
  return 0;
107
2
}
108
109
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
110
6.49k
{
111
6.49k
  int sv[2];
112
6.49k
  SOCKINFO info;
113
6.49k
  struct sockaddr_storage peer;
114
6.49k
  struct sockaddr_in *peer4 = (struct sockaddr_in *)&peer;
115
6.49k
  http_parser_t parser;
116
6.49k
  int timeout = 1;
117
6.49k
  int http_error_code = 0;
118
119
6.49k
  if (Size < 1 || Size > MAX_INPUT_SIZE) {
120
0
    return 0;
121
0
  }
122
6.49k
  parser_request_init(&parser);
123
6.49k
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0) {
124
0
    return 0;
125
0
  }
126
6.49k
  if (write(sv[1], Data, Size) != (ssize_t)Size) {
127
0
    close(sv[0]);
128
0
    close(sv[1]);
129
0
    return 0;
130
0
  }
131
  /* The end of file lets messages without a length complete. Responses
132
   * are left unread in sv[1] and dropped when it is closed. */
133
6.49k
  shutdown(sv[1], SHUT_WR);
134
135
  /* GENA and SOAP pick the handle by the address family of the peer. */
136
6.49k
  memset(&peer, 0, sizeof(peer));
137
6.49k
  peer4->sin_family = AF_INET;
138
6.49k
  peer4->sin_port = htons(49152);
139
6.49k
  peer4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
140
6.49k
  sock_init_with_ip(&info, sv[0], (struct sockaddr *)&peer);
141
142
  /* Same sequence as handle_request() in miniserver.c. */
143
6.49k
  if (http_RecvMessage(&info,
144
6.49k
        &parser,
145
6.49k
        HTTPMETHOD_UNKNOWN,
146
6.49k
        &timeout,
147
6.49k
        &http_error_code) == 0) {
148
4.69k
    dispatch(&info, &parser);
149
4.69k
  } else if (http_error_code > 0) {
150
1.79k
    http_SendStatusResponse(&info,
151
1.79k
      http_error_code,
152
1.79k
      parser.msg.major_version,
153
1.79k
      parser.msg.minor_version);
154
1.79k
  }
155
156
6.49k
  httpmsg_destroy(&parser.msg);
157
6.49k
  sock_destroy(&info, SD_BOTH);
158
6.49k
  close(sv[1]);
159
160
6.49k
  return 0;
161
6.49k
}