~ubuntu-branches/ubuntu/saucy/clamav/saucy-backports

« back to all changes in this revision

Viewing changes to libclamav/bytecode_api.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-07-15 01:08:10 UTC
  • mfrom: (0.35.47 sid)
  • Revision ID: package-import@ubuntu.com-20140715010810-ru66ek4fun2iseba
Tags: 0.98.4+dfsg-2~ubuntu13.10.1
No-change backport to saucy (LP: #1341962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
#include <string.h>
34
34
#include <math.h>
35
35
#include <ctype.h>
 
36
 
 
37
#include <openssl/ssl.h>
 
38
#include <openssl/err.h>
 
39
#include "libclamav/crypto.h"
 
40
 
36
41
#include "cltypes.h"
37
42
#include "clambc.h"
38
43
#include "bytecode.h"
70
75
{
71
76
    int n;
72
77
    if (!ctx->fmap) {
73
 
        API_MISUSE();
74
 
        return -1;
 
78
        API_MISUSE();
 
79
        return -1;
75
80
    }
76
81
    if (size < 0 || size > CLI_MAX_ALLOCATION) {
77
 
        cli_warnmsg("bytecode: negative read size: %d\n", size);
78
 
        API_MISUSE();
79
 
        return -1;
 
82
        cli_warnmsg("bytecode: negative read size: %d\n", size);
 
83
        API_MISUSE();
 
84
        return -1;
80
85
    }
81
86
    n = fmap_readn(ctx->fmap, data, ctx->off, size);
82
87
    if (n <= 0) {
83
 
        cli_dbgmsg("bcapi_read: fmap_readn failed (requested %d)\n", size);
84
 
        cli_event_count(EV, BCEV_READ_ERR);
85
 
        return n;
 
88
        cli_dbgmsg("bcapi_read: fmap_readn failed (requested %d)\n", size);
 
89
        cli_event_count(EV, BCEV_READ_ERR);
 
90
        return n;
86
91
    }
87
92
    cli_event_int(EV, BCEV_OFFSET, ctx->off);
88
93
    cli_event_fastdata(EV, BCEV_READ, data, size);
95
100
{
96
101
    off_t off;
97
102
    if (!ctx->fmap) {
98
 
        cli_dbgmsg("bcapi_seek: no fmap\n");
99
 
        API_MISUSE();
100
 
        return -1;
 
103
        cli_dbgmsg("bcapi_seek: no fmap\n");
 
104
        API_MISUSE();
 
105
        return -1;
101
106
    }
102
107
    switch (whence) {
103
 
        case 0:
104
 
            off = pos;
105
 
            break;
106
 
        case 1:
107
 
            off = ctx->off + pos;
108
 
            break;
109
 
        case 2:
110
 
            off = ctx->file_size + pos;
111
 
            break;
112
 
        default:
113
 
            API_MISUSE();
114
 
            cli_dbgmsg("bcapi_seek: invalid whence value\n");
115
 
            return -1;
 
108
        case 0:
 
109
            off = pos;
 
110
            break;
 
111
        case 1:
 
112
            off = ctx->off + pos;
 
113
            break;
 
114
        case 2:
 
115
            off = ctx->file_size + pos;
 
116
            break;
 
117
        default:
 
118
            API_MISUSE();
 
119
            cli_dbgmsg("bcapi_seek: invalid whence value\n");
 
120
            return -1;
116
121
    }
117
122
    if (off < 0 || off > ctx->file_size) {
118
 
        cli_dbgmsg("bcapi_seek: out of file: %ld (max %d)\n",
119
 
                   off, ctx->file_size);
120
 
        return -1;
 
123
        cli_dbgmsg("bcapi_seek: out of file: %ld (max %d)\n",
 
124
                   off, ctx->file_size);
 
125
        return -1;
121
126
    }
122
127
    cli_event_int(EV, BCEV_OFFSET, off);
123
128
    ctx->off = off;
135
140
{
136
141
    cli_event_int(EV, BCEV_DBG_INT, a);
137
142
    if (!cli_debug_flag)
138
 
        return 0;
 
143
        return 0;
139
144
    return fprintf(stderr, "%d", a);
140
145
}
141
146
 
154
159
    const unsigned char *buf;
155
160
    const unsigned char* next;
156
161
    if (!res || !ctx->fmap || ctx->off >= ctx->fmap->len) {
157
 
        API_MISUSE();
158
 
        return -1;
 
162
        API_MISUSE();
 
163
        return -1;
159
164
    }
160
165
    /* 32 should be longest instr we support decoding.
161
166
     * When we'll support mmx/sse instructions this should be updated! */
166
171
    else
167
172
        next = NULL;
168
173
    if (!next) {
169
 
        cli_dbgmsg("bcapi_disasm: failed\n");
170
 
        cli_event_count(EV, BCEV_DISASM_FAIL);
171
 
        return -1;
 
174
        cli_dbgmsg("bcapi_disasm: failed\n");
 
175
        cli_event_count(EV, BCEV_DISASM_FAIL);
 
176
        return -1;
172
177
    }
173
178
    return ctx->off + next - buf;
174
179
}
184
189
 
185
190
    cli_ctx *cctx = (cli_ctx*)ctx->ctx;
186
191
    if (len < 0) {
187
 
        cli_warnmsg("Bytecode API: called with negative length!\n");
188
 
        API_MISUSE();
189
 
        return -1;
 
192
        cli_warnmsg("Bytecode API: called with negative length!\n");
 
193
        API_MISUSE();
 
194
        return -1;
190
195
    }
191
196
    if (!ctx->outfd) {
192
 
        ctx->tempfile = cli_gentemp(cctx ? cctx->engine->tmpdir : NULL);
193
 
        if (!ctx->tempfile) {
194
 
            cli_dbgmsg("Bytecode API: Unable to allocate memory for tempfile\n");
195
 
            cli_event_error_oom(EV, 0);
196
 
            return -1;
197
 
        }
198
 
        ctx->outfd = open(ctx->tempfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
199
 
        if (ctx->outfd == -1) {
200
 
            ctx->outfd = 0;
201
 
            cli_warnmsg("Bytecode API: Can't create file %s: %s\n", ctx->tempfile, cli_strerror(errno, err, sizeof(err)));
202
 
            cli_event_error_str(EV, "cli_bcapi_write: Can't create temporary file");
203
 
            free(ctx->tempfile);
204
 
            return -1;
205
 
        }
206
 
        cli_dbgmsg("bytecode opened new tempfile: %s\n", ctx->tempfile);
 
197
        ctx->tempfile = cli_gentemp(cctx ? cctx->engine->tmpdir : NULL);
 
198
        if (!ctx->tempfile) {
 
199
            cli_dbgmsg("Bytecode API: Unable to allocate memory for tempfile\n");
 
200
            cli_event_error_oom(EV, 0);
 
201
            return -1;
 
202
        }
 
203
        ctx->outfd = open(ctx->tempfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
 
204
        if (ctx->outfd == -1) {
 
205
            ctx->outfd = 0;
 
206
            cli_warnmsg("Bytecode API: Can't create file %s: %s\n", ctx->tempfile, cli_strerror(errno, err, sizeof(err)));
 
207
            cli_event_error_str(EV, "cli_bcapi_write: Can't create temporary file");
 
208
            free(ctx->tempfile);
 
209
            return -1;
 
210
        }
 
211
        cli_dbgmsg("bytecode opened new tempfile: %s\n", ctx->tempfile);
207
212
    }
208
213
 
209
214
    cli_event_fastdata(ctx->bc_events, BCEV_WRITE, data, len);
210
215
    if (cli_checklimits("bytecode api", cctx, ctx->written + len, 0, 0))
211
 
        return -1;
 
216
        return -1;
212
217
    res = cli_writen(ctx->outfd, data, len);
213
218
    if (res > 0) ctx->written += res;
214
219
    if (res == -1) {
215
 
        cli_warnmsg("Bytecode API: write failed: %s\n", cli_strerror(errno, err, sizeof(err)));
216
 
        cli_event_error_str(EV, "cli_bcapi_write: write failed");
 
220
        cli_warnmsg("Bytecode API: write failed: %s\n", cli_strerror(errno, err, sizeof(err)));
 
221
        cli_event_error_str(EV, "cli_bcapi_write: write failed");
217
222
    }
218
223
    return res;
219
224
}
220
225
 
221
226
void cli_bytecode_context_set_trace(struct cli_bc_ctx* ctx, unsigned level,
222
 
                                    bc_dbg_callback_trace trace,
223
 
                                    bc_dbg_callback_trace_op trace_op,
224
 
                                    bc_dbg_callback_trace_val trace_val,
225
 
                                    bc_dbg_callback_trace_ptr trace_ptr)
 
227
                                    bc_dbg_callback_trace trace,
 
228
                                    bc_dbg_callback_trace_op trace_op,
 
229
                                    bc_dbg_callback_trace_val trace_val,
 
230
                                    bc_dbg_callback_trace_ptr trace_ptr)
226
231
{
227
232
    ctx->trace = trace;
228
233
    ctx->trace_op = trace_op;
234
239
uint32_t cli_bcapi_trace_scope(struct cli_bc_ctx *ctx, const uint8_t *scope, uint32_t scopeid)
235
240
{
236
241
    if (LIKELY(!ctx->trace_level))
237
 
        return 0;
 
242
        return 0;
238
243
    if (ctx->scope != (const char*)scope) {
239
 
        ctx->scope = (const char*)scope ? (const char*)scope : "?";
240
 
        ctx->scopeid = scopeid;
241
 
        ctx->trace_level |= 0x80;/* temporarely increase level to print params */
 
244
        ctx->scope = (const char*)scope ? (const char*)scope : "?";
 
245
        ctx->scopeid = scopeid;
 
246
        ctx->trace_level |= 0x80;/* temporarely increase level to print params */
242
247
    } else if ((ctx->trace_level >= trace_scope) && ctx->scopeid != scopeid) {
243
 
        ctx->scopeid = scopeid;
244
 
        ctx->trace_level |= 0x40;/* temporarely increase level to print location */
 
248
        ctx->scopeid = scopeid;
 
249
        ctx->trace_level |= 0x40;/* temporarely increase level to print location */
245
250
    }
246
251
    return 0;
247
252
}
249
254
uint32_t cli_bcapi_trace_directory(struct cli_bc_ctx *ctx, const uint8_t* dir, uint32_t dummy)
250
255
{
251
256
    if (LIKELY(!ctx->trace_level))
252
 
        return 0;
 
257
        return 0;
253
258
    ctx->directory = (const char*)dir ? (const char*)dir : "";
254
259
    return 0;
255
260
}
257
262
uint32_t cli_bcapi_trace_source(struct cli_bc_ctx *ctx, const uint8_t *file, uint32_t line)
258
263
{
259
264
    if (LIKELY(ctx->trace_level < trace_line))
260
 
        return 0;
 
265
        return 0;
261
266
    if (ctx->file != (const char*)file || ctx->line != line) {
262
 
        ctx->col = 0;
263
 
        ctx->file =(const char*)file ? (const char*)file : "??";
264
 
        ctx->line = line;
 
267
        ctx->col = 0;
 
268
        ctx->file =(const char*)file ? (const char*)file : "??";
 
269
        ctx->line = line;
265
270
    }
266
271
    return 0;
267
272
}
269
274
uint32_t cli_bcapi_trace_op(struct cli_bc_ctx *ctx, const uint8_t *op, uint32_t col)
270
275
{
271
276
    if (LIKELY(ctx->trace_level < trace_col))
272
 
        return 0;
 
277
        return 0;
273
278
    if (ctx->trace_level&0xc0) {
274
 
        ctx->col = col;
275
 
        /* func/scope changed and they needed param/location event */
276
 
        ctx->trace(ctx, (ctx->trace_level&0x80) ? trace_func : trace_scope);
277
 
        ctx->trace_level &= ~0xc0;
 
279
        ctx->col = col;
 
280
        /* func/scope changed and they needed param/location event */
 
281
        ctx->trace(ctx, (ctx->trace_level&0x80) ? trace_func : trace_scope);
 
282
        ctx->trace_level &= ~0xc0;
278
283
    }
279
284
    if (LIKELY(ctx->trace_level < trace_col))
280
 
        return 0;
 
285
        return 0;
281
286
    if (ctx->col != col) {
282
 
        ctx->col = col;
283
 
        ctx->trace(ctx, trace_col);
 
287
        ctx->col = col;
 
288
        ctx->trace(ctx, trace_col);
284
289
    } else {
285
 
        ctx->trace(ctx, trace_line);
 
290
        ctx->trace(ctx, trace_line);
286
291
    }
287
292
    if (LIKELY(ctx->trace_level < trace_op))
288
 
        return 0;
 
293
        return 0;
289
294
    if (ctx->trace_op && op)
290
 
        ctx->trace_op(ctx, (const char*)op);
 
295
        ctx->trace_op(ctx, (const char*)op);
291
296
    return 0;
292
297
}
293
298
 
294
299
uint32_t cli_bcapi_trace_value(struct cli_bc_ctx *ctx, const uint8_t* name, uint32_t value)
295
300
{
296
301
    if (LIKELY(ctx->trace_level < trace_val))
297
 
        return 0;
 
302
        return 0;
298
303
    if (ctx->trace_level&0x80) {
299
 
        if ((ctx->trace_level&0x7f) < trace_param)
300
 
            return 0;
301
 
        ctx->trace(ctx, trace_param);
 
304
        if ((ctx->trace_level&0x7f) < trace_param)
 
305
            return 0;
 
306
        ctx->trace(ctx, trace_param);
302
307
    }
303
308
    if (ctx->trace_val && name)
304
 
        ctx->trace_val(ctx, (const char*)name, value);
 
309
        ctx->trace_val(ctx, (const char*)name, value);
305
310
    return 0;
306
311
}
307
312
 
308
313
uint32_t cli_bcapi_trace_ptr(struct cli_bc_ctx *ctx, const uint8_t* ptr, uint32_t dummy)
309
314
{
310
315
    if (LIKELY(ctx->trace_level < trace_val))
311
 
        return 0;
 
316
        return 0;
312
317
    if (ctx->trace_level&0x80) {
313
 
        if ((ctx->trace_level&0x7f) < trace_param)
314
 
            return 0;
315
 
        ctx->trace(ctx, trace_param);
 
318
        if ((ctx->trace_level&0x7f) < trace_param)
 
319
            return 0;
 
320
        ctx->trace(ctx, trace_param);
316
321
    }
317
322
    if (ctx->trace_ptr)
318
 
        ctx->trace_ptr(ctx, ptr);
 
323
        ctx->trace_ptr(ctx, ptr);
319
324
    return 0;
320
325
}
321
326
 
325
330
  unsigned err = 0;
326
331
  const struct cli_pe_hook_data *pe = ctx->hooks.pedata;
327
332
  ret = cli_rawaddr(rva, ctx->sections, pe->nsections, &err,
328
 
                    ctx->file_size, pe->hdr_size);
 
333
                    ctx->file_size, pe->hdr_size);
329
334
  if (err) {
330
335
    cli_dbgmsg("bcapi_pe_rawaddr invalid rva: %u\n", rva);
331
336
    return PE_INVALID_RVA;
334
339
}
335
340
 
336
341
static inline const char* cli_memmem(const char *haystack, unsigned hlen,
337
 
                                     const unsigned char *needle, unsigned nlen)
 
342
                                     const unsigned char *needle, unsigned nlen)
338
343
{
339
344
    const char *p;
340
345
    unsigned char c;
341
346
    if (!needle || !haystack) {
342
 
        return NULL;
 
347
        return NULL;
343
348
    }
344
349
    c = *needle++;
345
350
    if (nlen == 1)
346
 
        return memchr(haystack, c, hlen);
 
351
        return memchr(haystack, c, hlen);
347
352
 
348
353
    while (hlen >= nlen) {
349
 
        p = haystack;
350
 
        haystack = memchr(haystack, c, hlen - nlen + 1);
351
 
        if (!haystack)
352
 
            return NULL;
353
 
        hlen -= haystack+1 - p;
354
 
        p = haystack + 1;
355
 
        if (!memcmp(p, needle, nlen-1))
356
 
            return haystack;
357
 
        haystack = p;
 
354
        p = haystack;
 
355
        haystack = memchr(haystack, c, hlen - nlen + 1);
 
356
        if (!haystack)
 
357
            return NULL;
 
358
        hlen -= haystack+1 - p;
 
359
        p = haystack + 1;
 
360
        if (!memcmp(p, needle, nlen-1))
 
361
            return haystack;
 
362
        haystack = p;
358
363
    }
359
364
    return NULL;
360
365
}
363
368
{
364
369
    fmap_t *map = ctx->fmap;
365
370
    if (!map || len <= 0) {
366
 
        cli_dbgmsg("bcapi_file_find preconditions not met\n");
367
 
        API_MISUSE();
368
 
        return -1;
 
371
        cli_dbgmsg("bcapi_file_find preconditions not met\n");
 
372
        API_MISUSE();
 
373
        return -1;
369
374
    }
370
375
    return cli_bcapi_file_find_limit(ctx, data, len, map->len);
371
376
}
378
383
    int n;
379
384
 
380
385
    if (!map || len > sizeof(buf)/4 || len <= 0 || limit <= 0) {
381
 
        cli_dbgmsg("bcapi_file_find_limit preconditions not met\n");
382
 
        API_MISUSE();
383
 
        return -1;
 
386
        cli_dbgmsg("bcapi_file_find_limit preconditions not met\n");
 
387
        API_MISUSE();
 
388
        return -1;
384
389
    }
385
390
 
386
391
    cli_event_int(EV, BCEV_OFFSET, off);
387
392
    cli_event_fastdata(EV, BCEV_FIND, data, len);
388
393
    for (;;) {
389
 
        const char *p;
390
 
        int32_t readlen = sizeof(buf);
391
 
        if (off + readlen > limit) {
392
 
            readlen = limit - off;
393
 
            if (readlen < 0)
394
 
                return -1;
395
 
        }
396
 
        n = fmap_readn(map, buf, off, readlen);
397
 
        if ((unsigned)n < len || n < 0)
398
 
            return -1;
399
 
        p = cli_memmem(buf, n, data, len);
400
 
        if (p)
401
 
            return off + p - buf;
402
 
        off += n;
 
394
        const char *p;
 
395
        int32_t readlen = sizeof(buf);
 
396
        if (off + readlen > limit) {
 
397
            readlen = limit - off;
 
398
            if (readlen < 0)
 
399
                return -1;
 
400
        }
 
401
        n = fmap_readn(map, buf, off, readlen);
 
402
        if ((unsigned)n < len || n < 0)
 
403
            return -1;
 
404
        p = cli_memmem(buf, n, data, len);
 
405
        if (p)
 
406
            return off + p - buf;
 
407
        off += n;
403
408
    }
404
409
    return -1;
405
410
}
408
413
{
409
414
    unsigned char c;
410
415
    if (!ctx->fmap) {
411
 
        cli_dbgmsg("bcapi_file_byteat: no fmap\n");
412
 
        return -1;
 
416
        cli_dbgmsg("bcapi_file_byteat: no fmap\n");
 
417
        return -1;
413
418
    }
414
419
    cli_event_int(EV, BCEV_OFFSET, off);
415
420
    if (fmap_readn(ctx->fmap, &c, off, 1) != 1) {
416
 
        cli_dbgmsg("bcapi_file_byteat: fmap_readn failed at %u\n", off);
417
 
        return -1;
 
421
        cli_dbgmsg("bcapi_file_byteat: fmap_readn failed at %u\n", off);
 
422
        return -1;
418
423
    }
419
424
    return c;
420
425
}
424
429
    void *v;
425
430
#if USE_MPOOL
426
431
    if (!ctx->mpool) {
427
 
        ctx->mpool = mpool_create();
428
 
        if (!ctx->mpool) {
429
 
            cli_dbgmsg("bytecode: mpool_create failed!\n");
430
 
            cli_event_error_oom(EV, 0);
431
 
            return NULL;
432
 
        }
 
432
        ctx->mpool = mpool_create();
 
433
        if (!ctx->mpool) {
 
434
            cli_dbgmsg("bytecode: mpool_create failed!\n");
 
435
            cli_event_error_oom(EV, 0);
 
436
            return NULL;
 
437
        }
433
438
    }
434
439
    v = mpool_malloc(ctx->mpool, size);
435
440
#else
438
443
    v = cli_malloc(size);
439
444
#endif
440
445
    if (!v)
441
 
        cli_event_error_oom(EV, size);
 
446
        cli_event_error_oom(EV, size);
442
447
    return v;
443
448
}
444
449
 
445
450
int32_t cli_bcapi_get_pe_section(struct cli_bc_ctx *ctx, void* section, uint32_t num)
446
451
{
447
452
    if (num < ctx->hooks.pedata->nsections) {
448
 
        memcpy(section, &ctx->sections[num], sizeof(struct cli_exe_section));
449
 
        return 0;
 
453
        memcpy(section, &ctx->sections[num], sizeof(struct cli_exe_section));
 
454
        return 0;
450
455
    }
451
456
    return -1;
452
457
}
453
458
 
454
459
int32_t cli_bcapi_fill_buffer(struct cli_bc_ctx *ctx, uint8_t* buf,
455
 
                              uint32_t buflen, uint32_t filled,
456
 
                              uint32_t pos, uint32_t fill)
 
460
                              uint32_t buflen, uint32_t filled,
 
461
                              uint32_t pos, uint32_t fill)
457
462
{
458
463
    int32_t res, remaining, tofill;
459
464
    if (!buf || !buflen || buflen > CLI_MAX_ALLOCATION || filled > buflen) {
460
 
        cli_dbgmsg("fill_buffer1\n");
461
 
        API_MISUSE();
462
 
        return -1;
 
465
        cli_dbgmsg("fill_buffer1\n");
 
466
        API_MISUSE();
 
467
        return -1;
463
468
    }
464
469
    if (ctx->off >= ctx->file_size) {
465
 
        cli_dbgmsg("fill_buffer2\n");
466
 
        API_MISUSE();
467
 
        return 0;
 
470
        cli_dbgmsg("fill_buffer2\n");
 
471
        API_MISUSE();
 
472
        return 0;
468
473
    }
469
474
    remaining = filled - pos;
470
475
    if (remaining) {
471
 
        if (!CLI_ISCONTAINED(buf, buflen, buf+pos, remaining)) {
472
 
            cli_dbgmsg("fill_buffer3\n");
473
 
            API_MISUSE();
474
 
            return -1;
475
 
        }
476
 
        memmove(buf, buf+pos, remaining);
 
476
        if (!CLI_ISCONTAINED(buf, buflen, buf+pos, remaining)) {
 
477
            cli_dbgmsg("fill_buffer3\n");
 
478
            API_MISUSE();
 
479
            return -1;
 
480
        }
 
481
        memmove(buf, buf+pos, remaining);
477
482
    }
478
483
    tofill = buflen - remaining;
479
484
    if (!CLI_ISCONTAINED(buf, buflen, buf+remaining, tofill)) {
480
 
        cli_dbgmsg("fill_buffer4\n");
481
 
        API_MISUSE();
482
 
        return -1;
 
485
        cli_dbgmsg("fill_buffer4\n");
 
486
        API_MISUSE();
 
487
        return -1;
483
488
    }
484
489
    res = cli_bcapi_read(ctx, buf+remaining, tofill);
485
490
    if (res <= 0) {
486
 
        cli_dbgmsg("fill_buffer5\n");
487
 
        API_MISUSE();
488
 
        return res;
 
491
        cli_dbgmsg("fill_buffer5\n");
 
492
        API_MISUSE();
 
493
        return res;
489
494
    }
490
495
    return remaining + res;
491
496
}
498
503
    cli_event_count(EV, BCEV_EXTRACTED);
499
504
    cli_dbgmsg("previous tempfile had %u bytes\n", ctx->written);
500
505
    if (!ctx->written)
501
 
        return 0;
 
506
        return 0;
502
507
    if (ctx->ctx && cli_updatelimits(ctx->ctx, ctx->written))
503
 
        return -1;
 
508
        return -1;
504
509
    ctx->written = 0;
505
510
    if (lseek(ctx->outfd, 0, SEEK_SET) == -1) {
506
511
        cli_dbgmsg("bytecode: call to lseek() has failed\n");
509
514
    cli_dbgmsg("bytecode: scanning extracted file %s\n", ctx->tempfile);
510
515
    cctx = (cli_ctx*)ctx->ctx;
511
516
    if (cctx) {
512
 
        cli_file_t current = cctx->container_type;
513
 
        if (ctx->containertype != CL_TYPE_ANY)
514
 
            cctx->container_type = ctx->containertype;
515
 
        cctx->recursion++;
516
 
        res = cli_magic_scandesc(ctx->outfd, cctx);
517
 
        cctx->recursion--;
518
 
        cctx->container_type = current;
519
 
        if (res == CL_VIRUS) {
520
 
            ctx->virname = cli_get_last_virus(cctx);
521
 
            ctx->found = 1;
522
 
        }
 
517
        cli_file_t current = cctx->container_type;
 
518
        if (ctx->containertype != CL_TYPE_ANY)
 
519
            cctx->container_type = ctx->containertype;
 
520
        cctx->recursion++;
 
521
        res = cli_magic_scandesc(ctx->outfd, cctx);
 
522
        cctx->recursion--;
 
523
        cctx->container_type = current;
 
524
        if (res == CL_VIRUS) {
 
525
            ctx->virname = cli_get_last_virus(cctx);
 
526
            ctx->found = 1;
 
527
        }
523
528
    }
524
529
    if ((cctx && cctx->engine->keeptmp) ||
525
 
        (ftruncate(ctx->outfd, 0) == -1)) {
 
530
        (ftruncate(ctx->outfd, 0) == -1)) {
526
531
 
527
 
        close(ctx->outfd);
528
 
        if (!(cctx && cctx->engine->keeptmp) && ctx->tempfile)
529
 
            cli_unlink(ctx->tempfile);
530
 
        free(ctx->tempfile);
531
 
        ctx->tempfile = NULL;
532
 
        ctx->outfd = 0;
 
532
        close(ctx->outfd);
 
533
        if (!(cctx && cctx->engine->keeptmp) && ctx->tempfile)
 
534
            cli_unlink(ctx->tempfile);
 
535
        free(ctx->tempfile);
 
536
        ctx->tempfile = NULL;
 
537
        ctx->outfd = 0;
533
538
    }
534
539
    cli_dbgmsg("bytecode: extracting new file with id %u\n", id);
535
540
    return res;
543
548
    int32_t result;
544
549
 
545
550
    if ((radix != 10 && radix != 16) || !ctx->fmap)
546
 
        return -1;
 
551
        return -1;
547
552
    cli_event_int(EV, BCEV_OFFSET, ctx->off);
548
553
    while ((p = fmap_need_off_once(ctx->fmap, ctx->off, BUF))) {
549
 
        for (i=0;i<BUF;i++) {
550
 
            if ((p[i] >= '0' && p[i] <= '9') || (radix == 16 && ((p[i] >= 'a' && p[i] <= 'f') || (p[i] >= 'A' && p[i] <= 'F')))) {
551
 
                char *endptr;
552
 
                p = fmap_need_ptr_once(ctx->fmap, p+i, 16);
553
 
                if (!p)
554
 
                    return -1;
555
 
                result = strtoul(p, &endptr, radix);
556
 
                ctx->off += i + (endptr - p);
557
 
                return result;
558
 
            }
559
 
        }
560
 
        ctx->off += BUF;
 
554
        for (i=0;i<BUF;i++) {
 
555
            if ((p[i] >= '0' && p[i] <= '9') || (radix == 16 && ((p[i] >= 'a' && p[i] <= 'f') || (p[i] >= 'A' && p[i] <= 'F')))) {
 
556
                char *endptr;
 
557
                p = fmap_need_ptr_once(ctx->fmap, p+i, 16);
 
558
                if (!p)
 
559
                    return -1;
 
560
                result = strtoul(p, &endptr, radix);
 
561
                ctx->off += i + (endptr - p);
 
562
                return result;
 
563
            }
 
564
        }
 
565
        ctx->off += BUF;
561
566
    }
562
567
    return -1;
563
568
}
567
572
    unsigned  n = ctx->nhashsets+1;
568
573
    struct cli_hashset *s = cli_realloc(ctx->hashsets, sizeof(*ctx->hashsets)*n);
569
574
    if (!s) {
570
 
        cli_event_error_oom(EV, 0);
571
 
        return -1;
 
575
        cli_event_error_oom(EV, 0);
 
576
        return -1;
572
577
    }
573
578
    ctx->hashsets = s;
574
579
    ctx->nhashsets = n;
580
585
static struct cli_hashset *get_hashset(struct cli_bc_ctx *ctx, int32_t id)
581
586
{
582
587
    if (id < 0 || id >= ctx->nhashsets || !ctx->hashsets) {
583
 
        API_MISUSE();
584
 
        return NULL;
 
588
        API_MISUSE();
 
589
        return NULL;
585
590
    }
586
591
    return &ctx->hashsets[id];
587
592
}
590
595
{
591
596
    struct cli_hashset *s = get_hashset(ctx, id);
592
597
    if (!s)
593
 
        return -1;
 
598
        return -1;
594
599
    return cli_hashset_addkey(s, key);
595
600
}
596
601
 
598
603
{
599
604
    struct cli_hashset *s = get_hashset(ctx, id);
600
605
    if (!s)
601
 
        return -1;
 
606
        return -1;
602
607
    return cli_hashset_removekey(s, key);
603
608
}
604
609
 
606
611
{
607
612
    struct cli_hashset *s = get_hashset(ctx, id);
608
613
    if (!s)
609
 
        return -1;
 
614
        return -1;
610
615
    return cli_hashset_contains(s, key);
611
616
}
612
617
 
620
625
{
621
626
    struct cli_hashset *s = get_hashset(ctx, id);
622
627
    if (!s)
623
 
        return -1;
 
628
        return -1;
624
629
    cli_hashset_destroy(s);
625
630
    if (id == ctx->nhashsets-1) {
626
 
        ctx->nhashsets--;
627
 
        if (!ctx->nhashsets) {
628
 
            free(ctx->hashsets);
629
 
            ctx->hashsets = NULL;
630
 
        } else {
631
 
            s = cli_realloc(ctx->hashsets, ctx->nhashsets*sizeof(*s));
632
 
            if (s)
633
 
                ctx->hashsets = s;
634
 
        }
 
631
        ctx->nhashsets--;
 
632
        if (!ctx->nhashsets) {
 
633
            free(ctx->hashsets);
 
634
            ctx->hashsets = NULL;
 
635
        } else {
 
636
            s = cli_realloc(ctx->hashsets, ctx->nhashsets*sizeof(*s));
 
637
            if (s)
 
638
                ctx->hashsets = s;
 
639
        }
635
640
    }
636
641
    return 0;
637
642
}
644
649
 
645
650
    data = cli_calloc(1, size);
646
651
    if (!data)
647
 
        return -1;
 
652
        return -1;
648
653
    b = cli_realloc(ctx->buffers, sizeof(*ctx->buffers)*n);
649
654
    if (!b) {
650
 
        free(data);
651
 
        return -1;
 
655
        free(data);
 
656
        return -1;
652
657
    }
653
658
    ctx->buffers = b;
654
659
    ctx->nbuffers = n;
666
671
    unsigned n = ctx->nbuffers + 1;
667
672
 
668
673
    if (at >= ctx->file_size)
669
 
        return -1;
 
674
        return -1;
670
675
 
671
676
    b = cli_realloc(ctx->buffers, sizeof(*ctx->buffers)*n);
672
677
    if (!b) {
673
 
        return -1;
 
678
        return -1;
674
679
    }
675
680
    ctx->buffers = b;
676
681
    ctx->nbuffers = n;
687
692
static struct bc_buffer *get_buffer(struct cli_bc_ctx *ctx, int32_t id)
688
693
{
689
694
    if (!ctx->buffers || id < 0 || id >= ctx->nbuffers) {
690
 
        cli_dbgmsg("bytecode api: invalid buffer id %u\n", id);
691
 
        return NULL;
 
695
        cli_dbgmsg("bytecode api: invalid buffer id %u\n", id);
 
696
        return NULL;
692
697
    }
693
698
    return &ctx->buffers[id];
694
699
}
697
702
{
698
703
    struct bc_buffer *b = get_buffer(ctx, id);
699
704
    if (!b)
700
 
        return 0;
 
705
        return 0;
701
706
    if (b->data) {
702
 
        if (b->write_cursor <= b->read_cursor)
703
 
            return 0;
704
 
        return b->write_cursor - b->read_cursor;
 
707
        if (b->write_cursor <= b->read_cursor)
 
708
            return 0;
 
709
        return b->write_cursor - b->read_cursor;
705
710
    }
706
711
    if (!ctx->fmap || b->read_cursor >= ctx->file_size)
707
 
        return 0;
 
712
        return 0;
708
713
    if (b->read_cursor + BUFSIZ <= ctx->file_size)
709
 
        return BUFSIZ;
 
714
        return BUFSIZ;
710
715
    return ctx->file_size - b->read_cursor;
711
716
}
712
717
 
714
719
{
715
720
    struct bc_buffer *b = get_buffer(ctx, id);
716
721
    if (!b || size > cli_bcapi_buffer_pipe_read_avail(ctx, id) || !size)
717
 
        return NULL;
 
722
        return NULL;
718
723
    if (b->data)
719
 
        return b->data + b->read_cursor;
 
724
        return b->data + b->read_cursor;
720
725
    return fmap_need_off(ctx->fmap, b->read_cursor, size);
721
726
}
722
727
 
724
729
{
725
730
    struct bc_buffer *b = get_buffer(ctx, id);
726
731
    if (!b)
727
 
        return -1;
 
732
        return -1;
728
733
    if (b->data) {
729
 
        if (b->write_cursor <= b->read_cursor)
730
 
            return -1;
731
 
        if (b->read_cursor + amount > b->write_cursor)
732
 
            b->read_cursor = b->write_cursor;
733
 
        else
734
 
            b->read_cursor += amount;
735
 
        if (b->read_cursor >= b->size &&
736
 
            b->write_cursor >= b->size)
737
 
            b->read_cursor = b->write_cursor = 0;
738
 
        return 0;
 
734
        if (b->write_cursor <= b->read_cursor)
 
735
            return -1;
 
736
        if (b->read_cursor + amount > b->write_cursor)
 
737
            b->read_cursor = b->write_cursor;
 
738
        else
 
739
            b->read_cursor += amount;
 
740
        if (b->read_cursor >= b->size &&
 
741
            b->write_cursor >= b->size)
 
742
            b->read_cursor = b->write_cursor = 0;
 
743
        return 0;
739
744
    }
740
745
    b->read_cursor += amount;
741
746
    return 0;
745
750
{
746
751
    struct bc_buffer *b = get_buffer(ctx, id);
747
752
    if (!b)
748
 
        return 0;
 
753
        return 0;
749
754
    if (!b->data)
750
 
        return 0;
 
755
        return 0;
751
756
    if (b->write_cursor >= b->size)
752
 
        return 0;
 
757
        return 0;
753
758
    return b->size - b->write_cursor;
754
759
}
755
760
 
757
762
{
758
763
    struct bc_buffer *b = get_buffer(ctx, id);
759
764
    if (!b || size > cli_bcapi_buffer_pipe_write_avail(ctx, id) || !size)
760
 
        return NULL;
 
765
        return NULL;
761
766
    if (!b->data)
762
 
        return NULL;
 
767
        return NULL;
763
768
    return b->data + b->write_cursor;
764
769
}
765
770
 
767
772
{
768
773
    struct bc_buffer *b = get_buffer(ctx, id);
769
774
    if (!b || !b->data)
770
 
        return -1;
 
775
        return -1;
771
776
    if (b->write_cursor + size >= b->size)
772
 
        b->write_cursor = b->size;
 
777
        b->write_cursor = b->size;
773
778
    else
774
 
        b->write_cursor += size;
 
779
        b->write_cursor += size;
775
780
    return 0;
776
781
}
777
782
 
779
784
{
780
785
    struct bc_buffer *b = get_buffer(ctx, id);
781
786
    if (!b)
782
 
        return -1;
 
787
        return -1;
783
788
    free(b->data);
784
789
    b->data = NULL;
785
790
    return -0;
792
797
    struct bc_inflate *b;
793
798
    unsigned n = ctx->ninflates + 1;
794
799
    if (!get_buffer(ctx, from) || !get_buffer(ctx, to)) {
795
 
        cli_dbgmsg("bytecode api: inflate_init: invalid buffers!\n");
796
 
        return -1;
 
800
        cli_dbgmsg("bytecode api: inflate_init: invalid buffers!\n");
 
801
        return -1;
797
802
    }
798
803
    memset(&stream, 0, sizeof(stream));
799
804
    ret = inflateInit2(&stream, windowBits);
800
805
    switch (ret) {
801
 
        case Z_MEM_ERROR:
802
 
            cli_dbgmsg("bytecode api: inflateInit2: out of memory!\n");
803
 
            return -1;
804
 
        case Z_VERSION_ERROR:
805
 
            cli_dbgmsg("bytecode api: inflateinit2: zlib version error!\n");
806
 
            return -1;
807
 
        case Z_STREAM_ERROR:
808
 
            cli_dbgmsg("bytecode api: inflateinit2: zlib stream error!\n");
809
 
            return -1;
810
 
        case Z_OK:
811
 
            break;
812
 
        default:
813
 
            cli_dbgmsg("bytecode api: inflateInit2: unknown error %d\n", ret);
814
 
            return -1;
 
806
        case Z_MEM_ERROR:
 
807
            cli_dbgmsg("bytecode api: inflateInit2: out of memory!\n");
 
808
            return -1;
 
809
        case Z_VERSION_ERROR:
 
810
            cli_dbgmsg("bytecode api: inflateinit2: zlib version error!\n");
 
811
            return -1;
 
812
        case Z_STREAM_ERROR:
 
813
            cli_dbgmsg("bytecode api: inflateinit2: zlib stream error!\n");
 
814
            return -1;
 
815
        case Z_OK:
 
816
            break;
 
817
        default:
 
818
            cli_dbgmsg("bytecode api: inflateInit2: unknown error %d\n", ret);
 
819
            return -1;
815
820
    }
816
821
 
817
822
    b = cli_realloc(ctx->inflates, sizeof(*ctx->inflates)*n);
818
823
    if (!b) {
819
 
        inflateEnd(&stream);
820
 
        return -1;
 
824
        inflateEnd(&stream);
 
825
        return -1;
821
826
    }
822
827
    ctx->inflates = b;
823
828
    ctx->ninflates = n;
833
838
static struct bc_inflate *get_inflate(struct cli_bc_ctx *ctx, int32_t id)
834
839
{
835
840
    if (id < 0 || id >= ctx->ninflates || !ctx->inflates)
836
 
        return NULL;
 
841
        return NULL;
837
842
    return &ctx->inflates[id];
838
843
}
839
844
 
843
848
    unsigned avail_in_orig, avail_out_orig;
844
849
    struct bc_inflate *b = get_inflate(ctx, id);
845
850
    if (!b || b->from == -1 || b->to == -1)
846
 
        return -1;
 
851
        return -1;
847
852
 
848
853
    b->stream.avail_in = avail_in_orig =
849
 
        cli_bcapi_buffer_pipe_read_avail(ctx, b->from);
 
854
        cli_bcapi_buffer_pipe_read_avail(ctx, b->from);
850
855
 
851
856
    b->stream.next_in = (void*)cli_bcapi_buffer_pipe_read_get(ctx, b->from,
852
 
                                                       b->stream.avail_in);
 
857
                                                       b->stream.avail_in);
853
858
 
854
859
    b->stream.avail_out = avail_out_orig =
855
 
        cli_bcapi_buffer_pipe_write_avail(ctx, b->to);
 
860
        cli_bcapi_buffer_pipe_write_avail(ctx, b->to);
856
861
 
857
862
    b->stream.next_out = cli_bcapi_buffer_pipe_write_get(ctx, b->to,
858
 
                                                         b->stream.avail_out);
 
863
                                                         b->stream.avail_out);
859
864
 
860
865
    if (!b->stream.avail_in || !b->stream.avail_out || !b->stream.next_in || !b->stream.next_out)
861
 
        return -1;
 
866
        return -1;
862
867
    /* try hard to extract data, skipping over corrupted data */
863
868
    do {
864
 
        if (!b->needSync) {
865
 
            ret = inflate(&b->stream, Z_NO_FLUSH);
866
 
            if (ret == Z_DATA_ERROR) {
867
 
                cli_dbgmsg("bytecode api: inflate at %lu: %s, trying to recover\n", b->stream.total_in,
868
 
                           b->stream.msg);
869
 
                b->needSync = 1;
870
 
            }
871
 
        }
872
 
        if (b->needSync) {
873
 
            ret = inflateSync(&b->stream);
874
 
            if (ret == Z_OK) {
875
 
                cli_dbgmsg("bytecode api: successfully recovered inflate stream\n");
876
 
                b->needSync = 0;
877
 
                continue;
878
 
            }
879
 
        }
880
 
        break;
 
869
        if (!b->needSync) {
 
870
            ret = inflate(&b->stream, Z_NO_FLUSH);
 
871
            if (ret == Z_DATA_ERROR) {
 
872
                cli_dbgmsg("bytecode api: inflate at %lu: %s, trying to recover\n", b->stream.total_in,
 
873
                           b->stream.msg);
 
874
                b->needSync = 1;
 
875
            }
 
876
        }
 
877
        if (b->needSync) {
 
878
            ret = inflateSync(&b->stream);
 
879
            if (ret == Z_OK) {
 
880
                cli_dbgmsg("bytecode api: successfully recovered inflate stream\n");
 
881
                b->needSync = 0;
 
882
                continue;
 
883
            }
 
884
        }
 
885
        break;
881
886
    } while (1);
882
887
    cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail_in_orig - b->stream.avail_in);
883
888
    cli_bcapi_buffer_pipe_write_stopped(ctx, b->to, avail_out_orig - b->stream.avail_out);
884
889
 
885
890
    if (ret == Z_MEM_ERROR) {
886
 
        cli_dbgmsg("bytecode api: out of memory!\n");
887
 
        cli_bcapi_inflate_done(ctx, id);
888
 
        return ret;
 
891
        cli_dbgmsg("bytecode api: out of memory!\n");
 
892
        cli_bcapi_inflate_done(ctx, id);
 
893
        return ret;
889
894
    }
890
895
    if (ret == Z_STREAM_END) {
891
 
        cli_bcapi_inflate_done(ctx, id);
 
896
        cli_bcapi_inflate_done(ctx, id);
892
897
    }
893
898
    if (ret == Z_BUF_ERROR) {
894
 
        cli_dbgmsg("bytecode api: buffer error!\n");
 
899
        cli_dbgmsg("bytecode api: buffer error!\n");
895
900
    }
896
901
 
897
902
    return ret;
902
907
    int ret;
903
908
    struct bc_inflate *b = get_inflate(ctx, id);
904
909
    if (!b || b->from == -1 || b->to == -1)
905
 
        return -1;
 
910
        return -1;
906
911
    ret = inflateEnd(&b->stream);
907
912
    if (ret == Z_STREAM_ERROR)
908
 
        cli_dbgmsg("bytecode api: inflateEnd: %s\n", b->stream.msg);
 
913
        cli_dbgmsg("bytecode api: inflateEnd: %s\n", b->stream.msg);
909
914
    b->from = b->to = -1;
910
915
    return ret;
911
916
}
924
929
    struct bc_jsnorm *b;
925
930
    unsigned  n = ctx->njsnorms + 1;
926
931
    if (!get_buffer(ctx, from)) {
927
 
        cli_dbgmsg("bytecode api: jsnorm_init: invalid buffers!\n");
928
 
        return -1;
 
932
        cli_dbgmsg("bytecode api: jsnorm_init: invalid buffers!\n");
 
933
        return -1;
929
934
    }
930
935
    state = cli_js_init();
931
936
    if (!state)
932
 
        return -1;
 
937
        return -1;
933
938
    b = cli_realloc(ctx->jsnorms, sizeof(*ctx->jsnorms)*n);
934
939
    if (!b) {
935
 
        cli_js_destroy(state);
936
 
        return -1;
 
940
        cli_js_destroy(state);
 
941
        return -1;
937
942
    }
938
943
    ctx->jsnorms = b;
939
944
    ctx->njsnorms = n;
941
946
    b->from = from;
942
947
    b->state = state;
943
948
    if (!ctx->jsnormdir) {
944
 
        cli_ctx *cctx = (cli_ctx*)ctx->ctx;
945
 
        ctx->jsnormdir = cli_gentemp(cctx ? cctx->engine->tmpdir : NULL);
946
 
        if (ctx->jsnormdir) {
947
 
            if (mkdir(ctx->jsnormdir, 0700)) {
948
 
                cli_dbgmsg("js: can't create temp dir %s\n", ctx->jsnormdir);
949
 
                free(ctx->jsnormdir);
950
 
                return CL_ETMPDIR;
951
 
            }
952
 
        }
 
949
        cli_ctx *cctx = (cli_ctx*)ctx->ctx;
 
950
        ctx->jsnormdir = cli_gentemp(cctx ? cctx->engine->tmpdir : NULL);
 
951
        if (ctx->jsnormdir) {
 
952
            if (mkdir(ctx->jsnormdir, 0700)) {
 
953
                cli_dbgmsg("js: can't create temp dir %s\n", ctx->jsnormdir);
 
954
                free(ctx->jsnormdir);
 
955
                return CL_ETMPDIR;
 
956
            }
 
957
        }
953
958
    }
954
959
    return n-1;
955
960
}
957
962
static struct bc_jsnorm *get_jsnorm(struct cli_bc_ctx *ctx, int32_t id)
958
963
{
959
964
    if (id < 0 || id >= ctx->njsnorms || !ctx->jsnorms)
960
 
        return NULL;
 
965
        return NULL;
961
966
    return &ctx->jsnorms[id];
962
967
}
963
968
 
968
973
    cli_ctx *cctx = ctx->ctx;
969
974
    struct bc_jsnorm *b = get_jsnorm(ctx, id);
970
975
    if (!b || b->from == -1 || !b->state)
971
 
        return -1;
 
976
        return -1;
972
977
 
973
978
    avail = cli_bcapi_buffer_pipe_read_avail(ctx, b->from);
974
979
    in = cli_bcapi_buffer_pipe_read_get(ctx, b->from, avail);
975
980
    if (!avail || !in)
976
 
        return -1;
 
981
        return -1;
977
982
    if (cctx && cli_checklimits("bytecode js api", cctx, ctx->jsnormwritten + avail, 0, 0))
978
 
        return -1;
 
983
        return -1;
979
984
    cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail);
980
985
    cli_js_process_buffer(b->state, (char*)in, avail);
981
986
    return 0;
985
990
{
986
991
    struct bc_jsnorm *b = get_jsnorm(ctx, id);
987
992
    if (!b || b->from == -1)
988
 
        return -1;
 
993
        return -1;
989
994
    if (ctx->ctx && cli_updatelimits(ctx->ctx, ctx->jsnormwritten))
990
 
        return -1;
 
995
        return -1;
991
996
    ctx->jsnormwritten = 0;
992
997
    cli_js_parse_done(b->state);
993
998
    cli_js_output(b->state, ctx->jsnormdir);
999
1004
static inline double myround(double a)
1000
1005
{
1001
1006
    if (a < 0)
1002
 
        return a-0.5;
 
1007
        return a-0.5;
1003
1008
    return a+0.5;
1004
1009
}
1005
1010
 
1007
1012
{
1008
1013
    double f;
1009
1014
    if (!b)
1010
 
        return 0x7fffffff;
 
1015
        return 0x7fffffff;
1011
1016
    /* log(a/b) is -32..32, so 2^26*32=2^31 covers the entire range of int32 */
1012
1017
    f = (1<<26)*log((double)a / b) / log(2);
1013
1018
    return (int32_t)myround(f);
1016
1021
int32_t cli_bcapi_ipow(struct cli_bc_ctx *ctx, int32_t a, int32_t b, int32_t c)
1017
1022
{
1018
1023
    if (!a && b < 0)
1019
 
        return 0x7fffffff;
 
1024
        return 0x7fffffff;
1020
1025
    return (int32_t)myround(c*pow(a,b));
1021
1026
}
1022
1027
 
1024
1029
{
1025
1030
    double f;
1026
1031
    if (!b)
1027
 
        return 0x7fffffff;
 
1032
        return 0x7fffffff;
1028
1033
    f= c*exp((double)a/b);
1029
1034
    return (uint32_t)myround(f);
1030
1035
}
1033
1038
{
1034
1039
    double f;
1035
1040
    if (!b)
1036
 
        return 0x7fffffff;
 
1041
        return 0x7fffffff;
1037
1042
    f = c*sin((double)a/b);
1038
1043
    return (int32_t)myround(f);
1039
1044
}
1042
1047
{
1043
1048
    double f;
1044
1049
    if (!b)
1045
 
        return 0x7fffffff;
 
1050
        return 0x7fffffff;
1046
1051
    f = c*cos((double)a/b);
1047
1052
    return (int32_t)myround(f);
1048
1053
}
1049
1054
 
1050
1055
int32_t cli_bcapi_memstr(struct cli_bc_ctx *ctx, const uint8_t* h, int32_t hs,
1051
 
                         const uint8_t*n, int32_t ns)
 
1056
                         const uint8_t*n, int32_t ns)
1052
1057
{
1053
1058
    const uint8_t *s;
1054
1059
    if (!h || !n || hs < 0 || ns < 0) {
1055
 
        API_MISUSE();
1056
 
        return -1;
 
1060
        API_MISUSE();
 
1061
        return -1;
1057
1062
    }
1058
1063
    cli_event_fastdata(EV, BCEV_MEM_1, h, hs);
1059
1064
    cli_event_fastdata(EV, BCEV_MEM_2, n, ns);
1060
1065
    s = (const uint8_t*) cli_memstr((const char*)h, hs, (const char*)n, ns);
1061
1066
    if (!s)
1062
 
        return -1;
 
1067
        return -1;
1063
1068
    return s - h;
1064
1069
}
1065
1070
 
1071
1076
    in[1] = bh;
1072
1077
 
1073
1078
    if (cli_hex2str_to((const char*)in, &result, 2) == -1)
1074
 
        return -1;
 
1079
        return -1;
1075
1080
    return result;
1076
1081
}
1077
1082
 
1081
1086
    const uint8_t *end = str + len;
1082
1087
    while (isspace(*str) && str < end) str++;
1083
1088
    if (str == end)
1084
 
        return -1;/* all spaces */
 
1089
        return -1;/* all spaces */
1085
1090
    if (*str == '+') str++;
1086
1091
    if (str == end)
1087
 
        return -1;/* all spaces and +*/
 
1092
        return -1;/* all spaces and +*/
1088
1093
    if (*str == '-')
1089
 
        return -1;/* only positive numbers */
 
1094
        return -1;/* only positive numbers */
1090
1095
    if (!isdigit(*str))
1091
 
        return -1;
 
1096
        return -1;
1092
1097
    while (isdigit(*str) && str < end) {
1093
 
        number = number*10 + (*str - '0');
 
1098
        number = number*10 + (*str - '0');
1094
1099
    }
1095
1100
    return number;
1096
1101
}
1098
1103
uint32_t cli_bcapi_debug_print_str_start(struct cli_bc_ctx *ctx , const uint8_t* s, uint32_t len)
1099
1104
{
1100
1105
    if (!s || len <= 0)
1101
 
        return -1;
 
1106
        return -1;
1102
1107
    cli_event_fastdata(EV, BCEV_DBG_STR, s, len);
1103
1108
    cli_dbgmsg("bytecode debug: %.*s", len, s);
1104
1109
    return 0;
1107
1112
uint32_t cli_bcapi_debug_print_str_nonl(struct cli_bc_ctx *ctx , const uint8_t* s, uint32_t len)
1108
1113
{
1109
1114
    if (!s || len <= 0)
1110
 
        return -1;
 
1115
        return -1;
1111
1116
    if (!cli_debug_flag)
1112
 
        return 0;
 
1117
        return 0;
1113
1118
    return fwrite(s, 1, len, stderr);
1114
1119
}
1115
1120
 
1121
1126
    double log2 = log(2);
1122
1127
 
1123
1128
    if (!s || len <= 0)
1124
 
        return -1;
 
1129
        return -1;
1125
1130
    memset(probTable, 0, sizeof(probTable));
1126
1131
    for (i=0;i<len;i++) {
1127
 
        probTable[s[i]]++;
 
1132
        probTable[s[i]]++;
1128
1133
    }
1129
1134
    for (i=0;i<256;i++) {
1130
 
        double p;
1131
 
        if (!probTable[i])
1132
 
            continue;
1133
 
        p = (double)probTable[i] / len;
1134
 
        entropy += -p*log(p)/log2;
 
1135
        double p;
 
1136
        if (!probTable[i])
 
1137
            continue;
 
1138
        p = (double)probTable[i] / len;
 
1139
        entropy += -p*log(p)/log2;
1135
1140
    }
1136
1141
    entropy *= 1<<26;
1137
1142
    return (uint32_t)entropy;
1142
1147
    unsigned n = ctx->nmaps+1;
1143
1148
    struct cli_map *s;
1144
1149
    if (!keysize)
1145
 
        return -1;
 
1150
        return -1;
1146
1151
    s = cli_realloc(ctx->maps, sizeof(*ctx->maps)*n);
1147
1152
    if (!s)
1148
 
        return -1;
 
1153
        return -1;
1149
1154
    ctx->maps = s;
1150
1155
    ctx->nmaps = n;
1151
1156
    s = &s[n-1];
1156
1161
static struct cli_map *get_hashtab(struct cli_bc_ctx *ctx, int32_t id)
1157
1162
{
1158
1163
    if (id < 0 || id >= ctx->nmaps || !ctx->maps)
1159
 
        return NULL;
 
1164
        return NULL;
1160
1165
    return &ctx->maps[id];
1161
1166
}
1162
1167
 
1164
1169
{
1165
1170
    struct cli_map *s = get_hashtab(ctx, id);
1166
1171
    if (!s)
1167
 
        return -1;
 
1172
        return -1;
1168
1173
    return cli_map_addkey(s, key, keysize);
1169
1174
}
1170
1175
 
1172
1177
{
1173
1178
    struct cli_map *s = get_hashtab(ctx, id);
1174
1179
    if (!s)
1175
 
        return -1;
 
1180
        return -1;
1176
1181
    return cli_map_setvalue(s, value, valuesize);
1177
1182
}
1178
1183
 
1180
1185
{
1181
1186
    struct cli_map *s = get_hashtab(ctx, id);
1182
1187
    if (!s)
1183
 
        return -1;
 
1188
        return -1;
1184
1189
    return cli_map_removekey(s, key, keysize);
1185
1190
}
1186
1191
 
1188
1193
{
1189
1194
    struct cli_map *s = get_hashtab(ctx, id);
1190
1195
    if (!s)
1191
 
        return -1;
 
1196
        return -1;
1192
1197
    return cli_map_find(s, key, keysize);
1193
1198
}
1194
1199
 
1196
1201
{
1197
1202
    struct cli_map *s = get_hashtab(ctx, id);
1198
1203
    if (!s)
1199
 
        return -1;
 
1204
        return -1;
1200
1205
    return cli_map_getvalue_size(s);
1201
1206
}
1202
1207
 
1204
1209
{
1205
1210
    struct cli_map *s = get_hashtab(ctx, id);
1206
1211
    if (!s)
1207
 
        return NULL;
 
1212
        return NULL;
1208
1213
    if (cli_map_getvalue_size(s) != valuesize)
1209
 
        return NULL;
 
1214
        return NULL;
1210
1215
    return cli_map_getvalue(s);
1211
1216
}
1212
1217
 
1214
1219
{
1215
1220
    struct cli_map *s = get_hashtab(ctx, id);
1216
1221
    if (!s)
1217
 
        return -1;
 
1222
        return -1;
1218
1223
    cli_map_delete(s);
1219
1224
    if (id == ctx->nmaps-1) {
1220
 
        ctx->nmaps--;
1221
 
        if (!ctx->nmaps) {
1222
 
            free(ctx->maps);
1223
 
            ctx->maps = NULL;
1224
 
        } else {
1225
 
            s = cli_realloc(ctx->maps, ctx->nmaps*(sizeof(*s)));
1226
 
            if (s)
1227
 
                ctx->maps = s;
1228
 
        }
 
1225
        ctx->nmaps--;
 
1226
        if (!ctx->nmaps) {
 
1227
            free(ctx->maps);
 
1228
            ctx->maps = NULL;
 
1229
        } else {
 
1230
            s = cli_realloc(ctx->maps, ctx->nmaps*(sizeof(*s)));
 
1231
            if (s)
 
1232
                ctx->maps = s;
 
1233
        }
1229
1234
    }
1230
1235
    return 0;
1231
1236
}
1255
1260
int32_t cli_bcapi_extract_set_container(struct cli_bc_ctx *ctx, uint32_t ftype)
1256
1261
{
1257
1262
    if (ftype > CL_TYPE_IGNORED)
1258
 
        return -1;
 
1263
        return -1;
1259
1264
    ctx->containertype = ftype;
1260
1265
    return 0;
1261
1266
}
1264
1269
{
1265
1270
    fmap_t *map;
1266
1271
    if (ctx->extracted_file_input == extracted_file)
1267
 
        return 0;
 
1272
        return 0;
1268
1273
    if (!extracted_file) {
1269
 
        cli_dbgmsg("bytecode api: input switched back to main file\n");
1270
 
        ctx->fmap = ctx->save_map;
1271
 
        ctx->extracted_file_input = 0;
1272
 
        return 0;
 
1274
        cli_dbgmsg("bytecode api: input switched back to main file\n");
 
1275
        ctx->fmap = ctx->save_map;
 
1276
        ctx->extracted_file_input = 0;
 
1277
        return 0;
1273
1278
    }
1274
1279
    if (ctx->outfd < 0)
1275
 
        return -1;
 
1280
        return -1;
1276
1281
    map = fmap(ctx->outfd, 0, 0);
1277
1282
    if (!map) {
1278
 
        cli_warnmsg("can't mmap() extracted temporary file %s\n", ctx->tempfile);
1279
 
        return -1;
 
1283
        cli_warnmsg("can't mmap() extracted temporary file %s\n", ctx->tempfile);
 
1284
        return -1;
1280
1285
    }
1281
1286
    ctx->save_map = ctx->fmap;
1282
1287
    cli_bytecode_context_setfile(ctx, map);
1288
1293
uint32_t cli_bcapi_get_environment(struct cli_bc_ctx *ctx , struct cli_environment* env, uint32_t len)
1289
1294
{
1290
1295
    if (len > sizeof(*env)) {
1291
 
        cli_dbgmsg("cli_bcapi_get_environment len %u > %lu\n", len, sizeof(*env));
1292
 
        return -1;
 
1296
        cli_dbgmsg("cli_bcapi_get_environment len %u > %lu\n", len, sizeof(*env));
 
1297
        return -1;
1293
1298
    }
1294
1299
    memcpy(env, ctx->env, len);
1295
1300
    return 0;
1298
1303
uint32_t cli_bcapi_disable_bytecode_if(struct cli_bc_ctx *ctx , const int8_t* reason, uint32_t len, uint32_t cond)
1299
1304
{
1300
1305
    if (ctx->bc->kind != BC_STARTUP) {
1301
 
        cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_bytecode_if\n");
1302
 
        return -1;
 
1306
        cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_bytecode_if\n");
 
1307
        return -1;
1303
1308
    }
1304
1309
    if (!cond)
1305
 
        return ctx->bytecode_disable_status;
 
1310
        return ctx->bytecode_disable_status;
1306
1311
    if (*reason == '^')
1307
 
        cli_warnmsg("Bytecode: disabling completely because %s\n", reason+1);
 
1312
        cli_warnmsg("Bytecode: disabling completely because %s\n", reason+1);
1308
1313
    else
1309
 
        cli_dbgmsg("Bytecode: disabling completely because %s\n", reason);
 
1314
        cli_dbgmsg("Bytecode: disabling completely because %s\n", reason);
1310
1315
    ctx->bytecode_disable_status = 2;
1311
1316
    return ctx->bytecode_disable_status;
1312
1317
}
1314
1319
uint32_t cli_bcapi_disable_jit_if(struct cli_bc_ctx *ctx , const int8_t* reason, uint32_t len, uint32_t cond)
1315
1320
{
1316
1321
    if (ctx->bc->kind != BC_STARTUP) {
1317
 
        cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_jit_if\n");
1318
 
        return -1;
 
1322
        cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_jit_if\n");
 
1323
        return -1;
1319
1324
    }
1320
1325
    if (!cond)
1321
 
        return ctx->bytecode_disable_status;
 
1326
        return ctx->bytecode_disable_status;
1322
1327
    if (*reason == '^')
1323
 
        cli_warnmsg("Bytecode: disabling JIT because %s\n", reason+1);
 
1328
        cli_warnmsg("Bytecode: disabling JIT because %s\n", reason+1);
1324
1329
    else
1325
 
        cli_dbgmsg("Bytecode: disabling JIT because %s\n", reason);
 
1330
        cli_dbgmsg("Bytecode: disabling JIT because %s\n", reason);
1326
1331
    if (ctx->bytecode_disable_status != 2) /* no reenabling */
1327
 
        ctx->bytecode_disable_status = 1;
 
1332
        ctx->bytecode_disable_status = 1;
1328
1333
    return ctx->bytecode_disable_status;
1329
1334
}
1330
1335
 
1331
1336
int32_t cli_bcapi_version_compare(struct cli_bc_ctx *ctx , const uint8_t* lhs, uint32_t lhs_len, 
1332
 
                                  const uint8_t* rhs, uint32_t rhs_len)
 
1337
                                  const uint8_t* rhs, uint32_t rhs_len)
1333
1338
{
1334
1339
    unsigned i = 0, j = 0;
1335
1340
    unsigned long li=0, ri=0;
1336
1341
    do {
1337
 
        while (i < lhs_len && j < rhs_len && lhs[i] == rhs[j] &&
1338
 
               !isdigit(lhs[i]) && !isdigit(rhs[j])) {
1339
 
            i++; j++;
1340
 
        }
1341
 
        if (i == lhs_len && j == rhs_len)
1342
 
            return 0;
1343
 
        if (i == lhs_len)
1344
 
            return -1;
1345
 
        if (j == rhs_len)
1346
 
            return 1;
1347
 
        if (!isdigit(lhs[i]) || !isdigit(rhs[j]))
1348
 
            return lhs[i] < rhs[j] ? -1 : 1;
1349
 
        while (isdigit(lhs[i]) && i < lhs_len)
1350
 
            li = 10*li + (lhs[i++] - '0');
1351
 
        while (isdigit(rhs[j]) && j < rhs_len)
1352
 
            ri = 10*ri + (rhs[j++] - '0');
1353
 
        if (li < ri)
1354
 
            return -1;
1355
 
        if (li > ri)
1356
 
            return 1;
 
1342
        while (i < lhs_len && j < rhs_len && lhs[i] == rhs[j] &&
 
1343
               !isdigit(lhs[i]) && !isdigit(rhs[j])) {
 
1344
            i++; j++;
 
1345
        }
 
1346
        if (i == lhs_len && j == rhs_len)
 
1347
            return 0;
 
1348
        if (i == lhs_len)
 
1349
            return -1;
 
1350
        if (j == rhs_len)
 
1351
            return 1;
 
1352
        if (!isdigit(lhs[i]) || !isdigit(rhs[j]))
 
1353
            return lhs[i] < rhs[j] ? -1 : 1;
 
1354
        while (isdigit(lhs[i]) && i < lhs_len)
 
1355
            li = 10*li + (lhs[i++] - '0');
 
1356
        while (isdigit(rhs[j]) && j < rhs_len)
 
1357
            ri = 10*ri + (rhs[j++] - '0');
 
1358
        if (li < ri)
 
1359
            return -1;
 
1360
        if (li > ri)
 
1361
            return 1;
1357
1362
    } while (1);
1358
1363
}
1359
1364
 
1363
1368
    uint8_t v = (value >> shift)&mask;
1364
1369
    /* q == mask -> ANY */
1365
1370
    if (q == v || q == mask)
1366
 
        return 1;
 
1371
        return 1;
1367
1372
    return 0;
1368
1373
}
1369
1374
 
1370
1375
uint32_t cli_bcapi_check_platform(struct cli_bc_ctx *ctx , uint32_t a, uint32_t b , uint32_t c)
1371
1376
{
1372
1377
    unsigned ret =
1373
 
        check_bits(a, ctx->env->platform_id_a, 24, 0xff) &&
1374
 
        check_bits(a, ctx->env->platform_id_a, 20, 0xf) &&
1375
 
        check_bits(a, ctx->env->platform_id_a, 16, 0xf) &&
1376
 
        check_bits(a, ctx->env->platform_id_a, 8, 0xff) &&
1377
 
        check_bits(a, ctx->env->platform_id_a, 0, 0xff) &&
1378
 
        check_bits(b, ctx->env->platform_id_b, 28, 0xf) &&
1379
 
        check_bits(b, ctx->env->platform_id_b, 24, 0xf) &&
1380
 
        check_bits(b, ctx->env->platform_id_b, 16, 0xff) &&
1381
 
        check_bits(b, ctx->env->platform_id_b, 8, 0xff) &&
1382
 
        check_bits(b, ctx->env->platform_id_b, 0, 0xff) &&
1383
 
        check_bits(c, ctx->env->platform_id_c, 24, 0xff) &&
1384
 
        check_bits(c, ctx->env->platform_id_c, 16, 0xff) &&
1385
 
        check_bits(c, ctx->env->platform_id_c, 8, 0xff) &&
1386
 
        check_bits(c, ctx->env->platform_id_c, 0, 0xff);
 
1378
        check_bits(a, ctx->env->platform_id_a, 24, 0xff) &&
 
1379
        check_bits(a, ctx->env->platform_id_a, 20, 0xf) &&
 
1380
        check_bits(a, ctx->env->platform_id_a, 16, 0xf) &&
 
1381
        check_bits(a, ctx->env->platform_id_a, 8, 0xff) &&
 
1382
        check_bits(a, ctx->env->platform_id_a, 0, 0xff) &&
 
1383
        check_bits(b, ctx->env->platform_id_b, 28, 0xf) &&
 
1384
        check_bits(b, ctx->env->platform_id_b, 24, 0xf) &&
 
1385
        check_bits(b, ctx->env->platform_id_b, 16, 0xff) &&
 
1386
        check_bits(b, ctx->env->platform_id_b, 8, 0xff) &&
 
1387
        check_bits(b, ctx->env->platform_id_b, 0, 0xff) &&
 
1388
        check_bits(c, ctx->env->platform_id_c, 24, 0xff) &&
 
1389
        check_bits(c, ctx->env->platform_id_c, 16, 0xff) &&
 
1390
        check_bits(c, ctx->env->platform_id_c, 8, 0xff) &&
 
1391
        check_bits(c, ctx->env->platform_id_c, 0, 0xff);
1387
1392
    if (ret) {
1388
 
        cli_dbgmsg("check_platform(0x%08x,0x%08x,0x%08x) = match\n",a,b,c);
 
1393
        cli_dbgmsg("check_platform(0x%08x,0x%08x,0x%08x) = match\n",a,b,c);
1389
1394
    }
1390
1395
    return ret;
1391
1396
}
1392
1397
 
1393
1398
int cli_bytecode_context_setpdf(struct cli_bc_ctx *ctx, unsigned phase,
1394
 
                                unsigned nobjs,
1395
 
                                struct pdf_obj *objs, uint32_t *pdf_flags,
1396
 
                                uint32_t pdfsize, uint32_t pdfstartoff)
 
1399
                                unsigned nobjs,
 
1400
                                struct pdf_obj *objs, uint32_t *pdf_flags,
 
1401
                                uint32_t pdfsize, uint32_t pdfstartoff)
1397
1402
{
1398
1403
    ctx->pdf_nobjs = nobjs;
1399
1404
    ctx->pdf_objs = objs;
1407
1412
int32_t cli_bcapi_pdf_get_obj_num(struct cli_bc_ctx *ctx)
1408
1413
{
1409
1414
    if (!ctx->pdf_phase)
1410
 
        return -1;
 
1415
        return -1;
1411
1416
    return ctx->pdf_nobjs;
1412
1417
}
1413
1418
 
1414
1419
int32_t cli_bcapi_pdf_get_flags(struct cli_bc_ctx *ctx)
1415
1420
{
1416
1421
    if (!ctx->pdf_phase)
1417
 
        return -1;
 
1422
        return -1;
1418
1423
    return *ctx->pdf_flags;
1419
1424
}
1420
1425
 
1421
1426
int32_t cli_bcapi_pdf_set_flags(struct cli_bc_ctx *ctx , int32_t flags)
1422
1427
{
1423
1428
    if (!ctx->pdf_phase)
1424
 
        return -1;
 
1429
        return -1;
1425
1430
    cli_dbgmsg("cli_pdf: bytecode set_flags %08x -> %08x\n",
1426
 
               *ctx->pdf_flags,
1427
 
               flags);
 
1431
               *ctx->pdf_flags,
 
1432
               flags);
1428
1433
    *ctx->pdf_flags = flags;
1429
1434
    return 0;
1430
1435
}
1433
1438
{
1434
1439
    unsigned i;
1435
1440
    if (!ctx->pdf_phase)
1436
 
        return -1;
 
1441
        return -1;
1437
1442
    for (i=0;i<ctx->pdf_nobjs;i++) {
1438
 
        if (ctx->pdf_objs[i].id == objid)
1439
 
            return i;
 
1443
        if (ctx->pdf_objs[i].id == objid)
 
1444
            return i;
1440
1445
    }
1441
1446
    return -1;
1442
1447
}
1444
1449
uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx , int32_t objidx)
1445
1450
{
1446
1451
    if (!ctx->pdf_phase ||
1447
 
        objidx >= ctx->pdf_nobjs ||
1448
 
        ctx->pdf_phase == PDF_PHASE_POSTDUMP /* map is obj itself, no access to pdf anymore */
 
1452
        objidx >= ctx->pdf_nobjs ||
 
1453
        ctx->pdf_phase == PDF_PHASE_POSTDUMP /* map is obj itself, no access to pdf anymore */
1449
1454
       )
1450
 
        return 0;
 
1455
        return 0;
1451
1456
    if (objidx + 1 == ctx->pdf_nobjs)
1452
 
        return ctx->pdf_size - ctx->pdf_objs[objidx].start;
 
1457
        return ctx->pdf_size - ctx->pdf_objs[objidx].start;
1453
1458
    return ctx->pdf_objs[objidx+1].start - ctx->pdf_objs[objidx].start - 4;
1454
1459
}
1455
1460
 
1457
1462
{
1458
1463
    uint32_t size = cli_bcapi_pdf_getobjsize(ctx, objidx);
1459
1464
    if (amount > size)
1460
 
        return NULL;
 
1465
        return NULL;
1461
1466
    return fmap_need_off(ctx->fmap, ctx->pdf_objs[objidx].start, amount);
1462
1467
}
1463
1468
 
1464
1469
int32_t cli_bcapi_pdf_getobjid(struct cli_bc_ctx *ctx , int32_t objidx)
1465
1470
{
1466
1471
    if (!ctx->pdf_phase ||
1467
 
        objidx >= ctx->pdf_nobjs)
1468
 
        return -1;
 
1472
        objidx >= ctx->pdf_nobjs)
 
1473
        return -1;
1469
1474
    return ctx->pdf_objs[objidx].id;
1470
1475
}
1471
1476
 
1472
1477
int32_t cli_bcapi_pdf_getobjflags(struct cli_bc_ctx *ctx , int32_t objidx)
1473
1478
{
1474
1479
    if (!ctx->pdf_phase ||
1475
 
        objidx >= ctx->pdf_nobjs)
1476
 
        return -1;
 
1480
        objidx >= ctx->pdf_nobjs)
 
1481
        return -1;
1477
1482
    return ctx->pdf_objs[objidx].flags;
1478
1483
}
1479
1484
 
1480
1485
int32_t cli_bcapi_pdf_setobjflags(struct cli_bc_ctx *ctx , int32_t objidx, int32_t flags)
1481
1486
{
1482
1487
    if (!ctx->pdf_phase ||
1483
 
        objidx >= ctx->pdf_nobjs)
1484
 
        return -1;
 
1488
        objidx >= ctx->pdf_nobjs)
 
1489
        return -1;
1485
1490
    cli_dbgmsg("cli_pdf: bytecode setobjflags %08x -> %08x\n",
1486
 
               ctx->pdf_objs[objidx].flags,
1487
 
               flags);
 
1491
               ctx->pdf_objs[objidx].flags,
 
1492
               flags);
1488
1493
    ctx->pdf_objs[objidx].flags = flags;
1489
1494
    return 0;
1490
1495
}
1492
1497
int32_t cli_bcapi_pdf_get_offset(struct cli_bc_ctx *ctx , int32_t objidx)
1493
1498
{
1494
1499
    if (!ctx->pdf_phase ||
1495
 
        objidx >= ctx->pdf_nobjs)
1496
 
        return -1;
 
1500
        objidx >= ctx->pdf_nobjs)
 
1501
        return -1;
1497
1502
    return ctx->pdf_startoff + ctx->pdf_objs[objidx].start;
1498
1503
}
1499
1504
 
1505
1510
int32_t cli_bcapi_pdf_get_dumpedobjid(struct cli_bc_ctx *ctx)
1506
1511
{
1507
1512
    if (ctx->pdf_phase != PDF_PHASE_POSTDUMP)
1508
 
        return -1;
 
1513
        return -1;
1509
1514
    return ctx->pdf_dumpedid;
1510
1515
}
1511
1516