Coverage Report

Created: 2026-06-09 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/sieve-binary-code.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "str.h"
6
#include "str-sanitize.h"
7
#include "mempool.h"
8
#include "buffer.h"
9
#include "hash.h"
10
#include "array.h"
11
#include "ostream.h"
12
13
#include "sieve-common.h"
14
#include "sieve-error.h"
15
#include "sieve-extensions.h"
16
#include "sieve-code.h"
17
#include "sieve-script.h"
18
19
#include "sieve-binary-private.h"
20
21
/*
22
 * Forward declarations
23
 */
24
25
static inline sieve_size_t
26
sieve_binary_emit_dynamic_data(struct sieve_binary_block *sblock,
27
             const void *data, size_t size);
28
29
/*
30
 * Emission functions
31
 */
32
33
/* Low-level emission functions */
34
35
static inline void
36
_sieve_binary_emit_data(struct sieve_binary_block *sblock,
37
      const void *data, sieve_size_t size)
38
0
{
39
0
  buffer_append(sblock->data, data, size);
40
0
}
41
42
static inline void
43
_sieve_binary_emit_byte(struct sieve_binary_block *sblock, uint8_t byte)
44
0
{
45
0
  _sieve_binary_emit_data(sblock, &byte, 1);
46
0
}
47
48
static inline void
49
_sieve_binary_update_data(struct sieve_binary_block *sblock,
50
        sieve_size_t address, const void *data,
51
        sieve_size_t size)
52
0
{
53
0
  buffer_write(sblock->data, address, data, size);
54
0
}
55
56
sieve_size_t sieve_binary_emit_data(struct sieve_binary_block *sblock,
57
            const void *data, sieve_size_t size)
58
0
{
59
0
  sieve_size_t address = _sieve_binary_block_get_size(sblock);
60
61
0
  _sieve_binary_emit_data(sblock, data, size);
62
63
0
  return address;
64
0
}
65
66
sieve_size_t sieve_binary_emit_byte(struct sieve_binary_block *sblock,
67
            uint8_t byte)
68
0
{
69
0
  sieve_size_t address = _sieve_binary_block_get_size(sblock);
70
71
0
  _sieve_binary_emit_data(sblock, &byte, 1);
72
73
0
  return address;
74
0
}
75
76
void sieve_binary_update_data(struct sieve_binary_block *sblock,
77
            sieve_size_t address, const void *data,
78
            sieve_size_t size)
79
0
{
80
0
  _sieve_binary_update_data(sblock, address, data, size);
81
0
}
82
83
/* Offset emission functions */
84
85
sieve_size_t sieve_binary_emit_offset(struct sieve_binary_block *sblock,
86
              sieve_offset_t offset)
87
0
{
88
0
  sieve_size_t address = _sieve_binary_block_get_size(sblock);
89
0
  uint8_t encoded[sizeof(offset)];
90
0
  int i;
91
92
0
  for (i = sizeof(offset)-1; i >= 0; i--) {
93
0
    encoded[i] = (uint8_t)offset;
94
0
    offset >>= 8;
95
0
  }
96
97
0
  _sieve_binary_emit_data(sblock, encoded, sizeof(offset));
98
99
0
  return address;
100
0
}
101
102
void sieve_binary_resolve_offset(struct sieve_binary_block *sblock,
103
         sieve_size_t address)
104
0
{
105
0
  sieve_size_t cur_address = _sieve_binary_block_get_size(sblock);
106
0
  sieve_offset_t offset;
107
0
  uint8_t encoded[sizeof(offset)];
108
0
  int i;
109
110
0
  i_assert(cur_address > address);
111
0
  i_assert((cur_address - address) <= (sieve_offset_t)-1);
112
0
  offset = cur_address - address;
113
0
  for (i = sizeof(offset)-1; i >= 0; i--) {
114
0
    encoded[i] = (uint8_t)offset;
115
0
    offset >>= 8;
116
0
  }
117
118
0
  _sieve_binary_update_data(sblock, address, encoded, sizeof(offset));
119
0
}
120
121
/* Literal emission */
122
123
sieve_size_t sieve_binary_emit_integer(struct sieve_binary_block *sblock,
124
               sieve_number_t integer)
125
0
{
126
0
  sieve_size_t address = _sieve_binary_block_get_size(sblock);
127
0
  uint8_t buffer[sizeof(sieve_number_t) + 1];
128
0
  int bufpos = sizeof(buffer) - 1;
129
130
  /* Encode last byte [0xxxxxxx]; msb == 0 marks the last byte */
131
0
  buffer[bufpos] = integer & 0x7F;
132
0
  bufpos--;
133
134
  /* Encode first bytes [1xxxxxxx] */
135
0
  integer >>= 7;
136
0
  while (integer > 0) {
137
0
    buffer[bufpos] = (integer & 0x7F) | 0x80;
138
0
    bufpos--;
139
0
    integer >>= 7;
140
0
  }
141
142
  /* Emit encoded integer */
143
0
  bufpos++;
144
0
  _sieve_binary_emit_data(sblock, buffer + bufpos, sizeof(buffer) - bufpos);
145
146
0
  return address;
147
0
}
148
149
static inline sieve_size_t
150
sieve_binary_emit_dynamic_data(struct sieve_binary_block *sblock,
151
             const void *data, sieve_size_t size)
152
0
{
153
0
  sieve_size_t address =
154
0
    sieve_binary_emit_integer(sblock, (sieve_number_t)size);
155
156
0
  _sieve_binary_emit_data(sblock, data, size);
157
158
0
  return address;
159
0
}
160
161
sieve_size_t sieve_binary_emit_cstring(struct sieve_binary_block *sblock,
162
               const char *str)
163
0
{
164
0
  sieve_size_t address =
165
0
    sieve_binary_emit_dynamic_data(sblock, str,
166
0
                 (sieve_size_t)strlen(str));
167
168
0
  _sieve_binary_emit_byte(sblock, 0);
169
0
  return address;
170
0
}
171
172
sieve_size_t sieve_binary_emit_string(struct sieve_binary_block *sblock,
173
              const string_t *str)
174
0
{
175
0
  sieve_size_t address =
176
0
    sieve_binary_emit_dynamic_data(sblock, str_data(str),
177
0
                 (sieve_size_t)str_len(str));
178
179
0
  _sieve_binary_emit_byte(sblock, 0);
180
0
  return address;
181
0
}
182
183
/*
184
 * Extension emission
185
 */
186
187
sieve_size_t sieve_binary_emit_extension(struct sieve_binary_block *sblock,
188
           const struct sieve_extension *ext,
189
           unsigned int offset)
190
0
{
191
0
  sieve_size_t address = _sieve_binary_block_get_size(sblock);
192
0
  struct sieve_binary_extension_reg *ereg = NULL;
193
194
0
  (void)sieve_binary_extension_register(sblock->sbin, ext, &ereg);
195
196
0
  i_assert(ereg != NULL);
197
198
0
  _sieve_binary_emit_byte(sblock, offset + ereg->index);
199
0
  return address;
200
0
}
201
202
void sieve_binary_emit_extension_object(
203
  struct sieve_binary_block *sblock,
204
  const struct sieve_extension_objects *objs, unsigned int code)
205
0
{
206
0
  if (objs->count > 1)
207
0
    _sieve_binary_emit_byte(sblock, code);
208
0
}
209
210
/*
211
 * Code retrieval
212
 */
213
214
#define ADDR_CODE_READ(block) \
215
0
  size_t _code_size; \
216
0
  const int8_t *_code = buffer_get_data((block)->data, &_code_size)
217
218
#define ADDR_CODE_AT(address) \
219
0
  ((int8_t)(_code[*address]))
220
#define ADDR_DATA_AT(address) \
221
0
  ((uint8_t)(_code[*address]))
222
#define ADDR_POINTER(address) \
223
0
  ((const int8_t *)(&_code[*address]))
224
225
#define ADDR_BYTES_LEFT(address) \
226
0
  ((*address) > _code_size ? 0 : ((_code_size) - (*address)))
227
#define ADDR_JUMP(address, offset) \
228
0
  (*address) += offset
229
230
/* Literals */
231
232
bool sieve_binary_read_byte(struct sieve_binary_block *sblock,
233
          sieve_size_t *address, unsigned int *byte_r)
234
0
{
235
0
  ADDR_CODE_READ(sblock);
236
237
0
  if (ADDR_BYTES_LEFT(address) >= 1) {
238
0
    if (byte_r != NULL)
239
0
      *byte_r = ADDR_DATA_AT(address);
240
0
    ADDR_JUMP(address, 1);
241
242
0
    return TRUE;
243
0
  }
244
245
0
  if (byte_r != NULL)
246
0
    *byte_r = 0;
247
0
  return FALSE;
248
0
}
249
250
bool sieve_binary_read_code(struct sieve_binary_block *sblock,
251
          sieve_size_t *address, signed int *code_r)
252
0
{
253
0
  ADDR_CODE_READ(sblock);
254
255
0
  if (ADDR_BYTES_LEFT(address) >= 1) {
256
0
    if (code_r != NULL)
257
0
      *code_r = ADDR_CODE_AT(address);
258
0
    ADDR_JUMP(address, 1);
259
260
0
    return TRUE;
261
0
  }
262
263
0
  if (code_r != NULL)
264
0
    *code_r = 0;
265
0
  return FALSE;
266
0
}
267
268
269
bool sieve_binary_read_offset(struct sieve_binary_block *sblock,
270
            sieve_size_t *address, sieve_offset_t *offset_r)
271
0
{
272
0
  sieve_offset_t offs = 0;
273
0
  ADDR_CODE_READ(sblock);
274
275
0
  if (ADDR_BYTES_LEFT(address) >= 4) {
276
0
    int i;
277
278
0
    for (i = 0; i < 4; i++) {
279
0
      offs = (offs << 8) + ADDR_DATA_AT(address);
280
0
      ADDR_JUMP(address, 1);
281
0
    }
282
283
0
    if (offset_r != NULL)
284
0
      *offset_r = offs;
285
286
0
    return TRUE;
287
0
  }
288
0
  return FALSE;
289
0
}
290
291
/* FIXME: might need negative numbers in the future */
292
bool sieve_binary_read_integer(struct sieve_binary_block *sblock,
293
             sieve_size_t *address, sieve_number_t *int_r)
294
0
{
295
0
  int bits = sizeof(sieve_number_t) * 8;
296
0
  sieve_number_t integer = 0;
297
298
0
  ADDR_CODE_READ(sblock);
299
300
0
  if (ADDR_BYTES_LEFT(address) == 0)
301
0
    return FALSE;
302
303
  /* Read first integer bytes [1xxxxxxx] */
304
0
  while ((ADDR_DATA_AT(address) & 0x80) > 0) {
305
0
    if (ADDR_BYTES_LEFT(address) > 0 && bits > 0) {
306
0
      integer |= ADDR_DATA_AT(address) & 0x7F;
307
0
      ADDR_JUMP(address, 1);
308
309
      /* Each byte encodes 7 bits of the integer */
310
0
      integer <<= 7;
311
0
      bits -= 7;
312
0
    } else {
313
      /* This is an error */
314
0
      return FALSE;
315
0
    }
316
0
  }
317
318
  /* Read last byte [0xxxxxxx] */
319
0
  integer |= ADDR_DATA_AT(address) & 0x7F;
320
0
  ADDR_JUMP(address, 1);
321
322
0
  if (int_r != NULL)
323
0
    *int_r = integer;
324
0
  return TRUE;
325
0
}
326
327
bool sieve_binary_read_string(struct sieve_binary_block *sblock,
328
            sieve_size_t *address, string_t **str_r)
329
0
{
330
0
  unsigned int strlen = 0;
331
0
  const char *strdata;
332
333
0
  ADDR_CODE_READ(sblock);
334
335
0
  if (!sieve_binary_read_unsigned(sblock, address, &strlen))
336
0
    return FALSE;
337
338
0
  if (strlen > ADDR_BYTES_LEFT(address))
339
0
    return FALSE;
340
341
0
  strdata = (const char *)ADDR_POINTER(address);
342
0
  ADDR_JUMP(address, strlen);
343
344
0
  if (ADDR_CODE_AT(address) != 0)
345
0
    return FALSE;
346
347
0
  if (str_r != NULL)
348
0
    *str_r = t_str_new_const(strdata, strlen);
349
350
0
  ADDR_JUMP(address, 1);
351
352
0
  return TRUE;
353
0
}
354
355
bool sieve_binary_read_extension(struct sieve_binary_block *sblock,
356
         sieve_size_t *address, unsigned int *offset_r,
357
         const struct sieve_extension **ext_r)
358
0
{
359
0
  unsigned int code;
360
0
  unsigned int offset = *offset_r;
361
0
  const struct sieve_extension *ext = NULL;
362
363
0
  ADDR_CODE_READ(sblock);
364
365
0
  if (ADDR_BYTES_LEFT(address) == 0)
366
0
    return FALSE;
367
368
0
  *offset_r = code = ADDR_DATA_AT(address);
369
0
  ADDR_JUMP(address, 1);
370
371
0
  if (code >= offset) {
372
0
    ext = sieve_binary_extension_get_by_index(sblock->sbin,
373
0
                (code - offset));
374
0
    if (ext == NULL)
375
0
      return FALSE;
376
0
  }
377
378
0
  if (ext_r != NULL)
379
0
    *ext_r = ext;
380
0
  return TRUE;
381
0
}
382
383
const void *
384
sieve_binary_read_extension_object(struct sieve_binary_block *sblock,
385
           sieve_size_t *address,
386
           const struct sieve_extension_objects *objs)
387
0
{
388
0
  unsigned int code;
389
390
0
  ADDR_CODE_READ(sblock);
391
392
0
  if (objs->count == 0)
393
0
    return NULL;
394
0
  if (objs->count == 1)
395
0
    return objs->objects;
396
0
  if (ADDR_BYTES_LEFT(address) == 0)
397
0
    return NULL;
398
399
0
  code = ADDR_DATA_AT(address);
400
0
  ADDR_JUMP(address, 1);
401
402
0
  if (code >= objs->count)
403
0
    return NULL;
404
0
  return ((const void *const *)objs->objects)[code];
405
0
}