static void fmap_aging(fmap_t *m) { #ifdef ANONYMOUS_MAP if(!m->aging) return; if(m->paged * m->pgsz > UNPAGE_THRSHLD_HI) { /* we alloc'd too much */ unsigned int i, avail = 0, freeme[2048], maxavail = MIN(sizeof(freeme)/sizeof(*freeme), m->paged - UNPAGE_THRSHLD_LO / m->pgsz) - 1; for(i=0; i<m->pages; i++) { uint32_t s = fmap_bitmap[i]; if((s & (FM_MASK_PAGED | FM_MASK_LOCKED)) == FM_MASK_PAGED ) { /* page is paged and not locked: dec age */ if(s & FM_MASK_COUNT) fmap_bitmap[i]--; /* and make it available for unpaging */ if(!avail) { freeme[0] = i; avail++; } else { /* Insert sort onto a stack'd array - same performance as quickselect */ unsigned int insert_to = MIN(maxavail, avail) - 1, age = fmap_bitmap[i] & FM_MASK_COUNT; if(avail <= maxavail || (fmap_bitmap[freeme[maxavail]] & FM_MASK_COUNT) > age) { while((fmap_bitmap[freeme[insert_to]] & FM_MASK_COUNT) > age) { freeme[insert_to + 1] = freeme[insert_to]; if(!insert_to--) break; } freeme[insert_to + 1] = i; if(avail <= maxavail) avail++; } } } } if(avail) { /* at least one page is paged and not locked */ char *lastpage = NULL; char *firstpage = NULL; for(i=0; i<avail; i++) { char *pptr = (char *)m + freeme[i] * m->pgsz + m->hdrsz; /* we mark the page as seen */ fmap_bitmap[freeme[i]] = FM_MASK_SEEN; /* and we mmap the page over so the kernel knows there's nothing good in there */ /* reduce number of mmap calls: if pages are adjacent only do 1 mmap call */ if (lastpage && pptr == lastpage) { lastpage = pptr + m->pgsz; continue; } if (!lastpage) { firstpage = pptr; lastpage = pptr + m->pgsz; continue; } fmap_lock; if(mmap(firstpage, lastpage - firstpage, PROT_READ | PROT_WRITE, MAP_FIXED|MAP_PRIVATE|ANONYMOUS_MAP, -1, 0) == MAP_FAILED) cli_dbgmsg("fmap_aging: kernel hates you\n"); fmap_unlock; firstpage = pptr; lastpage = pptr + m->pgsz; } if (lastpage) { fmap_lock; if(mmap(firstpage, lastpage - firstpage, PROT_READ | PROT_WRITE, MAP_FIXED|MAP_PRIVATE|ANONYMOUS_MAP, -1, 0) == MAP_FAILED) cli_dbgmsg("fmap_aging: kernel hates you\n"); fmap_unlock; } m->paged -= avail; } } #endif }
/* Read 64-bit program headers */ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, struct elf_file_hdr64 *file_hdr, uint8_t conv) { struct elf_program_hdr64 *program_hdr = NULL; uint16_t phnum, phentsize; uint64_t entry, fentry = 0, phoff; uint32_t i; uint8_t err; /* Program headers and Entry */ phnum = file_hdr->e_phnum; cli_dbgmsg("ELF: Number of program headers: %d\n", phnum); if(phnum > 128) { cli_dbgmsg("ELF: Suspicious number of program headers\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } entry = file_hdr->e_entry; if(phnum && entry) { phentsize = file_hdr->e_phentsize; /* Sanity check */ if (phentsize != sizeof(struct elf_program_hdr64)) { cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr64)\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } phoff = file_hdr->e_phoff; if(ctx) { cli_dbgmsg("ELF: Program header table offset: " STDu64 "\n", phoff); } if(phnum) { program_hdr = (struct elf_program_hdr64 *) cli_calloc(phnum, sizeof(struct elf_program_hdr64)); if(!program_hdr) { cli_errmsg("ELF: Can't allocate memory for program headers\n"); return CL_EMEM; } if(ctx) { cli_dbgmsg("------------------------------------\n"); } } for(i = 0; i < phnum; i++) { err = 0; if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr64)) != sizeof(struct elf_program_hdr64)) err = 1; phoff += sizeof(struct elf_program_hdr64); if(err) { cli_dbgmsg("ELF: Can't read segment #%d\n", i); if(ctx) { cli_dbgmsg("ELF: Possibly broken ELF file\n"); } free(program_hdr); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_BREAK; } if(ctx) { cli_dbgmsg("ELF: Segment #%d\n", i); cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv)); cli_dbgmsg("ELF: Segment offset: 0x" STDx64 "\n", EC64(program_hdr[i].p_offset, conv)); cli_dbgmsg("ELF: Segment virtual address: 0x" STDx64 "\n", EC64(program_hdr[i].p_vaddr, conv)); cli_dbgmsg("ELF: Segment real size: 0x" STDx64 "\n", EC64(program_hdr[i].p_filesz, conv)); cli_dbgmsg("ELF: Segment virtual size: 0x" STDx64 "\n", EC64(program_hdr[i].p_memsz, conv)); cli_dbgmsg("------------------------------------\n"); } } fentry = cli_rawaddr64(entry, program_hdr, phnum, conv, &err); free(program_hdr); if(err) { cli_dbgmsg("ELF: Can't calculate file offset of entry point\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } if(ctx) { cli_dbgmsg("ELF: Entry point address: 0x%.16" PRIx64 "\n", entry); cli_dbgmsg("ELF: Entry point offset: 0x%.16" PRIx64 " (" STDi64 ")\n", fentry, fentry); } } if(elfinfo) { elfinfo->ep = fentry; } return CL_CLEAN; }
/* Print section type and selected flags to the log */ static void cli_elf_sectionlog(uint32_t sh_type, uint32_t sh_flags) { switch(sh_type) { case 0x6: /* SHT_DYNAMIC */ cli_dbgmsg("ELF: Section type: Dynamic linking information\n"); break; case 0xb: /* SHT_DYNSYM */ cli_dbgmsg("ELF: Section type: Symbols for dynamic linking\n"); break; case 0xf: /* SHT_FINI_ARRAY */ cli_dbgmsg("ELF: Section type: Array of pointers to termination functions\n"); break; case 0x5: /* SHT_HASH */ cli_dbgmsg("ELF: Section type: Symbol hash table\n"); break; case 0xe: /* SHT_INIT_ARRAY */ cli_dbgmsg("ELF: Section type: Array of pointers to initialization functions\n"); break; case 0x8: /* SHT_NOBITS */ cli_dbgmsg("ELF: Section type: Empty section (NOBITS)\n"); break; case 0x7: /* SHT_NOTE */ cli_dbgmsg("ELF: Section type: Note section\n"); break; case 0x0: /* SHT_NULL */ cli_dbgmsg("ELF: Section type: Null (no associated section)\n"); break; case 0x10: /* SHT_PREINIT_ARRAY */ cli_dbgmsg("ELF: Section type: Array of pointers to preinit functions\n"); break; case 0x1: /* SHT_PROGBITS */ cli_dbgmsg("ELF: Section type: Program information\n"); break; case 0x9: /* SHT_REL */ cli_dbgmsg("ELF: Section type: Relocation entries w/o explicit addends\n"); break; case 0x4: /* SHT_RELA */ cli_dbgmsg("ELF: Section type: Relocation entries with explicit addends\n"); break; case 0x3: /* SHT_STRTAB */ cli_dbgmsg("ELF: Section type: String table\n"); break; case 0x2: /* SHT_SYMTAB */ cli_dbgmsg("ELF: Section type: Symbol table\n"); break; case 0x6ffffffd: /* SHT_GNU_verdef */ cli_dbgmsg("ELF: Section type: Provided symbol versions\n"); break; case 0x6ffffffe: /* SHT_GNU_verneed */ cli_dbgmsg("ELF: Section type: Required symbol versions\n"); break; case 0x6fffffff: /* SHT_GNU_versym */ cli_dbgmsg("ELF: Section type: Symbol Version Table\n"); break; default : cli_dbgmsg("ELF: Section type: Unknown\n"); } if(sh_flags & ELF_SHF_WRITE) cli_dbgmsg("ELF: Section contains writable data\n"); if(sh_flags & ELF_SHF_ALLOC) cli_dbgmsg("ELF: Section occupies memory\n"); if(sh_flags & ELF_SHF_EXECINSTR) cli_dbgmsg("ELF: Section contains executable code\n"); }
static int ooxml_content_cb(int fd, cli_ctx *ctx) { int ret = CL_SUCCESS, tmp, toval = 0, state; int core=0, extn=0, cust=0, dsig=0; int mcore=0, mextn=0, mcust=0; const xmlChar *name, *value, *CT, *PN; xmlTextReaderPtr reader = NULL; uint32_t loff; unsigned long sav_scansize = ctx->scansize; unsigned int sav_scannedfiles = ctx->scannedfiles; cli_dbgmsg("in ooxml_content_cb\n"); /* perform engine limit checks in temporary tracking session */ ret = ooxml_updatelimits(fd, ctx); if (ret != CL_CLEAN) return ret; /* apply a reader to the document */ reader = xmlReaderForFd(fd, "[Content_Types].xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS); if (reader == NULL) { cli_dbgmsg("ooxml_content_cb: xmlReaderForFd error for ""[Content_Types].xml""\n"); cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_XML_READER_FD"); ctx->scansize = sav_scansize; ctx->scannedfiles = sav_scannedfiles; return CL_SUCCESS; // libxml2 failed! } /* locate core-properties, extended-properties, and custom-properties (optional) */ while ((state = xmlTextReaderRead(reader)) == 1) { if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { ret = CL_ETIMEOUT; goto ooxml_content_exit; } name = xmlTextReaderConstLocalName(reader); if (name == NULL) continue; if (strcmp((const char *)name, "Override")) continue; if (xmlTextReaderHasAttributes(reader) != 1) continue; CT = PN = NULL; while (xmlTextReaderMoveToNextAttribute(reader) == 1) { name = xmlTextReaderConstLocalName(reader); value = xmlTextReaderConstValue(reader); if (name == NULL || value == NULL) continue; if (!xmlStrcmp(name, (const xmlChar *)"ContentType")) { CT = value; } else if (!xmlStrcmp(name, (const xmlChar *)"PartName")) { PN = value; } cli_dbgmsg("%s: %s\n", name, value); } if (!CT && !PN) continue; if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-package.core-properties+xml")) { /* default: /docProps/core.xml*/ tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); if (tmp == CL_ETIMEOUT) { ret = tmp; } else if (tmp != CL_VIRUS) { cli_dbgmsg("cli_process_ooxml: failed to find core properties file \"%s\"!\n", PN); mcore++; } else { cli_dbgmsg("ooxml_content_cb: found core properties file \"%s\" @ %x\n", PN, loff); if (!core) { tmp = unzip_single_internal(ctx, loff, ooxml_core_cb); if (tmp == CL_ETIMEOUT || tmp == CL_EMEM) { ret = tmp; } } core++; } } else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-officedocument.extended-properties+xml")) { /* default: /docProps/app.xml */ tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); if (tmp == CL_ETIMEOUT) { ret = tmp; } else if (tmp != CL_VIRUS) { cli_dbgmsg("cli_process_ooxml: failed to find extended properties file \"%s\"!\n", PN); mextn++; } else { cli_dbgmsg("ooxml_content_cb: found extended properties file \"%s\" @ %x\n", PN, loff); if (!extn) { tmp = unzip_single_internal(ctx, loff, ooxml_extn_cb); if (tmp == CL_ETIMEOUT || tmp == CL_EMEM) { ret = tmp; } } extn++; } } else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-officedocument.custom-properties+xml")) { /* default: /docProps/custom.xml */ tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff); if (tmp == CL_ETIMEOUT) { ret = tmp; } else if (tmp != CL_VIRUS) { cli_dbgmsg("cli_process_ooxml: failed to find custom properties file \"%s\"!\n", PN); mcust++; } else { cli_dbgmsg("ooxml_content_cb: found custom properties file \"%s\" @ %x\n", PN, loff); /* custom properties are not parsed */ cust++; } } else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml")) { dsig++; } if (ret != CL_SUCCESS) goto ooxml_content_exit; } ooxml_content_exit: if (core) { cli_jsonint(ctx->wrkproperty, "CorePropertiesFileCount", core); if (core > 1) cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CORE_PROPFILES"); } else if (!mcore) cli_dbgmsg("cli_process_ooxml: file does not contain core properties file\n"); if (mcore) { cli_jsonint(ctx->wrkproperty, "CorePropertiesMissingFileCount", mcore); cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CORE_PROPFILES"); } if (extn) { cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesFileCount", extn); if (extn > 1) cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_EXTN_PROPFILES"); } else if (!mextn) cli_dbgmsg("cli_process_ooxml: file does not contain extended properties file\n"); if (mextn) { cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesMissingFileCount", mextn); cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_EXTN_PROPFILES"); } if (cust) { cli_jsonint(ctx->wrkproperty, "CustomPropertiesFileCount", cust); if (cust > 1) cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CUSTOM_PROPFILES"); } else if (!mcust) cli_dbgmsg("cli_process_ooxml: file does not contain custom properties file\n"); if (mcust) { cli_jsonint(ctx->wrkproperty, "CustomPropertiesMissingFileCount", mcust); cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CUST_PROPFILES"); } if (dsig) { cli_jsonint(ctx->wrkproperty, "DigitalSignaturesCount", dsig); } /* restore the engine tracking limits; resets session limit tracking */ ctx->scansize = sav_scansize; ctx->scannedfiles = sav_scannedfiles; xmlTextReaderClose(reader); xmlFreeTextReader(reader); return ret; }
/* return count of valid strings found, 0 on error */ static int vba_read_project_strings(int fd, int big_endian) { unsigned char *buf = NULL; uint16_t buflen = 0; uint16_t length = 0; int ret = 0, getnewlength = 1; for(;;) { off_t offset; char *name; /* if no initial name length, exit */ if(getnewlength && !read_uint16(fd, &length, big_endian)) { ret = 0; break; } getnewlength = 0; /* if too short, break */ if (length < 6) { if (lseek(fd, -2, SEEK_CUR) == -1) { cli_dbgmsg("vba_read_project_strings: call to lseek() has failed\n"); ret = 0; } break; } /* ensure buffer is large enough */ if(length > buflen) { unsigned char *newbuf = (unsigned char *)cli_realloc(buf, length); if(newbuf == NULL) { ret = 0; break; } buflen = length; buf = newbuf; } /* save current offset */ offset = lseek(fd, 0, SEEK_CUR); if (offset == -1) { cli_dbgmsg("vba_read_project_strings: call to lseek() has failed\n"); ret = 0; break; } /* if read name failed, break */ if(cli_readn(fd, buf, length) != (int)length) { cli_dbgmsg("read name failed - rewinding\n"); if (lseek(fd, offset, SEEK_SET) == -1) { cli_dbgmsg("call to lseek() in read name failed\n"); ret = 0; } break; } name = get_unicode_name((const char *)buf, length, big_endian); cli_dbgmsg("length: %d, name: %s\n", length, (name) ? name : "[null]"); /* if invalid name, break */ if((name == NULL) || (memcmp("*\\", name, 2) != 0) || (strchr("ghcd", name[2]) == NULL)) { /* Not a valid string, rewind */ if (lseek(fd, -(length+2), SEEK_CUR) == -1) { cli_dbgmsg("call to lseek() after get_unicode_name has failed\n"); ret = 0; } free(name); break; } free(name); /* can't get length, break */ if(!read_uint16(fd, &length, big_endian)) { break; } ret++; /* continue on reasonable length value */ if ((length != 0) && (length != 65535)) { continue; } /* determine offset and run middle test */ offset = lseek(fd, 10, SEEK_CUR); if (offset == -1) { cli_dbgmsg("call to lseek() has failed\n"); ret = 0; break; } cli_dbgmsg("offset: %lu\n", (unsigned long)offset); vba56_test_middle(fd); getnewlength = 1; } free(buf); return ret; }
int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit, const struct cli_dconf *dconf) { unsigned int i; int ret; struct cli_pcre_meta *pm = NULL; int disable_all = 0; if (dconf && !(dconf->pcre & PCRE_CONF_SUPPORT)) disable_all = 1; for (i = 0; i < root->pcre_metas; ++i) { pm = root->pcre_metatable[i]; if (!pm) { cli_errmsg("cli_pcre_build: metadata for pcre %d is missing\n", i); return CL_ENULLARG; } /* for safety, disable all pcre */ if (disable_all) { pm->flags |= CLI_PCRE_DISABLED; continue; } if (pm->flags & CLI_PCRE_DISABLED) { cli_dbgmsg("cli_pcre_build: Skip compiling regex: %s (disabled)\n", pm->pdata.expression); continue; } /* disable global */ if (dconf && !(dconf->pcre & PCRE_CONF_GLOBAL)) { cli_dbgmsg("cli_pcre_build: disabling global option for regex /%s/\n", pm->pdata.expression); pm->flags &= ~(CLI_PCRE_GLOBAL); } /* options override through metadata manipulation */ #if USING_PCRE2 //pm->pdata.options |= PCRE2_NEVER_UTF; /* disables (?UTF*) potential security vuln */ //pm->pdata.options |= PCRE2_UCP; //pm->pdata.options |= PCRE2_AUTO_CALLOUT; /* used with CALLOUT(-BACK) function */ #else //pm->pdata.options |= PCRE_NEVER_UTF; /* implemented in 8.33, disables (?UTF*) potential security vuln */ //pm->pdata.options |= PCRE_UCP;/* implemented in 8.20 */ //pm->pdata.options |= PCRE_AUTO_CALLOUT; /* used with CALLOUT(-BACK) function */ #endif if (dconf && (dconf->pcre & PCRE_CONF_OPTIONS)) { /* compile the regex, no options override *wink* */ pm_dbgmsg("cli_pcre_build: Compiling regex: /%s/\n", pm->pdata.expression); ret = cli_pcre_compile(&(pm->pdata), match_limit, recmatch_limit, 0, 0); } else { /* compile the regex, options overridden and disabled */ pm_dbgmsg("cli_pcre_build: Compiling regex: /%s/ (without options)\n", pm->pdata.expression); ret = cli_pcre_compile(&(pm->pdata), match_limit, recmatch_limit, 0, 1); } if (ret != CL_SUCCESS) { cli_errmsg("cli_pcre_build: failed to build pcre regex\n"); pm->flags |= CLI_PCRE_DISABLED; /* disable the pcre, currently will terminate execution */ return ret; } } return CL_SUCCESS; }
void cli_detect_swizz_str(const unsigned char *str, uint32_t len, struct swizz_stats *stats, int blob) { unsigned char stri[4096]; uint32_t i, j = 0; int bad = 0; int lastalnum = 0; uint8_t ngrams[17576]; uint16_t all=0; uint16_t ngram_cnts[3]; uint16_t words = 0; int ret; stats->entries++; for(i=0;i<len-1 && j < sizeof(stri)-2;i += 2) { unsigned char c = str[i]; if (str[i+1] || !c) { bad++; continue; } if (!isalnum(c)) { if (!lastalnum) continue; lastalnum = 0; c = ' '; } else { lastalnum = 1; if (isdigit(c)) continue; } stri[j++] = tolower(c); } stri[j++] = '\0'; if ((!blob && (bad >= 8)) || j < 4) return; memset(ngrams, 0, sizeof(ngrams)); memset(ngram_cnts, 0, sizeof(ngram_cnts)); for(i=0;i<j-2;i++) { if (stri[i] != ' ' && stri[i+1] != ' ' && stri[i+2] != ' ') { uint16_t idx = (stri[i] - 'a')*676 + (stri[i+1] - 'a')*26 + (stri[i+2] - 'a'); if (idx < sizeof(ngrams)) { ngrams[idx]++; stats->gngrams[idx]++; } } else if (stri[i] == ' ') words++; } for(i=0;i<sizeof(ngrams);i++) { uint8_t v = ngrams[i]; if (v > 3) v = 3; if (v) { ngram_cnts[v-1]++; all++; } } if (!all) return; cli_dbgmsg("cli_detect_swizz_str: %u, %u, %u\n",ngram_cnts[0],ngram_cnts[1],ngram_cnts[2]); /* normalize */ for(i=0;i<sizeof(ngram_cnts)/sizeof(ngram_cnts[0]);i++) { uint32_t v = ngram_cnts[i]; ngram_cnts[i] = (v<<10)/all; } ret = swizz_j48(ngram_cnts) ? CL_VIRUS : CL_CLEAN; if (words < 3) ret = CL_CLEAN; cli_dbgmsg("cli_detect_swizz_str: %s, %u words\n", ret == CL_VIRUS ? "suspicious" : "ok", words); if (ret == CL_VIRUS) { stats->suspicious += j; cli_dbgmsg("cli_detect_swizz_str: %s\n", stri); } stats->total += j; }
static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, crtmgr *master, crtmgr *other) { struct cli_asn1 crt, tbs, obj; unsigned int avail, tbssize, issuersize; cli_crt_hashtype hashtype1, hashtype2; cli_crt x509; const uint8_t *tbsdata; const void *next, *issuer; if(cli_crt_init(&x509)) return 1; do { if(asn1_expect_objtype(map, *asn1data, size, &crt, 0x30)) /* SEQUENCE */ break; *asn1data = crt.next; tbsdata = crt.content; if(asn1_expect_objtype(map, crt.content, &crt.size, &tbs, 0x30)) /* SEQUENCE - TBSCertificate */ break; tbssize = (uint8_t *)tbs.next - tbsdata; if(asn1_expect_objtype(map, tbs.content, &tbs.size, &obj, 0xa0)) /* [0] */ break; avail = obj.size; next = obj.next; if(asn1_expect_obj(map, &obj.content, &avail, 0x02, 1, "\x02")) /* version 3 only */ break; if(avail) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in version\n"); break; } if(asn1_expect_objtype(map, next, &tbs.size, &obj, 0x02)) /* serialNumber */ break; if(map_sha1(map, obj.content, obj.size, x509.serial)) break; if(asn1_expect_rsa(map, &obj.next, &tbs.size, &hashtype1)) /* algo = sha1WithRSAEncryption | md5WithRSAEncryption */ break; if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, 0x30)) /* issuer */ break; issuer = obj.content; issuersize = obj.size; if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, 0x30)) /* validity */ break; avail = obj.size; next = obj.content; if(asn1_get_time(map, &next, &avail, &x509.not_before)) /* notBefore */ break; if(asn1_get_time(map, &next, &avail, &x509.not_after)) /* notAfter */ break; if(x509.not_before >= x509.not_after) { cli_dbgmsg("asn1_get_x509: bad validity\n"); break; } if(avail) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in validity\n"); break; } if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, 0x30)) /* subject */ break; if(map_sha1(map, obj.content, obj.size, x509.subject)) break; if(asn1_get_rsa_pubkey(map, &obj.next, &tbs.size, &x509)) break; avail = 0; while(tbs.size) { if(asn1_get_obj(map, obj.next, &tbs.size, &obj)) { tbs.size = 1; break; } if(obj.type <= 0xa0 + avail || obj.type > 0xa3) { cli_dbgmsg("asn1_get_x509: found type %02x in extensions, expecting a1, a2 or a3\n", obj.type); tbs.size = 1; break; } avail = obj.type - 0xa0; if(obj.type == 0xa3) { struct cli_asn1 exts; int have_ext_key = 0; if(asn1_expect_objtype(map, obj.content, &obj.size, &exts, 0x30)) { tbs.size = 1; break; } if(obj.size) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in extensions\n"); break; } while(exts.size) { struct cli_asn1 ext, id, value; if(asn1_expect_objtype(map, exts.content, &exts.size, &ext, 0x30)) { exts.size = 1; break; } exts.content = ext.next; if(asn1_expect_objtype(map, ext.content, &ext.size, &id, 0x06)) { exts.size = 1; break; } if(asn1_get_obj(map, id.next, &ext.size, &value)) { exts.size = 1; break; } if(value.type == 0x01) { /* critical flag */ if(value.size != 1) { cli_dbgmsg("asn1_get_x509: found boolean with wrong length\n"); exts.size = 1; break; } if(asn1_get_obj(map, value.next, &ext.size, &value)) { exts.size = 1; break; } } if(value.type != 0x04) { cli_dbgmsg("asn1_get_x509: bad extension value type %u\n", value.type); exts.size = 1; break; } if(ext.size) { cli_dbgmsg("asn1_get_x509: extra data in extension\n"); exts.size = 1; break; } if(id.size != 3) continue; if(!fmap_need_ptr_once(map, id.content, 3)) { exts.size = 1; break; } if(!memcmp("\x55\x1d\x0f", id.content, 3)) { /* KeyUsage 2.5.29.15 */ const uint8_t *keyusage = value.content; uint8_t usage; if(value.size < 4 || value.size > 5) { cli_dbgmsg("asn1_get_x509: bad KeyUsage\n"); exts.size = 1; break; } if(!fmap_need_ptr_once(map, value.content, value.size)) { exts.size = 1; break; } if(keyusage[0] != 0x03 || keyusage[1] != value.size - 2 || keyusage[2] > 7) { cli_dbgmsg("asn1_get_x509: bad KeyUsage\n"); exts.size = 1; break; } usage = keyusage[3]; if(value.size == 4) usage &= ~((1 << keyusage[2])-1); x509.certSign = ((usage & 4) != 0); continue; } if(!memcmp("\x55\x1d\x25", id.content, 3)) { /* ExtKeyUsage 2.5.29.37 */ struct cli_asn1 keypurp; have_ext_key = 1; if(asn1_expect_objtype(map, value.content, &value.size, &keypurp, 0x30)) { exts.size = 1; break; } if(value.size) { cli_dbgmsg("asn1_get_x509: extra data in ExtKeyUsage\n"); exts.size = 1; break; } ext.next = keypurp.content; while(keypurp.size) { if(asn1_expect_objtype(map, ext.next, &keypurp.size, &ext, 0x06)) { exts.size = 1; break; } if(ext.size != 8) continue; if(!fmap_need_ptr_once(map, ext.content, 8)) { exts.size = 1; break; } if(!memcmp("\x2b\x06\x01\x05\x05\x07\x03\x03", ext.content, 8)) /* id_kp_codeSigning */ x509.codeSign = 1; else if(!memcmp("\x2b\x06\x01\x05\x05\x07\x03\x08", ext.content, 8)) /* id_kp_timeStamping */ x509.timeSign = 1; } continue; } if(!memcmp("\x55\x1d\x13", id.content, 3)) { /* Basic Constraints 2.5.29.19 */ struct cli_asn1 constr; if(asn1_expect_objtype(map, value.content, &value.size, &constr, 0x30)) { exts.size = 1; break; } if(!constr.size) x509.certSign = 0; else { if(asn1_expect_objtype(map, constr.content, &constr.size, &ext, 0x01)) { exts.size = 1; break; } if(ext.size != 1) { cli_dbgmsg("asn1_get_x509: wrong bool size in basic constraint %u\n", ext.size); exts.size = 1; break; } if(!fmap_need_ptr_once(map, ext.content, 1)) { exts.size = 1; break; } x509.certSign = (((uint8_t *)(ext.content))[0] != 0); } } } if(exts.size) { tbs.size = 1; break; } if(!have_ext_key) x509.codeSign = x509.timeSign = 1; } } if(tbs.size) break; if(crtmgr_lookup(master, &x509) || crtmgr_lookup(other, &x509)) { cli_dbgmsg("asn1_get_x509: certificate already exists\n"); cli_crt_clear(&x509); return 0; } if(map_sha1(map, issuer, issuersize, x509.issuer)) break; if(asn1_expect_rsa(map, &tbs.next, &crt.size, &hashtype2)) /* signature algo = sha1WithRSAEncryption | md5WithRSAEncryption */ break; if(hashtype1 != hashtype2) { cli_dbgmsg("asn1_get_x509: found conflicting rsa hash types\n"); break; } x509.hashtype = hashtype1; if(asn1_expect_objtype(map, tbs.next, &crt.size, &obj, 0x03)) /* signature */ break; if(obj.size > 513) { cli_dbgmsg("asn1_get_x509: signature too long\n"); break; } if(!fmap_need_ptr_once(map, obj.content, obj.size)) { cli_dbgmsg("asn1_get_x509: cannot read signature\n"); break; } if(mp_read_unsigned_bin(&x509.sig, obj.content, obj.size)) { cli_dbgmsg("asn1_get_x509: cannot convert signature to big number\n"); break; } if(crt.size) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in signature\n"); break; } if((x509.hashtype == CLI_SHA1RSA && map_sha1(map, tbsdata, tbssize, x509.tbshash)) || (x509.hashtype == CLI_MD5RSA && (map_md5(map, tbsdata, tbssize, x509.tbshash)))) break; if(crtmgr_add(other, &x509)) break; cli_crt_clear(&x509); return 0; } while(0); cli_crt_clear(&x509); return 1; }
static int asn1_parse_mscat(fmap_t *map, size_t offset, unsigned int size, crtmgr *cmgr, int embedded, const void **hashes, unsigned int *hashes_size, struct cl_engine *engine) { struct cli_asn1 asn1, deep, deeper; uint8_t sha1[SHA1_HASH_SIZE], issuer[SHA1_HASH_SIZE], md[SHA1_HASH_SIZE], serial[SHA1_HASH_SIZE]; const uint8_t *message, *attrs; unsigned int dsize, message_size, attrs_size; cli_crt_hashtype hashtype; cli_crt *x509; void *ctx; int result; int isBlacklisted = 0; cli_dbgmsg("in asn1_parse_mscat\n"); do { if(!(message = fmap_need_off_once(map, offset, 1))) { cli_dbgmsg("asn1_parse_mscat: failed to read pkcs#7 entry\n"); break; } if(asn1_expect_objtype(map, message, &size, &asn1, 0x30)) /* SEQUENCE */ break; /* if(size) { */ /* cli_dbgmsg("asn1_parse_mscat: found extra data after pkcs#7 %u\n", size); */ /* break; */ /* } */ size = asn1.size; if(asn1_expect_obj(map, &asn1.content, &size, 0x06, lenof(OID_signedData), OID_signedData)) /* OBJECT 1.2.840.113549.1.7.2 - contentType = signedData */ break; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0xa0)) /* [0] - content */ break; if(size) { cli_dbgmsg("asn1_parse_mscat: found extra data in pkcs#7\n"); break; } size = asn1.size; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) /* SEQUENCE */ break; if(size) { cli_dbgmsg("asn1_parse_mscat: found extra data in signedData\n"); break; } size = asn1.size; if(asn1_expect_obj(map, &asn1.content, &size, 0x02, 1, "\x01")) /* INTEGER - VERSION 1 */ break; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x31)) /* SET OF DigestAlgorithmIdentifier */ break; if(asn1_expect_algo(map, &asn1.content, &asn1.size, lenof(OID_sha1), OID_sha1)) /* DigestAlgorithmIdentifier[0] == sha1 */ break; if(asn1.size) { cli_dbgmsg("asn1_parse_mscat: only one digestAlgorithmIdentifier is allowed\n"); break; } if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x30)) /* SEQUENCE - contentInfo */ break; /* Here there is either a PKCS #7 ContentType Object Identifier for Certificate Trust List (szOID_CTL) * or a single SPC_INDIRECT_DATA_OBJID */ if( (!embedded && asn1_expect_obj(map, &asn1.content, &asn1.size, 0x06, lenof(OID_szOID_CTL), OID_szOID_CTL)) || (embedded && asn1_expect_obj(map, &asn1.content, &asn1.size, 0x06, lenof(OID_SPC_INDIRECT_DATA_OBJID), OID_SPC_INDIRECT_DATA_OBJID)) ) break; if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0xa0)) break; if(asn1.size) { cli_dbgmsg("asn1_parse_mscat: found extra data in contentInfo\n"); break; } dsize = deep.size; if(asn1_expect_objtype(map, deep.content, &dsize, &deep, 0x30)) break; if(dsize) { cli_dbgmsg("asn1_parse_mscat: found extra data in content\n"); break; } *hashes = deep.content; *hashes_size = deep.size; if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa0)) /* certificates */ break; dsize = asn1.size; if(dsize) { crtmgr newcerts; crtmgr_init(&newcerts); while(dsize) { if(asn1_get_x509(map, &asn1.content, &dsize, cmgr, &newcerts)) { dsize = 1; break; } } if(dsize) break; if(newcerts.crts) { x509 = newcerts.crts; cli_dbgmsg("asn1_parse_mscat: %u new certificates collected\n", newcerts.items); while(x509) { cli_crt *parent = crtmgr_verify_crt(cmgr, x509); /* Dump the cert if requested before anything happens to it */ if (engine->dconf->pe & PE_CONF_DUMPCERT) { char issuer[SHA1_HASH_SIZE*2+1], subject[SHA1_HASH_SIZE*2+1], serial[SHA1_HASH_SIZE*2+1]; char mod[1024], exp[1024]; int j=1024; fp_toradix_n(&x509->n, mod, 16, j); fp_toradix_n(&x509->e, exp, 16, j); for (j=0; j < SHA1_HASH_SIZE; j++) { sprintf(&issuer[j*2], "%02x", x509->issuer[j]); sprintf(&subject[j*2], "%02x", x509->subject[j]); sprintf(&serial[j*2], "%02x", x509->serial[j]); } cli_dbgmsg_internal("cert subject:%s serial:%s pubkey:%s i:%s %lu->%lu %s %s %s\n", subject, serial, mod, issuer, (unsigned long)x509->not_before, (unsigned long)x509->not_after, x509->certSign ? "cert" : "", x509->codeSign ? "code" : "", x509->timeSign ? "time" : ""); } if(parent) { if (parent->isBlacklisted) { isBlacklisted = 1; cli_dbgmsg("asn1_parse_mscat: Authenticode certificate %s is revoked. Flagging sample as virus.\n", (parent->name ? parent->name : "(no name)")); } x509->codeSign &= parent->codeSign; x509->timeSign &= parent->timeSign; if(crtmgr_add(cmgr, x509)) break; crtmgr_del(&newcerts, x509); x509 = newcerts.crts; continue; } x509 = x509->next; } if(x509) break; if(newcerts.items) cli_dbgmsg("asn1_parse_mscat: %u certificates did not verify\n", newcerts.items); crtmgr_free(&newcerts); } } if(asn1_get_obj(map, asn1.next, &size, &asn1)) break; if(asn1.type == 0xa1 && asn1_get_obj(map, asn1.next, &size, &asn1)) /* crls - unused shouldn't be present */ break; if(asn1.type != 0x31) { /* signerInfos */ cli_dbgmsg("asn1_parse_mscat: unexpected type %02x for signerInfos\n", asn1.type); break; } if(size) { cli_dbgmsg("asn1_parse_mscat: unexpected extra data after signerInfos\n"); break; } size = asn1.size; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) break; if(size) { cli_dbgmsg("asn1_parse_mscat: only one signerInfo shall be present\n"); break; } size = asn1.size; if(asn1_expect_obj(map, &asn1.content, &size, 0x02, 1, "\x01")) /* Version = 1 */ break; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) /* issuerAndSerialNumber */ break; dsize = asn1.size; if(asn1_expect_objtype(map, asn1.content, &dsize, &deep, 0x30)) /* issuer */ break; if(map_sha1(map, deep.content, deep.size, issuer)) break; if(asn1_expect_objtype(map, deep.next, &dsize, &deep, 0x02)) /* serial */ break; if(map_sha1(map, deep.content, deep.size, serial)) break; if(dsize) { cli_dbgmsg("asn1_parse_mscat: extra data inside issuerAndSerialNumber\n"); break; } if(asn1_expect_algo(map, &asn1.next, &size, lenof(OID_sha1), OID_sha1)) /* digestAlgorithm == sha1 */ break; attrs = asn1.next; if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa0)) /* authenticatedAttributes */ break; attrs_size = (uint8_t *)(asn1.next) - attrs; if(attrs_size < 2) { cli_dbgmsg("asn1_parse_mscat: authenticatedAttributes size is too small\n"); break; } dsize = asn1.size; deep.next = asn1.content; result = 0; while(dsize) { struct cli_asn1 cobj; int content; if(asn1_expect_objtype(map, deep.next, &dsize, &deep, 0x30)) { /* attribute */ dsize = 1; break; } if(asn1_expect_objtype(map, deep.content, &deep.size, &deeper, 0x06)) { /* attribute type */ dsize = 1; break; } if(deeper.size != lenof(OID_contentType)) continue; if(!fmap_need_ptr_once(map, deeper.content, lenof(OID_contentType))) { cli_dbgmsg("asn1_parse_mscat: failed to read authenticated attribute\n"); dsize = 1; break; } if(!memcmp(deeper.content, OID_contentType, lenof(OID_contentType))) content = 0; /* contentType */ else if(!memcmp(deeper.content, OID_messageDigest, lenof(OID_messageDigest))) content = 1; /* messageDigest */ else continue; if(asn1_expect_objtype(map, deeper.next, &deep.size, &deeper, 0x31)) { /* set - contents */ dsize = 1; break; } if(deep.size) { cli_dbgmsg("asn1_parse_mscat: extra data in authenticated attributes\n"); dsize = 1; break; } if(result & (1<<content)) { cli_dbgmsg("asn1_parse_mscat: contentType or messageDigest appear twice\n"); dsize = 1; break; } if(content == 0) { /* contentType */ if( (!embedded && asn1_expect_obj(map, &deeper.content, &deeper.size, 0x06, lenof(OID_szOID_CTL), OID_szOID_CTL)) || /* cat file */ (embedded && asn1_expect_obj(map, &deeper.content, &deeper.size, 0x06, lenof(OID_SPC_INDIRECT_DATA_OBJID), OID_SPC_INDIRECT_DATA_OBJID)) /* embedded cat */ ) { dsize = 1; break; } result |= 1; } else { /* messageDigest */ if(asn1_expect_objtype(map, deeper.content, &deeper.size, &cobj, 0x04)) { dsize = 1; break; } if(cobj.size != SHA1_HASH_SIZE) { cli_dbgmsg("asn1_parse_mscat: messageDigest attribute has got the wrong size (%u)\n", cobj.size); dsize = 1; break; } if(!fmap_need_ptr_once(map, cobj.content, SHA1_HASH_SIZE)) { cli_dbgmsg("asn1_parse_mscat: failed to read authenticated attribute\n"); dsize = 1; break; } memcpy(md, cobj.content, SHA1_HASH_SIZE); result |= 2; } if(deeper.size) { cli_dbgmsg("asn1_parse_mscat: extra data in authenticated attribute\n"); dsize = 1; break; } } if(dsize) break; if(result != 3) { cli_dbgmsg("asn1_parse_mscat: contentType or messageDigest are missing\n"); break; } if(asn1_expect_algo(map, &asn1.next, &size, lenof(OID_rsaEncryption), OID_rsaEncryption)) /* digestEncryptionAlgorithm == sha1 */ break; if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x04)) /* encryptedDigest */ break; if(asn1.size > 513) { cli_dbgmsg("asn1_parse_mscat: encryptedDigest too long\n"); break; } if(map_sha1(map, *hashes, *hashes_size, sha1)) break; if(memcmp(sha1, md, sizeof(sha1))) { cli_dbgmsg("asn1_parse_mscat: messageDigest mismatch\n"); break; } if(!fmap_need_ptr_once(map, attrs, attrs_size)) { cli_dbgmsg("asn1_parse_mscat: failed to read authenticatedAttributes\n"); break; } ctx = cl_hash_init("sha1"); if (!(ctx)) break; cl_update_hash(ctx, "\x31", 1); cl_update_hash(ctx, (void *)(attrs + 1), attrs_size - 1); cl_finish_hash(ctx, sha1); if(!fmap_need_ptr_once(map, asn1.content, asn1.size)) { cli_dbgmsg("asn1_parse_mscat: failed to read encryptedDigest\n"); break; } if(!(x509 = crtmgr_verify_pkcs7(cmgr, issuer, serial, asn1.content, asn1.size, CLI_SHA1RSA, sha1, VRFY_CODE))) { cli_dbgmsg("asn1_parse_mscat: pkcs7 signature verification failed\n"); break; } message = asn1.content; message_size = asn1.size; if(!size) { cli_dbgmsg("asn1_parse_mscat: countersignature is missing\n"); break; } if(size && asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa1)) /* unauthenticatedAttributes */ break; if(size) { cli_dbgmsg("asn1_parse_mscat: extra data inside signerInfo\n"); break; } size = asn1.size; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) break; if(size) { cli_dbgmsg("asn1_parse_mscat: extra data inside unauthenticatedAttributes\n"); break; } size = asn1.size; /* 1.2.840.113549.1.9.6 - counterSignature */ if(asn1_expect_obj(map, &asn1.content, &size, 0x06, lenof(OID_countersignature), OID_countersignature)) break; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x31)) break; if(size) { cli_dbgmsg("asn1_parse_mscat: extra data inside counterSignature\n"); break; } size = asn1.size; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) break; if(size) { cli_dbgmsg("asn1_parse_mscat: extra data inside unauthenticatedAttributes\n"); break; } size = asn1.size; if(asn1_expect_obj(map, &asn1.content, &size, 0x02, 1, "\x01")) /* Version = 1*/ break; if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) /* issuerAndSerialNumber */ break; if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0x30)) /* issuer */ break; if(map_sha1(map, deep.content, deep.size, issuer)) break; if(asn1_expect_objtype(map, deep.next, &asn1.size, &deep, 0x02)) /* serial */ break; if(map_sha1(map, deep.content, deep.size, serial)) break; if(asn1.size) { cli_dbgmsg("asn1_parse_mscat: extra data inside countersignature issuer\n"); break; } if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x30)) /* digestAlgorithm */ break; if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0x06)) break; if(deep.size != lenof(OID_sha1) && deep.size != lenof(OID_md5)) { cli_dbgmsg("asn1_parse_mscat: wrong digestAlgorithm size\n"); break; } if(!fmap_need_ptr_once(map, deep.content, deep.size)) { cli_dbgmsg("asn1_parse_mscat: failed to read digestAlgorithm OID\n"); break; } if(deep.size == lenof(OID_sha1) && !memcmp(deep.content, OID_sha1, lenof(OID_sha1))) { hashtype = CLI_SHA1RSA; if(map_sha1(map, message, message_size, md)) break; } else if(deep.size == lenof(OID_md5) && !memcmp(deep.content, OID_md5, lenof(OID_md5))) { hashtype = CLI_MD5RSA; if(map_md5(map, message, message_size, md)) break; } else { cli_dbgmsg("asn1_parse_mscat: unknown digest oid in countersignature\n"); break; } if(asn1.size && asn1_expect_obj(map, &deep.next, &asn1.size, 0x05, 0, NULL)) break; if(asn1.size) { cli_dbgmsg("asn1_parse_mscat: extra data in countersignature oid\n"); break; } attrs = asn1.next; if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa0)) /* authenticatedAttributes */ break; attrs_size = (uint8_t *)(asn1.next) - attrs; if(attrs_size < 2) { cli_dbgmsg("asn1_parse_mscat: countersignature authenticatedAttributes are too small\n"); break; } result = 0; dsize = asn1.size; deep.next = asn1.content; while(dsize) { int content; if(asn1_expect_objtype(map, deep.next, &dsize, &deep, 0x30)) { /* attribute */ dsize = 1; break; } if(asn1_expect_objtype(map, deep.content, &deep.size, &deeper, 0x06)) { /* attribute type */ dsize = 1; break; } if(deeper.size != lenof(OID_contentType)) /* lenof(contentType) = lenof(messageDigest) = lenof(signingTime) = 9 */ continue; if(!fmap_need_ptr_once(map, deeper.content, lenof(OID_contentType))) { dsize = 1; break; } if(!memcmp(deeper.content, OID_contentType, lenof(OID_contentType))) content = 0; /* contentType */ else if(!memcmp(deeper.content, OID_messageDigest, lenof(OID_messageDigest))) content = 1; /* messageDigest */ else if(!memcmp(deeper.content, OID_signingTime, lenof(OID_signingTime))) content = 2; /* signingTime */ else continue; if(result & (1<<content)) { cli_dbgmsg("asn1_parse_mscat: duplicate field in countersignature\n"); dsize = 1; break; } result |= (1<<content); if(asn1_expect_objtype(map, deeper.next, &deep.size, &deeper, 0x31)) { /* attribute type */ dsize = 1; break; } if(deep.size) { cli_dbgmsg("asn1_parse_mscat: extra data in countersignature value\n"); dsize = 1; break; } deep.size = deeper.size; switch(content) { case 0: /* contentType = pkcs7-data */ if(asn1_expect_obj(map, &deeper.content, &deep.size, 0x06, lenof(OID_pkcs7_data), OID_pkcs7_data)) deep.size = 1; else if(deep.size) cli_dbgmsg("asn1_parse_mscat: extra data in countersignature content-type\n"); break; case 1: /* messageDigest */ if(asn1_expect_obj(map, &deeper.content, &deep.size, 0x04, (hashtype == CLI_SHA1RSA) ? SHA1_HASH_SIZE : 16, md)) { deep.size = 1; cli_dbgmsg("asn1_parse_mscat: countersignature hash mismatch\n"); } else if(deep.size) cli_dbgmsg("asn1_parse_mscat: extra data in countersignature message-digest\n"); break; case 2: /* signingTime */ { time_t sigdate; /* FIXME shall i use it?! */ if(asn1_get_time(map, &deeper.content, &deep.size, &sigdate)) deep.size = 1; else if(deep.size) cli_dbgmsg("asn1_parse_mscat: extra data in countersignature signing-time\n"); else if(sigdate < x509->not_before || sigdate > x509->not_after) { cli_dbgmsg("asn1_parse_mscat: countersignature timestamp outside cert validity\n"); deep.size = 1; } break; } } if(deep.size) { dsize = 1; break; } } if(dsize) break; if(result != 7) { cli_dbgmsg("asn1_parse_mscat: some important attributes are missing in countersignature\n"); break; } if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x30)) /* digestEncryptionAlgorithm == sha1 */ break; if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0x06)) /* digestEncryptionAlgorithm == sha1 */ break; if(deep.size != lenof(OID_rsaEncryption)) { /* lenof(OID_rsaEncryption) = lenof(OID_sha1WithRSAEncryption) = 9 */ cli_dbgmsg("asn1_parse_mscat: wrong digestEncryptionAlgorithm size in countersignature\n"); break; } if(!fmap_need_ptr_once(map, deep.content, lenof(OID_rsaEncryption))) { cli_dbgmsg("asn1_parse_mscat: cannot read digestEncryptionAlgorithm in countersignature\n"); break; } /* rsaEncryption or sha1withRSAEncryption */ if(memcmp(deep.content, OID_rsaEncryption, lenof(OID_rsaEncryption)) && memcmp(deep.content, OID_sha1WithRSAEncryption, lenof(OID_sha1WithRSAEncryption))) { cli_dbgmsg("asn1_parse_mscat: digestEncryptionAlgorithm in countersignature is not sha1\n"); break; } if(asn1.size && asn1_expect_obj(map, &deep.next, &asn1.size, 0x05, 0, NULL)) break; if(asn1.size) { cli_dbgmsg("asn1_parse_mscat: extra data in digestEncryptionAlgorithm in countersignature\n"); break; } if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x04)) /* encryptedDigest */ break; if(asn1.size > 513) { cli_dbgmsg("asn1_parse_mscat: countersignature encryptedDigest too long\n"); break; } if(size) { cli_dbgmsg("asn1_parse_mscat: extra data inside countersignature\n"); break; } if(!fmap_need_ptr_once(map, attrs, attrs_size)) { cli_dbgmsg("asn1_parse_mscat: failed to read authenticatedAttributes\n"); break; } if(hashtype == CLI_SHA1RSA) { ctx = cl_hash_init("sha1"); if (!(ctx)) break; cl_update_hash(ctx, "\x31", 1); cl_update_hash(ctx, (void *)(attrs + 1), attrs_size - 1); cl_finish_hash(ctx, sha1); } else { ctx = cl_hash_init("md5"); if (!(ctx)) break; cl_update_hash(ctx, "\x31", 1); cl_update_hash(ctx, (void *)(attrs + 1), attrs_size - 1); cl_finish_hash(ctx, sha1); } if(!fmap_need_ptr_once(map, asn1.content, asn1.size)) { cli_dbgmsg("asn1_parse_mscat: failed to read countersignature encryptedDigest\n"); break; } if(!crtmgr_verify_pkcs7(cmgr, issuer, serial, asn1.content, asn1.size, hashtype, sha1, VRFY_TIME)) { cli_dbgmsg("asn1_parse_mscat: pkcs7 countersignature verification failed\n"); break; } cli_dbgmsg("asn1_parse_mscat: catalog successfully parsed\n"); if (isBlacklisted) { return 1; } return 0; } while(0); cli_dbgmsg("asn1_parse_mscat: failed to parse catalog\n"); return 1; }
static int asn1_get_time(fmap_t *map, const void **asn1data, unsigned int *size, time_t *tm) { struct cli_asn1 obj; int ret = asn1_get_obj(map, *asn1data, size, &obj); unsigned int len; char *ptr; struct tm t; int n; if(ret) return ret; if(obj.type == 0x17) /* UTCTime - YYMMDDHHMMSSZ */ len = 13; else if(obj.type == 0x18) /* GeneralizedTime - YYYYMMDDHHMMSSZ */ len = 15; else { cli_dbgmsg("asn1_get_time: expected UTCTime or GeneralizedTime, got %02x\n", obj.type); return 1; } if(!fmap_need_ptr_once(map, obj.content, len)) { cli_dbgmsg("asn1_get_time: failed to read content\n"); return 1; } memset(&t, 0, sizeof(t)); ptr = (char *)obj.content; if(obj.type == 0x18) { t.tm_year = asn1_getnum(ptr) * 100; if(t.tm_year < 0) return 1; n = asn1_getnum(ptr); if(n<0) return 1; t.tm_year += n; ptr+=4; } else { n = asn1_getnum(ptr); if(n<0) return 1; if(n>=50) t.tm_year = 1900 + n; else t.tm_year = 2000 + n; ptr += 2; } t.tm_year -= 1900; n = asn1_getnum(ptr); if(n<1 || n>12) { cli_dbgmsg("asn1_get_time: invalid month %u\n", n); return 1; } t.tm_mon = n - 1; ptr+=2; n = asn1_getnum(ptr); if(n<1 || n>31) { cli_dbgmsg("asn1_get_time: invalid day %u\n", n); return 1; } t.tm_mday = n; ptr+=2; n = asn1_getnum(ptr); if(n<0 || n>23) { cli_dbgmsg("asn1_get_time: invalid hour %u\n", n); return 1; } t.tm_hour = n; ptr+=2; n = asn1_getnum(ptr); if(n<0 || n>59) { cli_dbgmsg("asn1_get_time: invalid minute %u\n", n); return 1; } t.tm_min = n; ptr+=2; n = asn1_getnum(ptr); if(n<0 || n>59) { cli_dbgmsg("asn1_get_time: invalid second %u\n", n); return 1; } t.tm_sec = n; ptr+=2; if(*ptr != 'Z') { cli_dbgmsg("asn1_get_time: expected UTC time 'Z', got '%c'\n", *ptr); return 1; } *tm = mktime(&t); *asn1data = obj.next; return 0; }
static int asn1_get_rsa_pubkey(fmap_t *map, const void **asn1data, unsigned int *size, cli_crt *x509) { struct cli_asn1 obj; unsigned int avail, avail2; if(asn1_expect_objtype(map, *asn1data, size, &obj, 0x30)) /* subjectPublicKeyInfo */ return 1; *asn1data = obj.next; avail = obj.size; if(asn1_expect_algo(map, &obj.content, &avail, lenof(OID_rsaEncryption), OID_rsaEncryption)) /* rsaEncryption */ return 1; if(asn1_expect_objtype(map, obj.content, &avail, &obj, 0x03)) /* BIT STRING - subjectPublicKey */ return 1; if(avail) { cli_dbgmsg("asn1_get_rsa_pubkey: found unexpected extra data in subjectPublicKeyInfo\n"); return 1; } /* if(obj.size != 141 && obj.size != 271) /\* encoded len of 1024 and 2048 bit public keys *\/ */ /* return 1; */ if(!fmap_need_ptr_once(map, obj.content, 1)) { cli_dbgmsg("asn1_get_rsa_pubkey: cannot read public key content\n"); return 1; } if(((uint8_t *)obj.content)[0] != 0) { /* no byte fragments */ cli_dbgmsg("asn1_get_rsa_pubkey: unexpected byte frags in public key\n"); return 1; } avail = obj.size - 1; obj.content = ((uint8_t *)obj.content) + 1; if(asn1_expect_objtype(map, obj.content, &avail, &obj, 0x30)) /* SEQUENCE */ return 1; if(avail) { cli_dbgmsg("asn1_get_rsa_pubkey: found unexpected extra data in public key content\n"); return 1; } avail = obj.size; if(asn1_expect_objtype(map, obj.content, &avail, &obj, 0x02)) /* INTEGER - mod */ return 1; if(obj.size < 1024/8 || obj.size > 4096/8+1) { cli_dbgmsg("asn1_get_rsa_pubkey: modulus has got an unsupported length (%u)\n", obj.size * 8); return 1; } avail2 = obj.size; if(!fmap_need_ptr_once(map, obj.content, avail2)) { cli_dbgmsg("asn1_get_rsa_pubkey: cannot read n\n"); return 1; } if(mp_read_unsigned_bin(&x509->n, obj.content, avail2)) { cli_dbgmsg("asn1_get_rsa_pubkey: cannot convert n to big number\n"); return 1; } if(asn1_expect_objtype(map, obj.next, &avail, &obj, 0x02)) /* INTEGER - exp */ return 1; if(avail) { cli_dbgmsg("asn1_get_rsa_pubkey: found unexpected extra data after exp\n"); return 1; } if(obj.size < 1 || obj.size > avail2) { cli_dbgmsg("asn1_get_rsa_pubkey: exponent has got an unsupported length (%u)\n", obj.size * 8); return 1; } if(!fmap_need_ptr_once(map, obj.content, obj.size)) { cli_dbgmsg("asn1_get_rsa_pubkey: cannot read e\n"); return 1; } if(mp_read_unsigned_bin(&x509->e, obj.content, obj.size)) { cli_dbgmsg("asn1_get_rsa_pubkey: cannot convert e to big number\n"); return 1; } return 0; }
int asn1_load_mscat(fmap_t *map, struct cl_engine *engine) { struct cli_asn1 c; unsigned int size; struct cli_matcher *db; int i; if(asn1_parse_mscat(map, 0, map->len, &engine->cmgr, 0, &c.next, &size, engine)) return 1; if(asn1_expect_objtype(map, c.next, &size, &c, 0x30)) return 1; if(asn1_expect_obj(map, &c.content, &c.size, 0x06, lenof(OID_szOID_CATALOG_LIST), OID_szOID_CATALOG_LIST)) return 1; if(c.size) { cli_dbgmsg("asn1_load_mscat: found extra data in szOID_CATALOG_LIST content\n"); return 1; } if(asn1_expect_objtype(map, c.next, &size, &c, 0x4)) /* List ID */ return 1; if(asn1_expect_objtype(map, c.next, &size, &c, 0x17)) /* Effective date - WTF?! */ return 1; if(asn1_expect_algo(map, &c.next, &size, lenof(OID_szOID_CATALOG_LIST_MEMBER), OID_szOID_CATALOG_LIST_MEMBER)) /* szOID_CATALOG_LIST_MEMBER */ return 1; if(asn1_expect_objtype(map, c.next, &size, &c, 0x30)) /* hashes here */ return 1; /* [0] is next but we don't care as it's really descriptives stuff */ size = c.size; c.next = c.content; while(size) { struct cli_asn1 tag; if(asn1_expect_objtype(map, c.next, &size, &c, 0x30)) return 1; if(asn1_expect_objtype(map, c.content, &c.size, &tag, 0x04)) /* TAG NAME */ return 1; if(asn1_expect_objtype(map, tag.next, &c.size, &tag, 0x31)) /* set */ return 1; if(c.size) { cli_dbgmsg("asn1_load_mscat: found extra data in tag\n"); return 1; } while(tag.size) { struct cli_asn1 tagval1, tagval2, tagval3; int hashtype; if(asn1_expect_objtype(map, tag.content, &tag.size, &tagval1, 0x30)) return 1; tag.content = tagval1.next; if(asn1_expect_objtype(map, tagval1.content, &tagval1.size, &tagval2, 0x06)) return 1; if(tagval2.size != lenof(OID_SPC_INDIRECT_DATA_OBJID)) continue; if(!fmap_need_ptr_once(map, tagval2.content, lenof(OID_SPC_INDIRECT_DATA_OBJID))) { cli_dbgmsg("asn1_load_mscat: cannot read SPC_INDIRECT_DATA\n"); return 1; } if(memcmp(tagval2.content, OID_SPC_INDIRECT_DATA_OBJID, lenof(OID_SPC_INDIRECT_DATA_OBJID))) continue; /* stuff like CAT_NAMEVALUE_OBJID(1.3.6.1.4.1.311.12.2.1) and CAT_MEMBERINFO_OBJID(.2).. */ if(asn1_expect_objtype(map, tagval2.next, &tagval1.size, &tagval2, 0x31)) return 1; if(tagval1.size) { cli_dbgmsg("asn1_load_mscat: found extra data in tag value\n"); return 1; } if(asn1_expect_objtype(map, tagval2.content, &tagval2.size, &tagval1, 0x30)) return 1; if(tagval2.size) { cli_dbgmsg("asn1_load_mscat: found extra data in SPC_INDIRECT_DATA_OBJID tag\n"); return 1; } if(asn1_expect_objtype(map, tagval1.content, &tagval1.size, &tagval2, 0x30)) return 1; if(asn1_expect_objtype(map, tagval2.content, &tagval2.size, &tagval3, 0x06)) /* shall have an obj 1.3.6.1.4.1.311.2.1.15 or 1.3.6.1.4.1.311.2.1.25 inside */ return 1; if(tagval3.size != lenof(OID_SPC_PE_IMAGE_DATA_OBJID)) { /* lenof(OID_SPC_PE_IMAGE_DATA_OBJID) = lenof(OID_SPC_CAB_DATA_OBJID) = 10*/ cli_dbgmsg("asn1_load_mscat: bad hash type size\n"); return 1; } if(!fmap_need_ptr_once(map, tagval3.content, lenof(OID_SPC_PE_IMAGE_DATA_OBJID))) { cli_dbgmsg("asn1_load_mscat: cannot read hash type\n"); return 1; } if(!memcmp(tagval3.content, OID_SPC_PE_IMAGE_DATA_OBJID, lenof(OID_SPC_PE_IMAGE_DATA_OBJID))) hashtype = 2; else if(!memcmp(tagval3.content, OID_SPC_CAB_DATA_OBJID, lenof(OID_SPC_CAB_DATA_OBJID))) hashtype = 1; else { cli_dbgmsg("asn1_load_mscat: unexpected hash type\n"); return 1; } if(asn1_expect_objtype(map, tagval2.next, &tagval1.size, &tagval2, 0x30)) return 1; if(tagval1.size) { cli_dbgmsg("asn1_load_mscat: found extra data after hash\n"); return 1; } if(asn1_expect_algo(map, &tagval2.content, &tagval2.size, lenof(OID_sha1), OID_sha1)) /* objid 1.3.14.3.2.26 - sha1 */ return 1; if(asn1_expect_objtype(map, tagval2.content, &tagval2.size, &tagval3, 0x04)) return 1; if(tagval2.size) { cli_dbgmsg("asn1_load_mscat: found extra data in hash\n"); return 1; } if(tagval3.size != SHA1_HASH_SIZE) { cli_dbgmsg("asn1_load_mscat: bad hash size %u\n", tagval3.size); return 1; } if(!fmap_need_ptr_once(map, tagval3.content, SHA1_HASH_SIZE)) { cli_dbgmsg("asn1_load_mscat: cannot read hash\n"); return 1; } if(cli_debug_flag) { char sha1[SHA1_HASH_SIZE*2+1]; for(i=0;i<SHA1_HASH_SIZE;i++) sprintf(&sha1[i*2], "%02x", ((uint8_t *)(tagval3.content))[i]); cli_dbgmsg("asn1_load_mscat: got hash %s (%s)\n", sha1, (hashtype == 2) ? "PE" : "CAB"); } if(!engine->hm_fp) { if(!(engine->hm_fp = mpool_calloc(engine->mempool, 1, sizeof(*db)))) { tag.size = 1;; return 1; } #ifdef USE_MPOOL engine->hm_fp->mempool = engine->mempool; #endif } if(hm_addhash_bin(engine->hm_fp, tagval3.content, CLI_HASH_SHA1, hashtype, NULL)) { cli_warnmsg("asn1_load_mscat: failed to add hash\n"); return 1; } } } return 0; }
int cli_scancpio_old(int fd, cli_ctx *ctx) { struct cpio_hdr_old hdr_old; char name[513]; unsigned int file = 0, trailer = 0; uint32_t filesize, namesize, hdr_namesize; int ret, conv; off_t pos; while(read(fd, &hdr_old, sizeof(hdr_old)) == sizeof(hdr_old)) { if(!hdr_old.magic && trailer) return CL_SUCCESS; if(hdr_old.magic == 070707) { conv = 0; } else if(hdr_old.magic == 0143561) { conv = 1; } else { cli_dbgmsg("cli_scancpio_old: Invalid magic number\n"); return CL_EFORMAT; } cli_dbgmsg("CPIO: -- File %u --\n", ++file); if(hdr_old.namesize) { hdr_namesize = EC16(hdr_old.namesize, conv); namesize = MIN(sizeof(name), hdr_namesize); if(read(fd, name, namesize) != namesize) { cli_dbgmsg("cli_scancpio_old: Can't read file name\n"); return CL_EFORMAT; } name[namesize - 1] = 0; sanitname(name); cli_dbgmsg("CPIO: Name: %s\n", name); if(!strcmp(name, "TRAILER!!!")) trailer = 1; if(namesize < hdr_namesize) { if(hdr_namesize % 2) hdr_namesize++; lseek(fd, hdr_namesize - namesize, SEEK_CUR); } else if(hdr_namesize % 2) lseek(fd, 1, SEEK_CUR); } filesize = (uint32_t) (EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv)); cli_dbgmsg("CPIO: Filesize: %u\n", filesize); if(!filesize) continue; if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) return CL_VIRUS; pos = lseek(fd, 0, SEEK_CUR); if((EC16(hdr_old.mode, conv) & 0170000) != 0100000) { cli_dbgmsg("CPIO: Not a regular file, skipping\n"); } else { ret = cli_checklimits("cli_scancpio_old", ctx, filesize, 0, 0); if(ret == CL_EMAXFILES) { return ret; } else if(ret == CL_SUCCESS) { ret = cli_dumpscan(fd, 0, filesize, ctx); if(ret == CL_VIRUS) return ret; } } if(filesize % 2) filesize++; lseek(fd, pos + filesize, SEEK_SET); } return CL_CLEAN; }
int cli_scancpio_newc(int fd, cli_ctx *ctx, int crc) { struct cpio_hdr_newc hdr_newc; char name[513], buff[9]; unsigned int file = 0, trailer = 0; uint32_t filesize, namesize, hdr_namesize, pad; int ret; off_t pos; while(read(fd, &hdr_newc, sizeof(hdr_newc)) == sizeof(hdr_newc)) { if(!hdr_newc.magic[0] && trailer) return CL_SUCCESS; if((!crc && strncmp(hdr_newc.magic, "070701", 6)) || (crc && strncmp(hdr_newc.magic, "070702", 6))) { cli_dbgmsg("cli_scancpio_newc: Invalid magic string\n"); return CL_EFORMAT; } cli_dbgmsg("CPIO: -- File %u --\n", ++file); strncpy(buff, hdr_newc.namesize, 8); buff[8] = 0; if(sscanf(buff, "%x", &hdr_namesize) != 1) { cli_dbgmsg("cli_scancpio_newc: Can't convert name size\n"); return CL_EFORMAT; } if(hdr_namesize) { namesize = MIN(sizeof(name), hdr_namesize); if(read(fd, name, namesize) != namesize) { cli_dbgmsg("cli_scancpio_newc: Can't read file name\n"); return CL_EFORMAT; } name[namesize - 1] = 0; sanitname(name); cli_dbgmsg("CPIO: Name: %s\n", name); if(!strcmp(name, "TRAILER!!!")) trailer = 1; pad = (4 - (sizeof(hdr_newc) + hdr_namesize) % 4) % 4; if(namesize < hdr_namesize) { if(pad) hdr_namesize += pad; lseek(fd, hdr_namesize - namesize, SEEK_CUR); } else if(pad) lseek(fd, pad, SEEK_CUR); } strncpy(buff, hdr_newc.filesize, 8); buff[8] = 0; if(sscanf(buff, "%x", &filesize) != 1) { cli_dbgmsg("cli_scancpio_newc: Can't convert file size\n"); return CL_EFORMAT; } cli_dbgmsg("CPIO: Filesize: %u\n", filesize); if(!filesize) continue; if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) return CL_VIRUS; pos = lseek(fd, 0, SEEK_CUR); ret = cli_checklimits("cli_scancpio_newc", ctx, filesize, 0, 0); if(ret == CL_EMAXFILES) { return ret; } else if(ret == CL_SUCCESS) { ret = cli_dumpscan(fd, 0, filesize, ctx); if(ret == CL_VIRUS) return ret; } if((pad = filesize % 4)) filesize += (4 - pad); lseek(fd, pos + filesize, SEEK_SET); } return CL_CLEAN; }
/* Return converted endian-fixed header, or error code */ static int cli_elf_fileheader(cli_ctx *ctx, fmap_t *map, union elf_file_hdr *file_hdr, uint8_t *do_convert, uint8_t *is64) { uint8_t format64, conv; /* Load enough for smaller header first */ if(fmap_readn(map, file_hdr, 0, sizeof(struct elf_file_hdr32)) != sizeof(struct elf_file_hdr32)) { /* Not an ELF file? */ cli_dbgmsg("ELF: Can't read file header\n"); return CL_BREAK; } if(memcmp(file_hdr->hdr64.e_ident, "\x7f\x45\x4c\x46", 4)) { cli_dbgmsg("ELF: Not an ELF file\n"); return CL_BREAK; } switch(file_hdr->hdr64.e_ident[4]) { case 1: cli_dbgmsg("ELF: ELF class 1 (32-bit)\n"); format64 = 0; break; case 2: cli_dbgmsg("ELF: ELF class 2 (64-bit)\n"); format64 = 1; break; default: cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr->hdr64.e_ident[4]); if (ctx) cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } /* Need to know to endian convert */ if(file_hdr->hdr64.e_ident[5] == 1) { #if WORDS_BIGENDIAN == 0 if(ctx) cli_dbgmsg("ELF: File is little-endian - conversion not required\n"); conv = 0; #else if(ctx) cli_dbgmsg("ELF: File is little-endian - data conversion enabled\n"); conv = 1; #endif } else { #if WORDS_BIGENDIAN == 0 if(ctx) cli_dbgmsg("ELF: File is big-endian - data conversion enabled\n"); conv = 1; #else if(ctx) cli_dbgmsg("ELF: File is big-endian - conversion not required\n"); conv = 0; #endif } *do_convert = conv; *is64 = format64; /* Solve bit-size and conversion pronto */ file_hdr->hdr64.e_type = EC16(file_hdr->hdr64.e_type, conv); file_hdr->hdr64.e_machine = EC16(file_hdr->hdr64.e_machine, conv); file_hdr->hdr64.e_version = EC32(file_hdr->hdr64.e_version, conv); if(format64) { /* Read rest of 64-bit header */ if(fmap_readn(map, file_hdr->hdr32.pad, sizeof(struct elf_file_hdr32), ELF_HDR_SIZEDIFF) != ELF_HDR_SIZEDIFF) { /* Not an ELF file? */ cli_dbgmsg("ELF: Can't read file header\n"); return CL_BREAK; } /* Now endian convert, if needed */ if(conv) { file_hdr->hdr64.e_entry = EC64(file_hdr->hdr64.e_entry, conv); file_hdr->hdr64.e_phoff = EC64(file_hdr->hdr64.e_phoff, conv); file_hdr->hdr64.e_shoff = EC64(file_hdr->hdr64.e_shoff, conv); file_hdr->hdr64.e_flags = EC32(file_hdr->hdr64.e_flags, conv); file_hdr->hdr64.e_ehsize = EC16(file_hdr->hdr64.e_ehsize, conv); file_hdr->hdr64.e_phentsize = EC16(file_hdr->hdr64.e_phentsize, conv); file_hdr->hdr64.e_phnum = EC16(file_hdr->hdr64.e_phnum, conv); file_hdr->hdr64.e_shentsize = EC16(file_hdr->hdr64.e_shentsize, conv); file_hdr->hdr64.e_shnum = EC16(file_hdr->hdr64.e_shnum, conv); file_hdr->hdr64.e_shstrndx = EC16(file_hdr->hdr64.e_shstrndx, conv); } } else { /* Convert 32-bit structure, if needed */ if(conv) { file_hdr->hdr32.hdr.e_entry = EC32(file_hdr->hdr32.hdr.e_entry, conv); file_hdr->hdr32.hdr.e_phoff = EC32(file_hdr->hdr32.hdr.e_phoff, conv); file_hdr->hdr32.hdr.e_shoff = EC32(file_hdr->hdr32.hdr.e_shoff, conv); file_hdr->hdr32.hdr.e_flags = EC32(file_hdr->hdr32.hdr.e_flags, conv); file_hdr->hdr32.hdr.e_ehsize = EC16(file_hdr->hdr32.hdr.e_ehsize, conv); file_hdr->hdr32.hdr.e_phentsize = EC16(file_hdr->hdr32.hdr.e_phentsize, conv); file_hdr->hdr32.hdr.e_phnum = EC16(file_hdr->hdr32.hdr.e_phnum, conv); file_hdr->hdr32.hdr.e_shentsize = EC16(file_hdr->hdr32.hdr.e_shentsize, conv); file_hdr->hdr32.hdr.e_shnum = EC16(file_hdr->hdr32.hdr.e_shnum, conv); file_hdr->hdr32.hdr.e_shstrndx = EC16(file_hdr->hdr32.hdr.e_shstrndx, conv); } /* Wipe pad for safety */ memset(file_hdr->hdr32.pad, 0, ELF_HDR_SIZEDIFF); } return CL_CLEAN; }
static int yylex(YYSTYPE *lvalp, yyscan_t scanner) { const size_t len = scanner->insize; const unsigned char *in = (const unsigned char*)scanner->in; unsigned char lookahead; enum char_class cClass; scanner->yytext = NULL; scanner->yylen = 0; if(scanner->pos == scanner->lastpos) { if(scanner->last_state == scanner->state) { cli_dbgmsg(MODULE "infloop detected, skipping character\n"); scanner->pos++; } /* its not necesarely an infloop if it changed * state, and it shouldn't infloop between states */ } scanner->lastpos = scanner->pos; scanner->last_state = scanner->state; while(scanner->pos < scanner->insize) { switch(scanner->state) { case Initial: textbuf_clean(&scanner->buf); cClass = ctype[in[scanner->pos++]]; switch(cClass) { case Whitespace: /* eat whitespace */ continue; case Slash: if(scanner->pos < len) { lookahead = in[scanner->pos]; switch(lookahead) { case '*': scanner->state = MultilineComment; scanner->pos++; continue; case '/': scanner->state = SinglelineComment; scanner->pos++; continue; } } --scanner->pos; return parseOperator(lvalp, scanner); case Operator: --scanner->pos; return parseOperator(lvalp, scanner); case DQuote: return parseDQString(lvalp, scanner); case SQuote: return parseSQString(lvalp, scanner); case Digit: --scanner->pos; return parseNumber(lvalp, scanner); case IdStart: --scanner->pos; return parseId(lvalp,scanner); CASE_SPECIAL_CHAR(BracketOpen, "["); CASE_SPECIAL_CHAR(BracketClose, "]"); CASE_SPECIAL_CHAR(Comma, ","); CASE_SPECIAL_CHAR(CurlyOpen, "{"); CASE_SPECIAL_CHAR(CurlyClose, "}"); CASE_SPECIAL_CHAR(ParOpen, "("); CASE_SPECIAL_CHAR(ParClose, ")"); CASE_SPECIAL_CHAR(Dot, "."); CASE_SPECIAL_CHAR(SemiColon, ";"); case Nop: continue; } break; case DoubleQString: return parseString(lvalp, scanner, '"', DoubleQString); case SingleQString: return parseString(lvalp, scanner, '\'', SingleQString); case Identifier: return parseId(lvalp, scanner); case MultilineComment: while(scanner->pos+1 < scanner->insize) { if(in[scanner->pos] == '*' && in[scanner->pos+1] == '/') { scanner->state = Initial; scanner->pos++; break; } scanner->pos++; } scanner->pos++; break; case Number: return parseNumber(lvalp, scanner); case SinglelineComment: while(scanner->pos < scanner->insize) { /* htmlnorm converts \n to space, so * stop on space too */ if(in[scanner->pos] == '\n' || in[scanner->pos] == ' ') break; scanner->pos++; } scanner->state = Initial; break; default: assert(0 && "Not reached"); } } return 0; }
int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char *trigger, const char *pattern, const char *cflags, const char *offset, const uint32_t *lsigid, unsigned int options) { struct cli_pcre_meta **newmetatable = NULL, *pm = NULL; uint32_t pcre_count; const char *opt; int ret = CL_SUCCESS, rssigs; if (!root || !trigger || !pattern || !offset) { cli_errmsg("cli_pcre_addpatt: NULL root or NULL trigger or NULL pattern or NULL offset\n"); return CL_ENULLARG; } /* TODO: trigger and regex checking (backreference limitations?) (control pattern limitations?) */ /* cli_ac_chklsig will fail a empty trigger; empty patterns can cause an infinite loop */ if (*trigger == '\0' || *pattern == '\0') { cli_errmsg("cli_pcre_addpatt: trigger or pattern cannot be an empty string\n"); return CL_EMALFDB; } if (cflags && *cflags == '\0') { cflags = NULL; } if (lsigid) pm_dbgmsg("cli_pcre_addpatt: Adding /%s/%s%s triggered on (%s) as subsig %d for lsigid %d\n", pattern, cflags ? " with flags " : "", cflags ? cflags : "", trigger, lsigid[1], lsigid[0]); else pm_dbgmsg("cli_pcre_addpatt: Adding /%s/%s%s triggered on (%s) [no lsigid]\n", pattern, cflags ? " with flags " : "", cflags ? cflags : "", trigger); #ifdef PCRE_BYPASS /* check for trigger bypass */ if (strcmp(trigger, PCRE_BYPASS)) { #endif /* validate the lsig trigger */ rssigs = cli_ac_chklsig(trigger, trigger + strlen(trigger), NULL, NULL, NULL, 1); if(rssigs == -1) { cli_errmsg("cli_pcre_addpatt: regex subsig /%s/ is missing a valid logical trigger\n", pattern); return CL_EMALFDB; } if (lsigid) { if (rssigs > lsigid[1]) { cli_errmsg("cli_pcre_addpatt: regex subsig %d logical trigger refers to subsequent subsig %d\n", lsigid[1], rssigs); return CL_EMALFDB; } if (rssigs == lsigid[1]) { cli_errmsg("cli_pcre_addpatt: regex subsig %d logical trigger is self-referential\n", lsigid[1]); return CL_EMALFDB; } } else { cli_dbgmsg("cli_pcre_addpatt: regex subsig is missing lsigid data\n"); } #ifdef PCRE_BYPASS } #endif /* allocating entries */ pm = (struct cli_pcre_meta *)mpool_calloc(root->mempool, 1, sizeof(*pm)); if (!pm) { cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for new pcre meta\n"); return CL_EMEM; } pm->trigger = cli_mpool_strdup(root->mempool, trigger); if (!pm->trigger) { cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for trigger string\n"); cli_pcre_freemeta(root, pm); mpool_free(root->mempool, pm); return CL_EMEM; } pm->virname = (char *)cli_mpool_virname(root->mempool, virname, options & CL_DB_OFFICIAL); if(!pm->virname) { cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for virname or NULL virname\n"); cli_pcre_freemeta(root, pm); mpool_free(root->mempool, pm); return CL_EMEM; } if (lsigid) { root->ac_lsigtable[lsigid[0]]->virname = pm->virname; pm->lsigid[0] = 1; pm->lsigid[1] = lsigid[0]; pm->lsigid[2] = lsigid[1]; } else { /* sigtool */ pm->lsigid[0] = 0; } pm->pdata.expression = strdup(pattern); if (!pm->pdata.expression) { cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for expression\n"); cli_pcre_freemeta(root, pm); mpool_free(root->mempool, pm); return CL_EMEM; } /* offset parsing and usage, similar to cli_ac_addsig */ /* relative and type-specific offsets handled during scan */ ret = cli_caloff(offset, NULL, root->type, pm->offdata, &(pm->offset_min), &(pm->offset_max)); if (ret != CL_SUCCESS) { cli_errmsg("cli_pcre_addpatt: cannot calculate offset data: %s for pattern: %s\n", offset, pattern); cli_pcre_freemeta(root, pm); mpool_free(root->mempool, pm); return ret; } if(pm->offdata[0] != CLI_OFF_ANY) { if(pm->offdata[0] == CLI_OFF_ABSOLUTE) root->pcre_absoff_num++; else root->pcre_reloff_num++; } /* parse and add options, also totally not from snort */ if (cflags) { opt = cflags; /* cli_pcre_addoptions handles pcre specific options */ while (cli_pcre_addoptions(&(pm->pdata), &opt, 0) != CL_SUCCESS) { /* handle matcher specific options here */ switch (*opt) { case 'g': pm->flags |= CLI_PCRE_GLOBAL; break; case 'r': pm->flags |= CLI_PCRE_ROLLING; break; case 'e': pm->flags |= CLI_PCRE_ENCOMPASS; break; default: cli_errmsg("cli_pcre_addpatt: unknown/extra pcre option encountered %c\n", *opt); cli_pcre_freemeta(root, pm); mpool_free(root->mempool, pm); return CL_EMALFDB; } opt++; } if (pm->flags) { pm_dbgmsg("Matcher: %s%s%s\n", pm->flags & CLI_PCRE_GLOBAL ? "CLAMAV_GLOBAL " : "", pm->flags & CLI_PCRE_ROLLING ? "CLAMAV_ROLLING " : "", pm->flags & CLI_PCRE_ENCOMPASS ? "CLAMAV_ENCOMPASS " : ""); } else pm_dbgmsg("Matcher: NONE\n"); if (pm->pdata.options) { #if USING_PCRE2 pm_dbgmsg("Compiler: %s%s%s%s%s%s%s\n", pm->pdata.options & PCRE2_CASELESS ? "PCRE2_CASELESS " : "", pm->pdata.options & PCRE2_DOTALL ? "PCRE2_DOTALL " : "", pm->pdata.options & PCRE2_MULTILINE ? "PCRE2_MULTILINE " : "", pm->pdata.options & PCRE2_EXTENDED ? "PCRE2_EXTENDED " : "", pm->pdata.options & PCRE2_ANCHORED ? "PCRE2_ANCHORED " : "", pm->pdata.options & PCRE2_DOLLAR_ENDONLY ? "PCRE2_DOLLAR_ENDONLY " : "", pm->pdata.options & PCRE2_UNGREEDY ? "PCRE2_UNGREEDY " : ""); #else pm_dbgmsg("Compiler: %s%s%s%s%s%s%s\n", pm->pdata.options & PCRE_CASELESS ? "PCRE_CASELESS " : "", pm->pdata.options & PCRE_DOTALL ? "PCRE_DOTALL " : "", pm->pdata.options & PCRE_MULTILINE ? "PCRE_MULTILINE " : "", pm->pdata.options & PCRE_EXTENDED ? "PCRE_EXTENDED " : "", pm->pdata.options & PCRE_ANCHORED ? "PCRE_ANCHORED " : "", pm->pdata.options & PCRE_DOLLAR_ENDONLY ? "PCRE_DOLLAR_ENDONLY " : "", pm->pdata.options & PCRE_UNGREEDY ? "PCRE_UNGREEDY " : ""); #endif } else pm_dbgmsg("Compiler: NONE\n"); } /* add metadata to the performance tracker */ if (options & CL_DB_PCRE_STATS) pcre_perf_events_init(pm, virname); /* add pcre data to root after reallocation */ pcre_count = root->pcre_metas+1; newmetatable = (struct cli_pcre_meta **)mpool_realloc(root->mempool, root->pcre_metatable, pcre_count * sizeof(struct cli_pcre_meta *)); if (!newmetatable) { cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for new pcre meta table\n"); cli_pcre_freemeta(root, pm); mpool_free(root->mempool, pm); return CL_EMEM; } newmetatable[pcre_count-1] = pm; root->pcre_metatable = newmetatable; root->pcre_metas = pcre_count; return CL_SUCCESS; }
static void run_decoders(struct parser_state *state) { size_t i; const char* name; struct tokens *tokens = &state->tokens; for(i = 0; i < tokens->cnt; i++) { const char *cstring = TOKEN_GET(&tokens->data[i], cstring); struct decode_result res; res.pos_begin = res.pos_end = 0; res.append = 0; if(tokens->data[i].type == TOK_FUNCTION && i+13 < tokens->cnt) { name = NULL; ++i; if(tokens->data[i].type == TOK_IDENTIFIER_NAME) { cstring = TOKEN_GET(&tokens->data[i], cstring); name = cstring; ++i; } if(match_parameters(&tokens->data[i], de_packer_3, sizeof(de_packer_3)/sizeof(de_packer_3[0])) != -1 || match_parameters(&tokens->data[i], de_packer_2, sizeof(de_packer_2)/sizeof(de_packer_2[0])) != -1) { /* find function decl. end */ handle_de(tokens->data, i, tokens->cnt, name, &res); } } else if(i+2 < tokens->cnt && tokens->data[i].type == TOK_IDENTIFIER_NAME && cstring && !strcmp("dF", cstring) && tokens->data[i+1].type == TOK_PAR_OPEN) { /* TODO: also match signature of dF function (possibly * declared using unescape */ handle_df(tokens->data, i+2, &res); } else if(i+2 < tokens->cnt && tokens->data[i].type == TOK_IDENTIFIER_NAME && cstring && !strcmp("eval", cstring) && tokens->data[i+1].type == TOK_PAR_OPEN) { handle_eval(tokens, i+2, &res); } if(res.pos_end > res.pos_begin) { struct tokens parent_tokens; if(res.pos_end < tokens->cnt && tokens->data[res.pos_end].type == TOK_SEMICOLON) res.pos_end++; parent_tokens = state->tokens;/* save current tokens */ /* initialize embedded context */ memset(&state->tokens, 0, sizeof(state->tokens)); if(++state->rec > 16) cli_dbgmsg(MODULE "recursion limit reached\n"); else { cli_js_process_buffer(state, res.txtbuf.data, res.txtbuf.pos); --state->rec; } free(res.txtbuf.data); /* state->tokens still refers to the embedded/nested context * here */ if(!res.append) { replace_token_range(&parent_tokens, res.pos_begin, res.pos_end, &state->tokens); } else { /* delete tokens */ replace_token_range(&parent_tokens, res.pos_begin, res.pos_end, NULL); append_tokens(&parent_tokens, &state->tokens); } /* end of embedded context, restore tokens state */ free(state->tokens.data); state->tokens = parent_tokens; } state_update_scope(state, &state->tokens.data[i]); } }
int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, const struct cli_pcre_off *data, cli_ctx *ctx) { struct cli_pcre_meta **metatable = root->pcre_metatable, *pm = NULL; struct cli_pcre_data *pd; struct cli_pcre_results p_res; struct cli_ac_result *newres; uint32_t adjbuffer, adjshift, adjlength; unsigned int i, evalcnt = 0; uint64_t maxfilesize, evalids = 0; uint32_t global, encompass, rolling; int rc, offset, ret = CL_SUCCESS, options=0; uint8_t viruses_found = 0; if ((root->pcre_metas == 0) || (!root->pcre_metatable) || (ctx && ctx->dconf && !(ctx->dconf->pcre & PCRE_CONF_SUPPORT))) return CL_SUCCESS; memset(&p_res, 0, sizeof(p_res)); for (i = 0; i < root->pcre_metas; ++i) { pm = root->pcre_metatable[i]; pd = &(pm->pdata); /* skip checking and running disabled pcres */ if (pm->flags & CLI_PCRE_DISABLED) { cli_dbgmsg("cli_pcre_scanbuf: skipping disabled regex /%s/\n", pd->expression); continue; } /* skip checking and running CLI_OFF_NONE pcres */ if (data && data->offset[i] == CLI_OFF_NONE) { pm_dbgmsg("cli_pcre_scanbuf: skipping CLI_OFF_NONE regex /%s/\n", pd->expression); continue; } /* evaluate trigger */ if (pm->lsigid[0]) { cli_dbgmsg("cli_pcre_scanbuf: checking %s; running regex /%s/\n", pm->trigger, pd->expression); #ifdef PCRE_BYPASS if (strcmp(pm->trigger, PCRE_BYPASS)) #endif if (cli_ac_chklsig(pm->trigger, pm->trigger + strlen(pm->trigger), mdata->lsigcnt[pm->lsigid[1]], &evalcnt, &evalids, 0) != 1) continue; } else { cli_dbgmsg("cli_pcre_scanbuf: skipping %s check due to uninitialized lsigid\n", pm->trigger); /* fall-through to unconditional execution - sigtool-only */ } global = (pm->flags & CLI_PCRE_GLOBAL); /* globally search for all matches (within bounds) */ encompass = (pm->flags & CLI_PCRE_ENCOMPASS); /* encompass search to offset->offset+maxshift */ rolling = (pm->flags & CLI_PCRE_ROLLING); /* rolling search (unanchored) */ offset = pd->search_offset; /* this is usually 0 */ cli_dbgmsg("cli_pcre_scanbuf: triggered %s; running regex /%s/%s%s\n", pm->trigger, pd->expression, global ? " (global)":"", rolling ? " (rolling)":""); /* adjust the buffer sent to cli_pcre_match for offset and maxshift */ if (!data) { if (cli_pcre_qoff(pm, length, &adjbuffer, &adjshift) != CL_SUCCESS) continue; } else { adjbuffer = data->offset[i]; adjshift = data->shift[i]; } /* check for need to anchoring */ if (!rolling && !adjshift && (adjbuffer != CLI_OFF_ANY)) #if USING_PCRE2 options |= PCRE2_ANCHORED; #else options |= PCRE_ANCHORED; #endif else options = 0; if (adjbuffer == CLI_OFF_ANY) adjbuffer = 0; /* check the offset bounds */ if (adjbuffer < length) { /* handle encompass flag */ if (encompass && adjshift != 0 && adjshift != CLI_OFF_NONE) { if (adjbuffer+adjshift > length) adjlength = length - adjbuffer; else adjlength = adjshift; } else { /* NOTE - if using non-encompass method 2, alter shift universally */ /* TODO - limitations on non-encompassed buffers? */ adjlength = length - adjbuffer; } } else { /* starting offset is outside bounds of file, skip pcre execution silently */ pm_dbgmsg("cli_pcre_scanbuf: starting offset is outside bounds of file %u >= %u\n", adjbuffer, length); continue; } pm_dbgmsg("cli_pcre_scanbuf: passed buffer adjusted to %u +%u(%u)[%u]%s\n", adjbuffer, adjlength, adjbuffer+adjlength, adjshift, encompass ? " (encompass)":""); /* if the global flag is set, loop through the scanning */ do { /* reset the match results */ if ((ret = cli_pcre_results_reset(&p_res, pd)) != CL_SUCCESS) break; /* performance metrics */ cli_event_time_start(p_sigevents, pm->sigtime_id); rc = cli_pcre_match(pd, buffer+adjbuffer, adjlength, offset, options, &p_res); cli_event_time_stop(p_sigevents, pm->sigtime_id); /* if debug, generate a match report */ if (cli_debug_flag) cli_pcre_report(pd, buffer+adjbuffer, adjlength, rc, &p_res); /* matched, rc shouldn't be >0 unless a full match occurs */ if (rc > 0) { cli_dbgmsg("cli_pcre_scanbuf: located regex match @ %d\n", adjbuffer+p_res.match[0]); /* check if we've gone over offset+shift */ if (!encompass && adjshift) { if (p_res.match[0] > adjshift) { /* ignore matched offset (outside of maxshift) */ cli_dbgmsg("cli_pcre_scanbuf: match found outside of maxshift @%u\n", adjbuffer+p_res.match[0]); break; } } /* track the detection count */ cli_event_count(p_sigevents, pm->sigmatch_id); /* for logical signature evaluation */ if (pm->lsigid[0]) { pm_dbgmsg("cli_pcre_scanbuf: assigning lsigcnt[%d][%d], located @ %d\n", pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0]); ret = lsig_sub_matched(root, mdata, pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0], 0); if (ret != CL_SUCCESS) break; } else { /* for raw match data - sigtool only */ if(res) { newres = (struct cli_ac_result *)cli_calloc(1, sizeof(struct cli_ac_result)); if(!newres) { cli_errmsg("cli_pcre_scanbuff: Can't allocate memory for new result\n"); ret = CL_EMEM; break; } newres->virname = pm->virname; newres->customdata = NULL; /* get value? */ newres->next = *res; newres->offset = adjbuffer+p_res.match[0]; *res = newres; } else { if (ctx && SCAN_ALL) { viruses_found = 1; cli_append_virus(ctx, (const char *)pm->virname); } if (virname) *virname = pm->virname; if (!ctx || !SCAN_ALL) { ret = CL_VIRUS; break; } } } } /* move off to the end of the match for next match; offset is relative to adjbuffer * NOTE: misses matches starting within the last match; TODO: start from start of last match? */ offset = p_res.match[1]; } while (global && rc > 0 && offset < adjlength); /* handle error code */ if (rc < 0 && p_res.err != CL_SUCCESS) ret = p_res.err; /* jumps out of main loop from 'global' loop */ if (ret != CL_SUCCESS) break; }
int cli_chm_open(const char *dirname, chm_metadata_t *metadata, cli_ctx *ctx) { STATBUF statbuf; int retval; cli_dbgmsg("in cli_chm_open\n"); if ((retval = chm_init_metadata(metadata)) != CL_SUCCESS) { return retval; } metadata->map = *ctx->fmap; if(metadata->map->len < CHM_ITSF_MIN_LEN) return CL_ESTAT; metadata->m_length = metadata->map->len; if (!itsf_read_header(metadata)) { goto abort; } itsf_print_header(&metadata->itsf_hdr); if (!itsp_read_header(metadata, metadata->itsf_hdr.dir_offset)) { goto abort; } itsp_print_header(&metadata->itsp_hdr); metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN; /* TODO: need to check this first calculation, currently have no files of this type */ if (metadata->itsp_hdr.index_head > 0) { metadata->chunk_offset += metadata->itsp_hdr.index_head * metadata->itsp_hdr.block_len; } metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1; /* Versions before 3 didn't have a data_offset */ /* TODO: need to check this calculation, currently have no files of this type */ if (metadata->itsf_hdr.version < 3) { metadata->itsf_hdr.data_offset = metadata->itsf_hdr.dir_offset + CHM_ITSP_LEN + (metadata->itsp_hdr.block_len*metadata->itsp_hdr.num_blocks); } while (metadata->num_chunks) { if (read_chunk(metadata) != CL_SUCCESS) { cli_dbgmsg("read_chunk failed\n"); goto abort; } if (read_control_entries(metadata) == FALSE) { goto abort; } metadata->num_chunks--; metadata->chunk_offset += metadata->itsp_hdr.block_len; } if (!metadata->sys_content.length || !metadata->sys_control.length || !metadata->sys_reset.length) { cli_dbgmsg("sys file missing\n"); goto abort; } metadata->ufd = chm_decompress_stream(metadata, dirname, ctx); if (metadata->ufd == -1) { goto abort; } metadata->chunk_entries = 0; metadata->chunk_data = NULL; metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN; metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1; return CL_SUCCESS; abort: return CL_EFORMAT; }
uint32_t cli_bcapi_debug_print_str(struct cli_bc_ctx *ctx, const uint8_t *str, uint32_t len) { cli_event_fastdata(EV, BCEV_DBG_STR, str, strlen((const char*)str)); cli_dbgmsg("bytecode debug: %s\n", str); return 0; }
static void itsp_print_header(chm_itsp_header_t *itsp_hdr) { if (!itsp_hdr) { return; } cli_dbgmsg("---- ITSP ----\n"); cli_dbgmsg("Signature:\t%c%c%c%c\n", itsp_hdr->signature[0], itsp_hdr->signature[1],itsp_hdr->signature[2],itsp_hdr->signature[3]); cli_dbgmsg("Version:\t%d\n", itsp_hdr->version); cli_dbgmsg("Block len:\t%u\n", itsp_hdr->block_len); cli_dbgmsg("Block idx int:\t%d\n", itsp_hdr->blockidx_intvl); cli_dbgmsg("Index depth:\t%d\n", itsp_hdr->index_depth); cli_dbgmsg("Index root:\t%d\n", itsp_hdr->index_root); cli_dbgmsg("Index head:\t%u\n", itsp_hdr->index_head); cli_dbgmsg("Index tail:\t%u\n", itsp_hdr->index_tail); cli_dbgmsg("Num Blocks:\t%u\n", itsp_hdr->num_blocks); cli_dbgmsg("Lang ID:\t%u\n\n", itsp_hdr->lang_id); }
static int vba_read_project_strings(int fd, int big_endian) { unsigned char *buf = NULL; uint16_t buflen = 0; int ret = 0; for(;;) { off_t offset; uint16_t length; char *name; if(!read_uint16(fd, &length, big_endian)) break; if (length < 6) { lseek(fd, -2, SEEK_CUR); break; } if(length > buflen) { unsigned char *newbuf = (unsigned char *)cli_realloc(buf, length); if(newbuf == NULL) { if(buf) free(buf); return 0; } buflen = length; buf = newbuf; } offset = lseek(fd, 0, SEEK_CUR); if(cli_readn(fd, buf, length) != (int)length) { cli_dbgmsg("read name failed - rewinding\n"); lseek(fd, offset, SEEK_SET); break; } name = get_unicode_name((const char *)buf, length, big_endian); cli_dbgmsg("length: %d, name: %s\n", length, (name) ? name : "[null]"); if((name == NULL) || (memcmp("*\\", name, 2) != 0) || (strchr("ghcd", name[2]) == NULL)) { /* Not a string */ lseek(fd, -(length+2), SEEK_CUR); if(name) free(name); break; } free(name); if(!read_uint16(fd, &length, big_endian)) { if(buf) free(buf); break; } ret++; if ((length != 0) && (length != 65535)) { lseek(fd, -2, SEEK_CUR); continue; } offset = lseek(fd, 10, SEEK_CUR); cli_dbgmsg("offset: %lu\n", (unsigned long)offset); vba56_test_middle(fd); } if(buf) free(buf); return ret; }
static int chm_decompress_stream(int fd, chm_metadata_t *metadata, const char *dirname, cli_ctx *ctx) { lzx_content_t lzx_content; lzx_reset_table_t lzx_reset_table; lzx_control_t lzx_control; int window_bits, length, tmpfd, retval=-1; struct lzx_stream * stream; char filename[1024]; struct cab_file file; snprintf(filename, 1024, "%s"PATHSEP"clamav-unchm.bin", dirname); tmpfd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); if (tmpfd<0) { cli_dbgmsg("open failed for %s\n", filename); return -1; } if (!metadata->sys_control.length || !metadata->sys_content.length ||!metadata->sys_reset.length) { cli_dbgmsg("Control file missing\n"); goto abort; } if (!read_sys_control(metadata, &lzx_control)) { goto abort; } if (!read_sys_content(metadata, &lzx_content)) { goto abort; } if (!read_sys_reset_table(metadata, &lzx_reset_table)) { goto abort; } switch (lzx_control.window_size) { case 0x008000: window_bits = 15; break; case 0x010000: window_bits = 16; break; case 0x020000: window_bits = 17; break; case 0x040000: window_bits = 18; break; case 0x080000: window_bits = 19; break; case 0x100000: window_bits = 20; break; case 0x200000: window_bits = 21; break; default: cli_dbgmsg("bad control window size: 0x%x\n", lzx_control.window_size); goto abort; } if (lzx_control.reset_interval % LZX_FRAME_SIZE) { cli_dbgmsg("bad reset_interval: 0x%x\n", lzx_control.window_size); goto abort; } length = lzx_reset_table.uncom_len; length += lzx_control.reset_interval; length &= -lzx_control.reset_interval; cli_dbgmsg("Compressed offset: %lu\n", (unsigned long int) lzx_content.offset); if ((uint64_t) lseek(fd, lzx_content.offset, SEEK_SET) != lzx_content.offset) { goto abort; } memset(&file, 0, sizeof(struct cab_file)); file.max_size = ctx->engine->maxfilesize; stream = lzx_init(fd, tmpfd, window_bits, lzx_control.reset_interval / LZX_FRAME_SIZE, 4096, length, &file, NULL); if (!stream) { cli_dbgmsg("lzx_init failed\n"); goto abort; } lzx_decompress(stream, length); lzx_free(stream); #ifndef _WIN32 /* Delete the file */ if(cli_unlink(filename)) retval = -1; else #endif retval = tmpfd; abort: if ((retval == -1) && (tmpfd >= 0)) { close(tmpfd); } return retval; }
vba_project_t * cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which) { unsigned char *buf; const unsigned char vba56_signature[] = { 0xcc, 0x61 }; uint16_t record_count, buflen, ffff, byte_count; uint32_t offset; int i, j, fd, big_endian = FALSE; vba_project_t *vba_project; struct vba56_header v56h; off_t seekback; char fullname[1024], *hash; cli_dbgmsg("in cli_vba_readdir()\n"); if(dir == NULL) return NULL; /* * _VBA_PROJECT files are embedded within office documents (OLE2) */ if (!uniq_get(U, "_vba_project", 12, &hash)) return NULL; snprintf(fullname, sizeof(fullname), "%s"PATHSEP"%s_%u", dir, hash, which); fullname[sizeof(fullname)-1] = '\0'; fd = open(fullname, O_RDONLY|O_BINARY); if(fd == -1) return NULL; if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) { close(fd); return NULL; } if (memcmp(v56h.magic, vba56_signature, sizeof(v56h.magic)) != 0) { close(fd); return NULL; } i = vba_read_project_strings(fd, TRUE); if ((seekback = lseek(fd, 0, SEEK_CUR)) == -1) { cli_dbgmsg("vba_readdir: lseek() failed. Unable to guess VBA type\n"); close(fd); return NULL; } if (lseek(fd, sizeof(struct vba56_header), SEEK_SET) == -1) { cli_dbgmsg("vba_readdir: lseek() failed. Unable to guess VBA type\n"); close(fd); return NULL; } j = vba_read_project_strings(fd, FALSE); if(!i && !j) { close(fd); cli_dbgmsg("vba_readdir: Unable to guess VBA type\n"); return NULL; } if (i > j) { big_endian = TRUE; if (lseek(fd, seekback, SEEK_SET) == -1) { cli_dbgmsg("vba_readdir: call to lseek() while guessing big-endian has failed\n"); close(fd); return NULL; } cli_dbgmsg("vba_readdir: Guessing big-endian\n"); } else { cli_dbgmsg("vba_readdir: Guessing little-endian\n"); } /* junk some more stuff */ do if (cli_readn(fd, &ffff, 2) != 2) { close(fd); return NULL; } while(ffff != 0xFFFF); /* check for alignment error */ if(!seekandread(fd, -3, SEEK_CUR, &ffff, sizeof(uint16_t))) { close(fd); return NULL; } if (ffff != 0xFFFF) { if (lseek(fd, 1, SEEK_CUR) == -1) { cli_dbgmsg("call to lseek() while checking alignment error has failed\n"); close(fd); return NULL; } } if(!read_uint16(fd, &ffff, big_endian)) { close(fd); return NULL; } if(ffff != 0xFFFF) { if (lseek(fd, ffff, SEEK_CUR) == -1) { cli_dbgmsg("call to lseek() while checking alignment error has failed\n"); close(fd); return NULL; } } if(!read_uint16(fd, &ffff, big_endian)) { close(fd); return NULL; } if(ffff == 0xFFFF) ffff = 0; if (lseek(fd, ffff + 100, SEEK_CUR) == -1) { cli_dbgmsg("call to lseek() failed\n"); close(fd); return NULL; } if(!read_uint16(fd, &record_count, big_endian)) { close(fd); return NULL; } cli_dbgmsg("vba_readdir: VBA Record count %d\n", record_count); if (record_count == 0) { /* No macros, assume clean */ close(fd); return NULL; } if (record_count > MAX_VBA_COUNT) { /* Almost certainly an error */ cli_dbgmsg("vba_readdir: VBA Record count too big\n"); close(fd); return NULL; } vba_project = create_vba_project(record_count, dir, U); if(vba_project == NULL) { close(fd); return NULL; } buf = NULL; buflen = 0; for(i = 0; i < record_count; i++) { uint16_t length; char *ptr; vba_project->colls[i] = 0; if(!read_uint16(fd, &length, big_endian)) break; if (length == 0) { cli_dbgmsg("vba_readdir: zero name length\n"); break; } if(length > buflen) { unsigned char *newbuf = (unsigned char *)cli_realloc(buf, length); if(newbuf == NULL) break; buflen = length; buf = newbuf; } if (cli_readn(fd, buf, length) != length) { cli_dbgmsg("vba_readdir: read name failed\n"); break; } ptr = get_unicode_name((const char *)buf, length, big_endian); if(ptr == NULL) break; if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) { cli_dbgmsg("vba_readdir: cannot find project %s (%s)\n", ptr, hash); free(ptr); break; } cli_dbgmsg("vba_readdir: project name: %s (%s)\n", ptr, hash); free(ptr); vba_project->name[i] = hash; if(!read_uint16(fd, &length, big_endian)) break; lseek(fd, length, SEEK_CUR); if(!read_uint16(fd, &ffff, big_endian)) break; if (ffff == 0xFFFF) { lseek(fd, 2, SEEK_CUR); if(!read_uint16(fd, &ffff, big_endian)) break; lseek(fd, ffff + 8, SEEK_CUR); } else lseek(fd, ffff + 10, SEEK_CUR); if(!read_uint16(fd, &byte_count, big_endian)) break; lseek(fd, (8 * byte_count) + 5, SEEK_CUR); if(!read_uint32(fd, &offset, big_endian)) break; cli_dbgmsg("vba_readdir: offset: %u\n", (unsigned int)offset); vba_project->offset[i] = offset; lseek(fd, 2, SEEK_CUR); } if(buf) free(buf); close(fd); if(i < record_count) { free(vba_project->name); free(vba_project->colls); free(vba_project->dir); free(vba_project->offset); free(vba_project); return NULL; } return vba_project; }
int cli_chm_open(int fd, const char *dirname, chm_metadata_t *metadata, cli_ctx *ctx) { struct stat statbuf; int retval; cli_dbgmsg("in cli_chm_open\n"); if ((retval = chm_init_metadata(metadata)) != CL_SUCCESS) { return retval; } if (fstat(fd, &statbuf) == 0) { if (statbuf.st_size < CHM_ITSF_MIN_LEN) { return CL_ESTAT; } metadata->m_length = statbuf.st_size; metadata->map = fmap(fd, 0, metadata->m_length); if (!metadata->map) { return CL_EMAP; } } else { char err[128]; cli_warnmsg("fstat() failed: %s\n", cli_strerror(errno, err, sizeof(err))); return CL_ESTAT; } if (!itsf_read_header(metadata)) { goto abort; } itsf_print_header(&metadata->itsf_hdr); if (!itsp_read_header(metadata, metadata->itsf_hdr.dir_offset)) { goto abort; } itsp_print_header(&metadata->itsp_hdr); metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN; /* TODO: need to check this first calculation, currently have no files of this type */ if (metadata->itsp_hdr.index_head > 0) { metadata->chunk_offset += metadata->itsp_hdr.index_head * metadata->itsp_hdr.block_len; } metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1; /* Versions before 3 didn't have a data_offset */ /* TODO: need to check this calculation, currently have no files of this type */ if (metadata->itsf_hdr.version < 3) { metadata->itsf_hdr.data_offset = metadata->itsf_hdr.dir_offset + CHM_ITSP_LEN + (metadata->itsp_hdr.block_len*metadata->itsp_hdr.num_blocks); } while (metadata->num_chunks) { if (read_chunk(metadata) != CL_SUCCESS) { cli_dbgmsg("read_chunk failed\n"); goto abort; } if (read_control_entries(metadata) == FALSE) { goto abort; } metadata->num_chunks--; metadata->chunk_offset += metadata->itsp_hdr.block_len; } if (!metadata->sys_content.length || !metadata->sys_control.length || !metadata->sys_reset.length) { cli_dbgmsg("sys file missing\n"); goto abort; } metadata->ufd = chm_decompress_stream(fd, metadata, dirname, ctx); if (metadata->ufd == -1) { goto abort; } metadata->chunk_entries = 0; metadata->chunk_data = NULL; metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN; metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1; return CL_SUCCESS; abort: funmap(metadata->map); return CL_EFORMAT; }
/* 64-bit version of section header parsing */ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, struct elf_file_hdr64 *file_hdr, uint8_t conv) { struct elf_section_hdr64 *section_hdr = NULL; uint16_t shnum, shentsize; uint32_t i; uint64_t shoff; shnum = file_hdr->e_shnum; cli_dbgmsg("ELF: Number of sections: %d\n", shnum); if(ctx && (shnum > 2048)) { cli_dbgmsg("ELF: Number of sections > 2048, skipping\n"); return CL_BREAK; } else if(elfinfo && (shnum > 256)) { cli_dbgmsg("ELF: Suspicious number of sections\n"); return CL_BREAK; } if(elfinfo) { elfinfo->nsections = shnum; } shentsize = file_hdr->e_shentsize; /* Sanity check */ if(shentsize != sizeof(struct elf_section_hdr64)) { cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr64)\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } if(elfinfo && !shnum) { return CL_CLEAN; } shoff = file_hdr->e_shoff; if(ctx) cli_dbgmsg("ELF: Section header table offset: " STDu64 "\n", shoff); if(elfinfo) { elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section)); if(!elfinfo->section) { cli_dbgmsg("ELF: Can't allocate memory for section headers\n"); return CL_EMEM; } } if(shnum) { section_hdr = (struct elf_section_hdr64 *) cli_calloc(shnum, shentsize); if(!section_hdr) { cli_errmsg("ELF: Can't allocate memory for section headers\n"); if(elfinfo) { free(elfinfo->section); elfinfo->section = NULL; } return CL_EMEM; } if(ctx) { cli_dbgmsg("------------------------------------\n"); } } /* Loop over section headers */ for(i = 0; i < shnum; i++) { uint32_t sh_type, sh_flags; if(fmap_readn(map, §ion_hdr[i], shoff, sizeof(struct elf_section_hdr64)) != sizeof(struct elf_section_hdr64)) { cli_dbgmsg("ELF: Can't read section header\n"); if(ctx) { cli_dbgmsg("ELF: Possibly broken ELF file\n"); } free(section_hdr); if(elfinfo) { free(elfinfo->section); elfinfo->section = NULL; } if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_BREAK; } shoff += sizeof(struct elf_section_hdr64); if(elfinfo) { elfinfo->section[i].rva = EC64(section_hdr[i].sh_addr, conv); elfinfo->section[i].raw = EC64(section_hdr[i].sh_offset, conv); elfinfo->section[i].rsz = EC64(section_hdr[i].sh_size, conv); } if(ctx) { cli_dbgmsg("ELF: Section %u\n", i); cli_dbgmsg("ELF: Section offset: " STDu64 "\n", EC64(section_hdr[i].sh_offset, conv)); cli_dbgmsg("ELF: Section size: " STDu64 "\n", EC64(section_hdr[i].sh_size, conv)); sh_type = EC32(section_hdr[i].sh_type, conv); sh_flags = (uint32_t)(EC64(section_hdr[i].sh_flags, conv) & ELF_SHF_MASK); cli_elf_sectionlog(sh_type, sh_flags); cli_dbgmsg("------------------------------------\n"); } } free(section_hdr); return CL_CLEAN; }
void submit_post(const char *host, const char *port, const char *method, const char *url, const char *postdata, uint32_t timeout) { int sockfd, n; unsigned int i; char *buf, *encoded=NULL; size_t bufsz; ssize_t recvsz; char chunkedlen[21]; fd_set readfds; struct timeval tv; char *acceptable_methods[] = { "GET", "PUT", "POST", NULL }; for (i=0; acceptable_methods[i] != NULL; i++) if (!strcmp(method, acceptable_methods[i])) break; if (acceptable_methods[i] == NULL) return; bufsz = strlen(method); bufsz += sizeof(" HTTP/1.1") + 2; /* Yes. Three blank spaces. +1 for the \n */ bufsz += strlen(url); bufsz += sizeof("Host: \r\n"); bufsz += strlen(host); bufsz += sizeof("Connection: Close\r\n"); bufsz += 4; /* +4 for \r\n\r\n */ if (!strcmp(method, "POST") || !strcmp(method, "PUT")) { encoded = encode_data(postdata); if (!(encoded)) return; snprintf(chunkedlen, sizeof(chunkedlen), "%zu", strlen(encoded)); bufsz += sizeof("Content-Type: application/x-www-form-urlencoded\r\n"); bufsz += sizeof("Content-Length: \r\n"); bufsz += strlen(chunkedlen); bufsz += strlen(encoded); } buf = cli_calloc(1, bufsz); if (!(buf)) { if ((encoded)) free(encoded); return; } snprintf(buf, bufsz, "%s %s HTTP/1.1\r\n", method, url); snprintf(buf+strlen(buf), bufsz-strlen(buf), "Host: %s\r\n", host); snprintf(buf+strlen(buf), bufsz-strlen(buf), "Connection: Close\r\n"); if (!strcmp(method, "POST") || !strcmp(method, "PUT")) { snprintf(buf+strlen(buf), bufsz-strlen(buf), "Content-Type: application/x-www-form-urlencoded\r\n"); snprintf(buf+strlen(buf), bufsz-strlen(buf), "Content-Length: %s\r\n", chunkedlen); snprintf(buf+strlen(buf), bufsz-strlen(buf), "\r\n"); snprintf(buf+strlen(buf), bufsz-strlen(buf), "%s", encoded); free(encoded); } #if defined(_WIN32) sockfd = connect_host(host, port, timeout, 0); #else sockfd = connect_host(host, port, timeout, 1); #endif if (sockfd < 0) { free(buf); return; } cli_dbgmsg("stats - Connected to %s:%s\n", host, port); if ((size_t)send(sockfd, buf, strlen(buf), 0) != (size_t)strlen(buf)) { closesocket(sockfd); free(buf); return; } cli_dbgmsg("stats - Sending %s\n", buf); while (1) { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); /* * Check to make sure the stats submitted okay (so that we don't kill the HTTP request * while it's being processed). Give a ten-second timeout so we don't have a major * impact on scanning. */ tv.tv_sec = timeout; tv.tv_usec = 0; if ((n = select(sockfd+1, &readfds, NULL, NULL, &tv)) <= 0) break; if (FD_ISSET(sockfd, &readfds)) { memset(buf, 0x00, bufsz); if ((recvsz = recv(sockfd, buf, bufsz-1, 0) <= 0)) break; buf[bufsz-1] = '\0'; cli_dbgmsg("stats - received: %s\n", buf); if (strstr(buf, "STATOK")) { cli_dbgmsg("stats - Data received okay\n"); break; } } } closesocket(sockfd); free(buf); }
/* Scan function for ELF */ int cli_scanelf(cli_ctx *ctx) { union elf_file_hdr file_hdr; fmap_t *map = *ctx->fmap; int ret; uint8_t conv = 0, is64 = 0; cli_dbgmsg("in cli_scanelf\n"); /* Load header to determine size and class */ ret = cli_elf_fileheader(ctx, map, &file_hdr, &conv, &is64); if(ret == CL_BREAK) { return CL_CLEAN; /* here, break means "exit but report clean" */ } else if(ret != CL_CLEAN) { return ret; } /* Log File type and machine type */ switch(file_hdr.hdr64.e_type) { case 0x0: /* ET_NONE */ cli_dbgmsg("ELF: File type: None\n"); break; case 0x1: /* ET_REL */ cli_dbgmsg("ELF: File type: Relocatable\n"); break; case 0x2: /* ET_EXEC */ cli_dbgmsg("ELF: File type: Executable\n"); break; case 0x3: /* ET_DYN */ cli_dbgmsg("ELF: File type: Core\n"); break; case 0x4: /* ET_CORE */ cli_dbgmsg("ELF: File type: Core\n"); break; default: cli_dbgmsg("ELF: File type: Unknown (%d)\n", file_hdr.hdr64.e_type); } switch(file_hdr.hdr64.e_machine) { /* Due to a huge list, we only include the most popular machines here */ case 0: /* EM_NONE */ cli_dbgmsg("ELF: Machine type: None\n"); break; case 2: /* EM_SPARC */ cli_dbgmsg("ELF: Machine type: SPARC\n"); break; case 3: /* EM_386 */ cli_dbgmsg("ELF: Machine type: Intel 80386\n"); break; case 4: /* EM_68K */ cli_dbgmsg("ELF: Machine type: Motorola 68000\n"); break; case 8: /* EM_MIPS */ cli_dbgmsg("ELF: Machine type: MIPS RS3000\n"); break; case 9: /* EM_S370 */ cli_dbgmsg("ELF: Machine type: IBM System/370\n"); break; case 15: /* EM_PARISC */ cli_dbgmsg("ELF: Machine type: HPPA\n"); break; case 20: /* EM_PPC */ cli_dbgmsg("ELF: Machine type: PowerPC\n"); break; case 21: /* EM_PPC64 */ cli_dbgmsg("ELF: Machine type: PowerPC 64-bit\n"); break; case 22: /* EM_S390 */ cli_dbgmsg("ELF: Machine type: IBM S390\n"); break; case 40: /* EM_ARM */ cli_dbgmsg("ELF: Machine type: ARM\n"); break; case 41: /* EM_FAKE_ALPHA */ cli_dbgmsg("ELF: Machine type: Digital Alpha\n"); break; case 43: /* EM_SPARCV9 */ cli_dbgmsg("ELF: Machine type: SPARC v9 64-bit\n"); break; case 50: /* EM_IA_64 */ cli_dbgmsg("ELF: Machine type: IA64\n"); break; case 62: /* EM_X86_64 */ cli_dbgmsg("ELF: Machine type: AMD x86-64\n"); break; default: cli_dbgmsg("ELF: Machine type: Unknown (0x%x)\n", file_hdr.hdr64.e_machine); } /* Program headers and Entry */ if(is64) { ret = cli_elf_ph64(ctx, map, NULL, &(file_hdr.hdr64), conv); } else { ret = cli_elf_ph32(ctx, map, NULL, &(file_hdr.hdr32.hdr), conv); } if(ret == CL_BREAK) { return CL_CLEAN; /* break means "exit but report clean" */ } else if(ret != CL_CLEAN) { return ret; } /* Sections */ if(is64) { ret = cli_elf_sh64(ctx, map, NULL, &(file_hdr.hdr64), conv); } else { ret = cli_elf_sh32(ctx, map, NULL, &(file_hdr.hdr32.hdr), conv); } if(ret == CL_BREAK) { return CL_CLEAN; /* break means "exit but report clean" */ } else if(ret != CL_CLEAN) { return ret; } return CL_CLEAN; }
extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len, clcb_pread pread_cb, int use_aging) { unsigned int pages, mapsz, hdrsz; cl_fmap_t *m; int pgsz = cli_getpagesize(); if((off_t)offset < 0 || offset != fmap_align_to(offset, pgsz)) { cli_warnmsg("fmap: attempted mapping with unaligned offset\n"); return NULL; } if(!len) { cli_dbgmsg("fmap: attempted void mapping\n"); return NULL; } if (offset >= len) { cli_warnmsg("fmap: attempted oof mapping\n"); return NULL; } pages = fmap_align_items(len, pgsz); hdrsz = fmap_align_to(sizeof(fmap_t) + (pages-1) * sizeof(uint32_t), pgsz); /* fmap_t includes 1 bitmap slot, hence (pages-1) */ mapsz = pages * pgsz + hdrsz; #ifndef ANONYMOUS_MAP use_aging = 0; #endif #ifdef ANONYMOUS_MAP if (use_aging) { fmap_lock; if ((m = (fmap_t *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|/*FIXME: MAP_POPULATE is ~8% faster but more memory intensive */ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) { m = NULL; } else { #if HAVE_MADVISE madvise((void *)m, mapsz, MADV_RANDOM|MADV_DONTFORK); #endif /* madvise */ /* fault the header while we still have the lock - we DO context switch here a lot here :@ */ memset(fmap_bitmap, 0, sizeof(uint32_t) * pages); } fmap_unlock; } #endif /* ANONYMOUS_MAP */ if (!use_aging) { m = (fmap_t *)cli_malloc(mapsz); if (!(m)) { cli_warnmsg("fmap: map allocation failed\n"); return NULL; } memset(m, 0, hdrsz); } if(!m) { cli_warnmsg("fmap: map allocation failed\n"); return NULL; } m->handle = handle; m->pread_cb = pread_cb; m->aging = use_aging; m->offset = offset; m->nested_offset = 0; m->len = len;/* m->nested_offset + m->len = m->real_len */ m->real_len = len; m->pages = pages; m->hdrsz = hdrsz; m->pgsz = pgsz; m->paged = 0; m->dont_cache_flag = 0; m->unmap = use_aging ? unmap_mmap : unmap_malloc; m->need = handle_need; m->need_offstr = handle_need_offstr; m->gets = handle_gets; m->unneed_off = handle_unneed_off; return m; }