Browse Source

[Minor] Add preliminary 7z support

tags/1.7.0
Vsevolod Stakhov 6 years ago
parent
commit
cac2158f80
2 changed files with 134 additions and 0 deletions
  1. 133
    0
      src/libmime/archives.c
  2. 1
    0
      src/libmime/archives.h

+ 133
- 0
src/libmime/archives.c View File

@@ -558,6 +558,130 @@ part->flags |= RSPAMD_MIME_PART_ARCHIVE;
arch->size = part->parsed_data.len;
}

static inline gint
rspamd_archive_7zip_read_vint (const guchar *start, gsize remain, guint64 *res)
{
/*
* REAL_UINT64 means real UINT64.
* UINT64 means real UINT64 encoded with the following scheme:
*
* Size of encoding sequence depends from first byte:
* First_Byte Extra_Bytes Value
* (binary)
* 0xxxxxxx : ( xxxxxxx )
* 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
* 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
* ...
* 1111110x BYTE y[6] : ( x << (8 * 6)) + y
* 11111110 BYTE y[7] : y
* 11111111 BYTE y[8] : y
*/
guchar t;

if (remain == 0) {
return -1;
}

t = *start;

if (!isset (&t, 7)) {
/* Trivial case */
*res = t;
return 1;
}
else if (t == 0xFF) {
if (remain >= sizeof (guint64) + 1) {
memcpy (res, start + 1, sizeof (guint64));
*res = GUINT64_FROM_LE (*res);

return sizeof (guint64) + 1;
}
}
else {
gint cur_bit = 6, intlen = 1;
const guchar bmask = 0xFF;
guint64 tgt;

while (cur_bit > 0) {
if (!isset (&t, cur_bit)) {
if (remain >= intlen + 1) {
memcpy (&tgt, start + 1, intlen);
tgt = GUINT64_FROM_LE (tgt);
/* Shift back */
tgt >>= sizeof (tgt) - NBBY * intlen;
/* Add masked value */
tgt += (guint64)(t & (bmask >> (NBBY - cur_bit)))
<< (NBBY * intlen);
*res = tgt;

return intlen + 1;
}
}
cur_bit --;
intlen ++;
}
}

return -1;
}

#define SZ_READ_VINT_SKIP() do { \
r = rspamd_archive_7zip_read_vint (p, end - p, &vint); \
if (r == -1) { \
msg_debug_task ("7z archive is invalid (bad vint)"); \
return; \
} \
p += r; \
} while (0)
#define SZ_READ_VINT(var) do { \
r = rspamd_archive_7zip_read_vint (p, end - p, &(var)); \
if (r == -1) { \
msg_debug_task ("7z archive is invalid (bad vint)"); \
return; \
} \
p += r; \
} while (0)

static void
rspamd_archive_process_7zip (struct rspamd_task *task,
struct rspamd_mime_part *part)
{
struct rspamd_archive *arch;
const guchar *p, *end;
const guchar sz_magic[] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
guint64 section_offset = 0, section_length = 0;
gint r;

p = part->parsed_data.begin;
end = p + part->parsed_data.len;

if (end - p <= sizeof (guint64) + sizeof (guint32) ||
memcmp (p, sz_magic, sizeof (sz_magic)) != 0) {
msg_debug_task ("7z archive is invalid (no 7z magic)");

return;
}

arch = rspamd_mempool_alloc0 (task->task_pool, sizeof (*arch));
arch->files = g_ptr_array_new ();
arch->type = RSPAMD_ARCHIVE_7ZIP;
rspamd_mempool_add_destructor (task->task_pool, rspamd_archive_dtor,
arch);

/* Magic (6 bytes) + version (2 bytes) + crc32 (4 bytes) */
p += sizeof (guint64) + sizeof (guint32);

SZ_READ_VINT(section_offset);
SZ_READ_VINT(section_length);

part->flags |= RSPAMD_MIME_PART_ARCHIVE;
part->specific.arch = arch;
if (part->cd != NULL) {
arch->archive_name = &part->cd->filename;
}
arch->size = part->parsed_data.len;
}

static gboolean
rspamd_archive_cheat_detect (struct rspamd_mime_part *part, const gchar *str,
const guchar *magic_start, gsize magic_len)
@@ -608,6 +732,7 @@ rspamd_archives_process (struct rspamd_task *task)
struct rspamd_mime_part *part;
const guchar rar_magic[] = {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07};
const guchar zip_magic[] = {0x50, 0x4b, 0x03, 0x04};
const guchar sz_magic[] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};

for (i = 0; i < task->parts->len; i ++) {
part = g_ptr_array_index (task->parts, i);
@@ -621,6 +746,11 @@ rspamd_archives_process (struct rspamd_task *task)
rar_magic, sizeof (rar_magic))) {
rspamd_archive_process_rar (task, part);
}
else if (rspamd_archive_cheat_detect (part, "7z",
sz_magic, sizeof (sz_magic))) {
rspamd_archive_process_7zip (task, part);
}

}
}
}
@@ -638,6 +768,9 @@ rspamd_archive_type_str (enum rspamd_archive_type type)
case RSPAMD_ARCHIVE_RAR:
ret = "rar";
break;
case RSPAMD_ARCHIVE_7ZIP:
ret = "7z";
break;
}

return ret;

+ 1
- 0
src/libmime/archives.h View File

@@ -21,6 +21,7 @@
enum rspamd_archive_type {
RSPAMD_ARCHIVE_ZIP,
RSPAMD_ARCHIVE_RAR,
RSPAMD_ARCHIVE_7ZIP,
};

enum rspamd_archive_flags {

Loading…
Cancel
Save