Coverage Report

Created: 2026-08-31 07:00

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