~ubuntu-branches/ubuntu/utopic/clamav/utopic-security

« back to all changes in this revision

Viewing changes to libclamav/7z/7zDec.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-02-01 11:06:17 UTC
  • mfrom: (0.35.37 sid)
  • Revision ID: package-import@ubuntu.com-20140201110617-33h2xxk09dep0ui4
Tags: 0.98.1+dfsg-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Drop build-dep on electric-fence (in Universe)
  - Add apparmor profiles for clamd and freshclam along with maintainer
    script changes
  - Add autopkgtest

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 7zDec.c -- Decoding from 7z folder
 
2
2010-11-02 : Igor Pavlov : Public domain */
 
3
 
 
4
#include <string.h>
 
5
 
 
6
#define _7ZIP_PPMD_SUPPPORT
 
7
 
 
8
#include "7z.h"
 
9
 
 
10
#include "Bcj2.h"
 
11
#include "Bra.h"
 
12
#include "CpuArch.h"
 
13
#include "LzmaDec.h"
 
14
#include "Lzma2Dec.h"
 
15
#ifdef _7ZIP_PPMD_SUPPPORT
 
16
#include "Ppmd7.h"
 
17
#endif
 
18
 
 
19
#define k_Copy 0
 
20
#define k_LZMA2 0x21
 
21
#define k_LZMA  0x30101
 
22
#define k_BCJ   0x03030103
 
23
#define k_PPC   0x03030205
 
24
#define k_ARM   0x03030501
 
25
#define k_ARMT  0x03030701
 
26
#define k_SPARC 0x03030805
 
27
#define k_BCJ2  0x0303011B
 
28
 
 
29
#ifdef _7ZIP_PPMD_SUPPPORT
 
30
 
 
31
#define k_PPMD 0x30401
 
32
 
 
33
typedef struct
 
34
{
 
35
  IByteIn p;
 
36
  const Byte *cur;
 
37
  const Byte *end;
 
38
  const Byte *begin;
 
39
  UInt64 processed;
 
40
  Bool extra;
 
41
  SRes res;
 
42
  ILookInStream *inStream;
 
43
} CByteInToLook;
 
44
 
 
45
static Byte ReadByte(void *pp)
 
46
{
 
47
  CByteInToLook *p = (CByteInToLook *)pp;
 
48
  if (p->cur != p->end)
 
49
    return *p->cur++;
 
50
  if (p->res == SZ_OK)
 
51
  {
 
52
    size_t size = p->cur - p->begin;
 
53
    p->processed += size;
 
54
    p->res = p->inStream->Skip(p->inStream, size);
 
55
    size = (1 << 25);
 
56
    p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
 
57
    p->cur = p->begin;
 
58
    p->end = p->begin + size;
 
59
    if (size != 0)
 
60
      return *p->cur++;;
 
61
  }
 
62
  p->extra = True;
 
63
  return 0;
 
64
}
 
65
 
 
66
static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
 
67
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
 
68
{
 
69
  CPpmd7 ppmd;
 
70
  CByteInToLook s;
 
71
  SRes res = SZ_OK;
 
72
 
 
73
  s.p.Read = ReadByte;
 
74
  s.inStream = inStream;
 
75
  s.begin = s.end = s.cur = NULL;
 
76
  s.extra = False;
 
77
  s.res = SZ_OK;
 
78
  s.processed = 0;
 
79
 
 
80
  if (coder->Props.size != 5)
 
81
    return SZ_ERROR_UNSUPPORTED;
 
82
 
 
83
  {
 
84
    unsigned order = coder->Props.data[0];
 
85
    UInt32 memSize = GetUi32(coder->Props.data + 1);
 
86
    if (order < PPMD7_MIN_ORDER ||
 
87
        order > PPMD7_MAX_ORDER ||
 
88
        memSize < PPMD7_MIN_MEM_SIZE ||
 
89
        memSize > PPMD7_MAX_MEM_SIZE)
 
90
      return SZ_ERROR_UNSUPPORTED;
 
91
    Ppmd7_Construct(&ppmd);
 
92
    if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
 
93
      return SZ_ERROR_MEM;
 
94
    Ppmd7_Init(&ppmd, order);
 
95
  }
 
96
  {
 
97
    CPpmd7z_RangeDec rc;
 
98
    Ppmd7z_RangeDec_CreateVTable(&rc);
 
99
    rc.Stream = &s.p;
 
100
    if (!Ppmd7z_RangeDec_Init(&rc))
 
101
      res = SZ_ERROR_DATA;
 
102
    else if (s.extra)
 
103
      res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
 
104
    else
 
105
    {
 
106
      SizeT i;
 
107
      for (i = 0; i < outSize; i++)
 
108
      {
 
109
        int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
 
110
        if (s.extra || sym < 0)
 
111
          break;
 
112
        outBuffer[i] = (Byte)sym;
 
113
      }
 
114
      if (i != outSize)
 
115
        res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
 
116
      else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
 
117
        res = SZ_ERROR_DATA;
 
118
    }
 
119
  }
 
120
  Ppmd7_Free(&ppmd, allocMain);
 
121
  return res;
 
122
}
 
123
 
 
124
#endif
 
125
 
 
126
 
 
127
static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
 
128
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
 
129
{
 
130
  CLzmaDec state;
 
131
  SRes res = SZ_OK;
 
132
 
 
133
  LzmaDec_Construct(&state);
 
134
  RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
 
135
  state.dic = outBuffer;
 
136
  state.dicBufSize = outSize;
 
137
  LzmaDec_Init(&state);
 
138
 
 
139
  for (;;)
 
140
  {
 
141
    Byte *inBuf = NULL;
 
142
    size_t lookahead = (1 << 18);
 
143
    if (lookahead > inSize)
 
144
      lookahead = (size_t)inSize;
 
145
    res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
 
146
    if (res != SZ_OK)
 
147
      break;
 
148
 
 
149
    {
 
150
      SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
 
151
      ELzmaStatus status;
 
152
      res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
 
153
      lookahead -= inProcessed;
 
154
      inSize -= inProcessed;
 
155
      if (res != SZ_OK)
 
156
        break;
 
157
      if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
 
158
      {
 
159
        if (state.dicBufSize != outSize || lookahead != 0 ||
 
160
            (status != LZMA_STATUS_FINISHED_WITH_MARK &&
 
161
             status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
 
162
          res = SZ_ERROR_DATA;
 
163
        break;
 
164
      }
 
165
      res = inStream->Skip((void *)inStream, inProcessed);
 
166
      if (res != SZ_OK)
 
167
        break;
 
168
    }
 
169
  }
 
170
 
 
171
  LzmaDec_FreeProbs(&state, allocMain);
 
172
  return res;
 
173
}
 
174
 
 
175
static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
 
176
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
 
177
{
 
178
  CLzma2Dec state;
 
179
  SRes res = SZ_OK;
 
180
 
 
181
  Lzma2Dec_Construct(&state);
 
182
  if (coder->Props.size != 1)
 
183
    return SZ_ERROR_DATA;
 
184
  RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
 
185
  state.decoder.dic = outBuffer;
 
186
  state.decoder.dicBufSize = outSize;
 
187
  Lzma2Dec_Init(&state);
 
188
 
 
189
  for (;;)
 
190
  {
 
191
    Byte *inBuf = NULL;
 
192
    size_t lookahead = (1 << 18);
 
193
    if (lookahead > inSize)
 
194
      lookahead = (size_t)inSize;
 
195
    res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
 
196
    if (res != SZ_OK)
 
197
      break;
 
198
 
 
199
    {
 
200
      SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
 
201
      ELzmaStatus status;
 
202
      res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
 
203
      lookahead -= inProcessed;
 
204
      inSize -= inProcessed;
 
205
      if (res != SZ_OK)
 
206
        break;
 
207
      if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
 
208
      {
 
209
        if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
 
210
            (status != LZMA_STATUS_FINISHED_WITH_MARK))
 
211
          res = SZ_ERROR_DATA;
 
212
        break;
 
213
      }
 
214
      res = inStream->Skip((void *)inStream, inProcessed);
 
215
      if (res != SZ_OK)
 
216
        break;
 
217
    }
 
218
  }
 
219
 
 
220
  Lzma2Dec_FreeProbs(&state, allocMain);
 
221
  return res;
 
222
}
 
223
 
 
224
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
 
225
{
 
226
  while (inSize > 0)
 
227
  {
 
228
    void *inBuf;
 
229
    size_t curSize = (1 << 18);
 
230
    if (curSize > inSize)
 
231
      curSize = (size_t)inSize;
 
232
    RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
 
233
    if (curSize == 0)
 
234
      return SZ_ERROR_INPUT_EOF;
 
235
    memcpy(outBuffer, inBuf, curSize);
 
236
    outBuffer += curSize;
 
237
    inSize -= curSize;
 
238
    RINOK(inStream->Skip((void *)inStream, curSize));
 
239
  }
 
240
  return SZ_OK;
 
241
}
 
242
 
 
243
static Bool IS_MAIN_METHOD(UInt32 m)
 
244
{
 
245
  switch(m)
 
246
  {
 
247
    case k_Copy:
 
248
    case k_LZMA:
 
249
    case k_LZMA2:
 
250
    #ifdef _7ZIP_PPMD_SUPPPORT
 
251
    case k_PPMD:
 
252
    #endif
 
253
      return True;
 
254
  }
 
255
  return False;
 
256
}
 
257
 
 
258
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
 
259
{
 
260
  return
 
261
      c->NumInStreams == 1 &&
 
262
      c->NumOutStreams == 1 &&
 
263
      c->MethodID <= (UInt32)0xFFFFFFFF &&
 
264
      IS_MAIN_METHOD((UInt32)c->MethodID);
 
265
}
 
266
 
 
267
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
 
268
 
 
269
static SRes CheckSupportedFolder(const CSzFolder *f)
 
270
{
 
271
  if (f->NumCoders < 1 || f->NumCoders > 4)
 
272
    return SZ_ERROR_UNSUPPORTED;
 
273
 
 
274
  if (f->Coders[0].MethodID == 0x06F10701) /* ACAB */
 
275
    return SZ_ERROR_ENCRYPTED;
 
276
 
 
277
  if (!IS_SUPPORTED_CODER(&f->Coders[0]))
 
278
    return SZ_ERROR_UNSUPPORTED;
 
279
  if (f->NumCoders == 1)
 
280
  {
 
281
    if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
 
282
      return SZ_ERROR_UNSUPPORTED;
 
283
    return SZ_OK;
 
284
  }
 
285
  if (f->NumCoders == 2)
 
286
  {
 
287
    CSzCoderInfo *c = &f->Coders[1];
 
288
    if (c->MethodID > (UInt32)0xFFFFFFFF ||
 
289
        c->NumInStreams != 1 ||
 
290
        c->NumOutStreams != 1 ||
 
291
        f->NumPackStreams != 1 ||
 
292
        f->PackStreams[0] != 0 ||
 
293
        f->NumBindPairs != 1 ||
 
294
        f->BindPairs[0].InIndex != 1 ||
 
295
        f->BindPairs[0].OutIndex != 0)
 
296
      return SZ_ERROR_UNSUPPORTED;
 
297
    switch ((UInt32)c->MethodID)
 
298
    {
 
299
      case k_BCJ:
 
300
      case k_ARM:
 
301
        break;
 
302
      default:
 
303
        return SZ_ERROR_UNSUPPORTED;
 
304
    }
 
305
    return SZ_OK;
 
306
  }
 
307
  if (f->NumCoders == 4)
 
308
  {
 
309
    if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
 
310
        !IS_SUPPORTED_CODER(&f->Coders[2]) ||
 
311
        !IS_BCJ2(&f->Coders[3]))
 
312
      return SZ_ERROR_UNSUPPORTED;
 
313
    if (f->NumPackStreams != 4 ||
 
314
        f->PackStreams[0] != 2 ||
 
315
        f->PackStreams[1] != 6 ||
 
316
        f->PackStreams[2] != 1 ||
 
317
        f->PackStreams[3] != 0 ||
 
318
        f->NumBindPairs != 3 ||
 
319
        f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
 
320
        f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
 
321
        f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
 
322
      return SZ_ERROR_UNSUPPORTED;
 
323
    return SZ_OK;
 
324
  }
 
325
  return SZ_ERROR_UNSUPPORTED;
 
326
}
 
327
 
 
328
static UInt64 GetSum(const UInt64 *values, UInt32 index)
 
329
{
 
330
  UInt64 sum = 0;
 
331
  UInt32 i;
 
332
  for (i = 0; i < index; i++)
 
333
    sum += values[i];
 
334
  return sum;
 
335
}
 
336
 
 
337
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
 
338
 
 
339
static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
 
340
    ILookInStream *inStream, UInt64 startPos,
 
341
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
 
342
    Byte *tempBuf[])
 
343
{
 
344
  UInt32 ci;
 
345
  SizeT tempSizes[3] = { 0, 0, 0};
 
346
  SizeT tempSize3 = 0;
 
347
  Byte *tempBuf3 = 0;
 
348
 
 
349
  RINOK(CheckSupportedFolder(folder));
 
350
 
 
351
  for (ci = 0; ci < folder->NumCoders; ci++)
 
352
  {
 
353
    CSzCoderInfo *coder = &folder->Coders[ci];
 
354
 
 
355
    if (IS_MAIN_METHOD((UInt32)coder->MethodID))
 
356
    {
 
357
      UInt32 si = 0;
 
358
      UInt64 offset;
 
359
      UInt64 inSize;
 
360
      Byte *outBufCur = outBuffer;
 
361
      SizeT outSizeCur = outSize;
 
362
      if (folder->NumCoders == 4)
 
363
      {
 
364
        UInt32 indices[] = { 3, 2, 0 };
 
365
        UInt64 unpackSize = folder->UnpackSizes[ci];
 
366
        si = indices[ci];
 
367
        if (ci < 2)
 
368
        {
 
369
          Byte *temp;
 
370
          outSizeCur = (SizeT)unpackSize;
 
371
          if (outSizeCur != unpackSize)
 
372
            return SZ_ERROR_MEM;
 
373
          temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
 
374
          if (temp == 0 && outSizeCur != 0)
 
375
            return SZ_ERROR_MEM;
 
376
          outBufCur = tempBuf[1 - ci] = temp;
 
377
          tempSizes[1 - ci] = outSizeCur;
 
378
        }
 
379
        else if (ci == 2)
 
380
        {
 
381
          if (unpackSize > outSize) /* check it */
 
382
            return SZ_ERROR_PARAM;
 
383
          tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
 
384
          tempSize3 = outSizeCur = (SizeT)unpackSize;
 
385
        }
 
386
        else
 
387
          return SZ_ERROR_UNSUPPORTED;
 
388
      }
 
389
      offset = GetSum(packSizes, si);
 
390
      inSize = packSizes[si];
 
391
      RINOK(LookInStream_SeekTo(inStream, startPos + offset));
 
392
 
 
393
      if (coder->MethodID == k_Copy)
 
394
      {
 
395
        if (inSize != outSizeCur) /* check it */
 
396
          return SZ_ERROR_DATA;
 
397
        RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
 
398
      }
 
399
      else if (coder->MethodID == k_LZMA)
 
400
      {
 
401
        RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
 
402
      }
 
403
      else if (coder->MethodID == k_LZMA2)
 
404
      {
 
405
        RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
 
406
      }
 
407
      else
 
408
      {
 
409
        #ifdef _7ZIP_PPMD_SUPPPORT
 
410
        RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
 
411
        #else
 
412
        return SZ_ERROR_UNSUPPORTED;
 
413
        #endif
 
414
      }
 
415
    }
 
416
    else if (coder->MethodID == k_BCJ2)
 
417
    {
 
418
      UInt64 offset = GetSum(packSizes, 1);
 
419
      UInt64 s3Size = packSizes[1];
 
420
      SRes res;
 
421
      if (ci != 3)
 
422
        return SZ_ERROR_UNSUPPORTED;
 
423
      RINOK(LookInStream_SeekTo(inStream, startPos + offset));
 
424
      tempSizes[2] = (SizeT)s3Size;
 
425
      if (tempSizes[2] != s3Size)
 
426
        return SZ_ERROR_MEM;
 
427
      tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
 
428
      if (tempBuf[2] == 0 && tempSizes[2] != 0)
 
429
        return SZ_ERROR_MEM;
 
430
      res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
 
431
      RINOK(res)
 
432
 
 
433
      res = Bcj2_Decode(
 
434
          tempBuf3, tempSize3,
 
435
          tempBuf[0], tempSizes[0],
 
436
          tempBuf[1], tempSizes[1],
 
437
          tempBuf[2], tempSizes[2],
 
438
          outBuffer, outSize);
 
439
      RINOK(res)
 
440
    }
 
441
    else
 
442
    {
 
443
      if (ci != 1)
 
444
        return SZ_ERROR_UNSUPPORTED;
 
445
      switch(coder->MethodID)
 
446
      {
 
447
        case k_BCJ:
 
448
        {
 
449
          UInt32 state;
 
450
          x86_Convert_Init(state);
 
451
          x86_Convert(outBuffer, outSize, 0, &state, 0);
 
452
          break;
 
453
        }
 
454
        CASE_BRA_CONV(ARM)
 
455
        default:
 
456
          return SZ_ERROR_UNSUPPORTED;
 
457
      }
 
458
    }
 
459
  }
 
460
  return SZ_OK;
 
461
}
 
462
 
 
463
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
 
464
    ILookInStream *inStream, UInt64 startPos,
 
465
    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
 
466
{
 
467
  Byte *tempBuf[3] = { 0, 0, 0};
 
468
  int i;
 
469
  SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
 
470
      outBuffer, (SizeT)outSize, allocMain, tempBuf);
 
471
  for (i = 0; i < 3; i++)
 
472
    IAlloc_Free(allocMain, tempBuf[i]);
 
473
  return res;
 
474
}