Coverage Report

Created: 2025-11-09 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/parser/parse_hname2.c
Line
Count
Source
1
/*
2
 * Fast 32-bit Header Field Name Parser
3
 *
4
 * Copyright (C) 2001-2003 FhG Fokus
5
 *
6
 * This file is part of opensips, a free SIP server.
7
 *
8
 * opensips is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version
12
 *
13
 * opensips is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
21
 *
22
 * History:
23
 * --------
24
 * 2003-02-28 scratchpad compatibility abandoned (jiri)
25
 * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
26
 * 2003-05-01 added support for Accept HF (janakj)
27
 * 2006-02-17 Session-Expires, Min-SE (dhsueh@somanetworks.com)
28
 */
29
30
31
#include "parse_hname2.h"
32
#include "keys.h"
33
#include "../ut.h"  /* q_memchr */
34
35
1.05M
#define LOWER_BYTE(b) ((b) | 0x20U)
36
2.71M
#define LOWER_DWORD(d) ((d) | 0x20202020U)
37
38
/*
39
 * Skip all white-chars and return position of the first
40
 * non-white char
41
 */
42
static inline char* skip_ws(char* p, char *end)
43
65.6k
{
44
87.7k
  for(; p < end; p++) {
45
87.2k
    if ((*p != ' ') && (*p != '\t')) return p;
46
87.2k
  }
47
487
  return p;
48
65.6k
}
49
50
/*
51
 * Parser macros
52
 */
53
#include "case_via.h"      /* Via */
54
#include "case_from.h"     /* From */
55
#include "case_to.h"       /* To */
56
#include "case_cseq.h"     /* CSeq */
57
#include "case_call.h"     /* Call-ID */
58
#include "case_cont.h"     /* Contact, Content-Type, Content-Length,
59
                              Content-Purpose, Content-Action,
60
                              Content-Disposition */
61
#include "case_rout.h"     /* Route */
62
#include "case_max.h"      /* Max-Forwards */
63
#include "case_reco.h"     /* Record-Route */
64
#include "case_path.h"     /* Path */
65
#include "case_auth.h"     /* Authorization */
66
#include "case_expi.h"     /* Expires */
67
#include "case_prox.h"     /* Proxy-Authorization, Proxy-Require */
68
#include "case_allo.h"     /* Allow */
69
#include "case_unsu.h"     /* Unsupported */
70
#include "case_even.h"     /* Event */
71
#include "case_acce.h"     /* Accept, Accept-Language */
72
#include "case_orga.h"     /* Organization */
73
#include "case_prio.h"     /* Priority */
74
#include "case_subj.h"     /* Subject */
75
#include "case_user.h"     /* User-Agent */
76
#include "case_supp.h"     /* Supported */
77
#include "case_dive.h"     /* Diversion */
78
#include "case_remo.h"     /* Remote-Party-ID */
79
#include "case_refe.h"     /* Refer-To */
80
#include "case_sess.h"     /* Session-Expires */
81
#include "case_min_.h"     /* Min-SE */
82
#include "case_p_pr.h"     /* P-Preferred-Identity */
83
#include "case_p_as.h"     /* P-Asserted-Identity */
84
#include "case_priv.h"     /* Privacy */
85
#include "case_retr.h"     /* Retry-After */
86
#include "case_www.h"      /* WWW-Authenticate */
87
#include "case_feat.h"     /* Feature-Caps */
88
#include "case_repl.h"     /* Replaces */
89
#include "case_to_p.h"     /* To-Path */
90
#include "case_mess.h"     /* Message-ID */
91
#include "case_byte.h"     /* Byte-Range */
92
#include "case_fail.h"     /* Failure-Report */
93
#include "case_succ.h"     /* Success-Report */
94
#include "case_stat.h"     /* Status */
95
#include "case_use_.h"     /* Use-Path */
96
#include "case_secu.h"     /* Security-Client, Security-Server,
97
                              Security-Verify */
98
99
100
/*
101
 * Read 4-bytes from memory, as an unsigned integer
102
 * Reading byte by byte ensures that the code works also on HW which
103
 * does not allow reading 4-bytes at once from unaligned memory position
104
 * (Sparc for example)
105
 */
106
#define READ(addr) \
107
1.25M
  ((unsigned)*((unsigned char *)addr + 0) + \
108
1.25M
   ((unsigned)*((unsigned char *)addr + 1) << 8) + \
109
1.25M
   ((unsigned)*((unsigned char *)addr + 2) << 16) + \
110
1.25M
   ((unsigned)*((unsigned char *)addr + 3) << 24))
111
112
#ifdef FUZZ_BUILD
113
/* fuzzers are sensible to heap read overflows, so enable all "HAVE" checks */
114
1.17M
#define HAVE(bytes) (end - p >= (long)(bytes))
115
#else
116
/* with PKG memory, parser read overflows of a few bytes are harmless, since
117
 * the memory is pre-allocated and the read cannot SIGSEGV, making the parser
118
 * a lot more performant in production */
119
#define HAVE(bytes) 1
120
#endif
121
122
#define FIRST_QUATERNIONS       \
123
2.37k
  case _via1_: via1_CASE; \
124
18.8k
  case _from_: from_CASE; \
125
697
  case _to12_: to12_CASE; \
126
76.6k
  case _cseq_: cseq_CASE; \
127
76.6k
  case _call_: call_CASE; \
128
58.8k
  case _cont_: cont_CASE; \
129
5.06k
  case _rout_: rout_CASE; \
130
16.9k
  case _max__: max_CASE;  \
131
17.5k
  case _reco_: reco_CASE; \
132
261
  case _via2_: via2_CASE; \
133
12.8k
  case _auth_: auth_CASE; \
134
9.10k
  case _supp_: supp_CASE; \
135
13.2k
  case _expi_: expi_CASE; \
136
68.9k
  case _prox_: prox_CASE; \
137
14.1k
  case _allo_: allo_CASE; \
138
9.55k
  case _path_: path_CASE; \
139
21.4k
  case _unsu_: unsu_CASE; \
140
8.08k
  case _even_: even_CASE; \
141
73.6k
  case _acce_: acce_CASE; \
142
12.6k
  case _orga_: orga_CASE; \
143
7.13k
  case _prio_: prio_CASE; \
144
11.4k
  case _subj_: subj_CASE; \
145
7.85k
  case _user_: user_CASE; \
146
12.7k
  case _dive_: dive_CASE; \
147
9.08k
  case _remo_: remo_CASE; \
148
9.25k
  case _refe_: refe_CASE; \
149
22.9k
  case _sess_: sess_CASE; \
150
19.5k
  case _min__: min__CASE; \
151
16.7k
  case _p_pr_: p_pr_CASE; \
152
9.11k
  case _p_as_: p_as_CASE; \
153
16.8k
  case _priv_: priv_CASE; \
154
29.0k
  case _retr_: retr_CASE; \
155
15.3k
  case _www__: www_CASE;  \
156
9.54k
  case _feat_: feat_CASE; \
157
5.81k
  case _repl_: repl_CASE; \
158
8.39k
  case _to_p_: to_p_CASE; \
159
24.5k
  case _mess_: mess_CASE; \
160
14.3k
  case _byte_: byte_CASE; \
161
11.2k
  case _fail_: fail_CASE; \
162
10.5k
  case _succ_: succ_CASE; \
163
11.0k
  case _stat_: stat_CASE; \
164
3.04k
  case _use__: use__CASE; \
165
42.0k
  case _secu_: secu_CASE; \
166
167
168
#define PARSE_COMPACT(id)      \
169
310k
  switch(*(p + 1)) {         \
170
9.11k
    case ' ':              \
171
22.3k
    case '\t':             \
172
22.3k
      hdr->type = id;    \
173
22.3k
      hdr->name.len = 1; \
174
22.3k
      p += 2;            \
175
22.3k
      goto dc_end;       \
176
195k
    case ':':              \
177
195k
      hdr->type = id;    \
178
195k
      hdr->name.len = 1; \
179
195k
      return (p + 2);    \
180
310k
  }
181
182
183
char* parse_hname2(char* begin, char* end, struct hdr_field* hdr)
184
1.47M
{
185
1.47M
  register char* p;
186
1.47M
  register unsigned int val;
187
188
1.47M
  if ((end - begin) < 4) {
189
1.73k
    hdr->type = HDR_ERROR_T;
190
1.73k
    return begin;
191
1.73k
  }
192
193
1.47M
  p = begin;
194
195
1.47M
  val = LOWER_DWORD(READ(p));
196
1.47M
  hdr->name.s = begin;
197
198
1.47M
  switch(val) {
199
200
1.33M
    FIRST_QUATERNIONS;
201
    /* fall through */
202
203
1.33M
    default:
204
666k
      switch(LOWER_BYTE(*p)) {
205
71.1k
        case 't':
206
71.1k
          switch(LOWER_BYTE(*(p + 1))) {
207
2.37k
            case 'o':
208
2.37k
              p += 2;
209
2.37k
              hdr->type = HDR_TO_T;
210
2.37k
              hdr->name.len = 2;
211
2.37k
              goto dc_cont;
212
1.61k
            case ' ':
213
1.61k
            case '\t':
214
1.61k
              p += 2;
215
1.61k
              hdr->type = HDR_TO_T;
216
1.61k
              hdr->name.len = 1;
217
1.61k
              goto dc_end;
218
53.5k
            case ':':
219
53.5k
              hdr->type = HDR_TO_T;
220
53.5k
              hdr->name.len = 1;
221
53.5k
              return (p + 2);
222
71.1k
          }
223
13.5k
          break;
224
148k
        case 'v': PARSE_COMPACT(HDR_VIA_T);           break;
225
19.0k
        case 'f': PARSE_COMPACT(HDR_FROM_T);          break;
226
15.8k
        case 'i': PARSE_COMPACT(HDR_CALLID_T);        break;
227
28.2k
        case 'm': PARSE_COMPACT(HDR_CONTACT_T);       break;
228
9.29k
        case 'l': PARSE_COMPACT(HDR_CONTENTLENGTH_T); break;
229
6.82k
        case 'k': PARSE_COMPACT(HDR_SUPPORTED_T);     break;
230
45.3k
        case 'c': PARSE_COMPACT(HDR_CONTENTTYPE_T);   break;
231
23.2k
        case 'o': PARSE_COMPACT(HDR_EVENT_T);         break;
232
14.3k
        case 'x': PARSE_COMPACT(HDR_SESSION_EXPIRES_T); break;
233
666k
      }
234
390k
      goto other;
235
1.47M
  }
236
  /* the above swtich will never continue here */
237
238
239
30.5k
 dc_end:
240
  /* HDR name entirely found, consume WS till colon */
241
  /* overflow during the "switch-case" parsing ? */
242
30.5k
  if (p>=end)
243
38
    goto error;
244
30.5k
  p = skip_ws(p, end);
245
30.5k
  if (p >= end || *p != ':')
246
229
    goto error;
247
  /* hdr type, name should be already set at this point */
248
30.2k
  return (p+1);
249
  /*done*/
250
251
252
300k
 dc_cont:
253
  /* HDR name partially found, see what's next */
254
  /* overflow during the "switch-case" parsing ? */
255
300k
  if (p>=end)
256
362
    goto error;
257
  /* hdr type, name should be already set at this point (for partial finding) */
258
299k
  switch (*p) {
259
275k
    case ':' :
260
275k
      return (p+1);
261
1.23k
    case ' ':
262
4.90k
    case '\t':
263
      /* consume spaces to the end of name */
264
4.90k
      p = skip_ws( p+1, end);
265
4.90k
      if (p >= end || *p != ':')
266
42
        goto error;
267
4.86k
      return (p+1);
268
    /* default: it seems the hdr name continues, fall to "other" */
269
299k
  }
270
271
272
815k
 other:
273
  /* Unknown header type */
274
815k
  hdr->type = HDR_OTHER_T;
275
  /* if overflow during the "switch-case" parsing, the "while" will
276
   * exit and we will fall in the "error" section */
277
9.73M
  while ( p < end ) {
278
9.72M
    switch (*p) {
279
777k
      case ':' :
280
777k
        hdr->name.len = p - hdr->name.s;
281
777k
        return (p + 1);
282
26.5k
      case ' ' :
283
30.2k
      case '\t':
284
30.2k
        hdr->name.len = p - hdr->name.s;
285
30.2k
        p = skip_ws(p+1, end);
286
30.2k
        if (p >= end || *p != ':')
287
1.81k
          goto error;
288
28.4k
        return (p+1);
289
9.72M
    }
290
8.91M
    p++;
291
8.91M
  }
292
293
10.3k
 error:
294
  /* No colon found, error.. */
295
10.3k
  hdr->type = HDR_ERROR_T;
296
10.3k
  hdr->name.s = 0;
297
10.3k
  hdr->name.len = 0;
298
10.3k
  return 0;
299
815k
}