int prtn_intxn_list_check(prtn_intxn_list_t* list, unsigned *pitxn, off_t start, size_t size) { prtn_intxn_node_t *new_node, *check_node; int ret = CL_CLEAN; *pitxn = list->Size; check_node = list->Head; while (check_node != NULL) { (*pitxn)--; if (start > check_node->Start) { if (check_node->Start+check_node->Size > start) { ret = CL_VIRUS; break; } } else if (start < check_node->Start) { if (start+size > check_node->Start) { ret = CL_VIRUS; break; } } else { ret = CL_VIRUS; break; } check_node = check_node->Next; } /* allocate new node for partition bounds */ new_node = (prtn_intxn_node_t *) cli_malloc(sizeof(prtn_intxn_node_t)); if (!new_node) { cli_dbgmsg("PRTN_INTXN: could not allocate new node for checklist!\n"); prtn_intxn_list_free(list); return CL_EMEM; } new_node->Start = start; new_node->Size = size; new_node->Next = list->Head; list->Head = new_node; (list->Size)++; return ret; }
static int apm_prtn_intxn(cli_ctx *ctx, struct apm_partition_info *aptable, size_t sectorsize, int old_school) { prtn_intxn_list_t prtncheck; struct apm_partition_info apentry; unsigned i, pitxn; int ret = CL_CLEAN, tmp = CL_CLEAN; off_t pos; uint32_t max_prtns = 0; prtn_intxn_list_init(&prtncheck); /* check engine maxpartitions limit */ if (aptable->numPartitions < ctx->engine->maxpartitions) { max_prtns = aptable->numPartitions; } else { max_prtns = ctx->engine->maxpartitions; } for (i = 1; i <= max_prtns; ++i) { /* read partition table entry */ pos = i * sectorsize; if (fmap_readn(*ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) { cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n"); prtn_intxn_list_free(&prtncheck); return CL_EFORMAT; } /* convert necessary info big endian to host */ apentry.pBlockStart = be32_to_host(apentry.pBlockStart); apentry.pBlockCount = be32_to_host(apentry.pBlockCount); /* re-calculate if old_school and aligned [512 * 4 => 2048] */ if (old_school && ((i % 4) == 0)) { if (!strncmp((char*)apentry.type, "Apple_Driver", 32) || !strncmp((char*)apentry.type, "Apple_Driver43", 32) || !strncmp((char*)apentry.type, "Apple_Driver43_CD", 32) || !strncmp((char*)apentry.type, "Apple_Driver_ATA", 32) || !strncmp((char*)apentry.type, "Apple_Driver_ATAPI", 32) || !strncmp((char*)apentry.type, "Apple_Patches", 32)) { apentry.pBlockCount = apentry.pBlockCount * 4;; } } tmp = prtn_intxn_list_check(&prtncheck, &pitxn, apentry.pBlockStart, apentry.pBlockCount); if (tmp != CL_CLEAN) { if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) { apm_parsemsg("Name: %s\n", (char*)aptable.name); apm_parsemsg("Type: %s\n", (char*)aptable.type); cli_dbgmsg("cli_scanapm: detected intersection with partitions " "[%u, %u]\n", pitxn, i); cli_append_virus(ctx, PRTN_INTXN_DETECTION); ret = tmp; tmp = 0; } else if (tmp == CL_VIRUS) { apm_parsemsg("Name: %s\n", (char*)aptable.name); apm_parsemsg("Type: %s\n", (char*)aptable.type); cli_dbgmsg("cli_scanapm: detected intersection with partitions " "[%u, %u]\n", pitxn, i); cli_append_virus(ctx, PRTN_INTXN_DETECTION); prtn_intxn_list_free(&prtncheck); return CL_VIRUS; } else { prtn_intxn_list_free(&prtncheck); return tmp; } } pos += sectorsize; } prtn_intxn_list_free(&prtncheck); return ret; }
/* checks internal logical partitions */ static int mbr_extended_prtn_intxn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t sectorsize) { struct mbr_boot_record ebr; prtn_intxn_list_t prtncheck; unsigned i, pitxn; int ret = CL_CLEAN, tmp = CL_CLEAN, mbr_base = 0; off_t pos = 0, logiclba = 0; mbr_base = sectorsize - sizeof(struct mbr_boot_record); prtn_intxn_list_init(&prtncheck); logiclba = 0; i = 0; do { pos = extlba * sectorsize; /* start of extended partition */ /* read the extended boot record */ pos += (logiclba * sectorsize) + mbr_base; if (fmap_readn(*ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) { cli_dbgmsg("cli_scanebr: Invalid extended boot record\n"); prtn_intxn_list_free(&prtncheck); return CL_EFORMAT; } /* convert the little endian to host */ mbr_convert_to_host(&ebr); /* update state */ (*prtncount)++; /* assume that logical record is first and extended is second */ tmp = prtn_intxn_list_check(&prtncheck, &pitxn, logiclba, ebr.entries[0].numLBA); if (tmp != CL_CLEAN) { if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) { cli_dbgmsg("cli_scanebr: detected intersection with partitions " "[%u, %u]\n", pitxn, i); cli_append_virus(ctx, PRTN_INTXN_DETECTION); ret = tmp; tmp = 0; } else if (tmp == CL_VIRUS) { cli_dbgmsg("cli_scanebr: detected intersection with partitions " "[%u, %u]\n", pitxn, i); cli_append_virus(ctx, PRTN_INTXN_DETECTION); prtn_intxn_list_free(&prtncheck); return CL_VIRUS; } else { prtn_intxn_list_free(&prtncheck); return tmp; } } /* assume extended is second entry */ if (ebr.entries[1].type != MBR_EXTENDED) { cli_dbgmsg("cli_scanebr: second entry for EBR is not an extended partition\n"); break; } logiclba = ebr.entries[1].firstLBA; ++i; } while (logiclba != 0 && (*prtncount) < ctx->engine->maxpartitions); prtn_intxn_list_free(&prtncheck); return ret; }
/* this includes the overall bounds of extended partitions */ static int mbr_primary_prtn_intxn(cli_ctx *ctx, struct mbr_boot_record mbr, size_t sectorsize) { prtn_intxn_list_t prtncheck; unsigned i = 0, pitxn = 0, prtncount = 0; int ret = CL_CLEAN, tmp = CL_CLEAN; prtn_intxn_list_init(&prtncheck); for (i = 0; i < MBR_MAX_PARTITION_ENTRIES && prtncount < ctx->engine->maxpartitions; ++i) { if (mbr.entries[i].type == MBR_EMPTY) { /* empty partiton entry */ prtncount++; } else { tmp = prtn_intxn_list_check(&prtncheck, &pitxn, mbr.entries[i].firstLBA, mbr.entries[i].numLBA); if (tmp != CL_CLEAN) { if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) { cli_dbgmsg("cli_scanmbr: detected intersection with partitions " "[%u, %u]\n", pitxn, i); cli_append_virus(ctx, PRTN_INTXN_DETECTION); ret = tmp; tmp = 0; } else if (tmp == CL_VIRUS) { cli_dbgmsg("cli_scanmbr: detected intersection with partitions " "[%u, %u]\n", pitxn, i); cli_append_virus(ctx, PRTN_INTXN_DETECTION); prtn_intxn_list_free(&prtncheck); return CL_VIRUS; } else { prtn_intxn_list_free(&prtncheck); return tmp; } } if (mbr.entries[i].type == MBR_EXTENDED) { /* check the logical partitions */ tmp = mbr_extended_prtn_intxn(ctx, &prtncount, mbr.entries[i].firstLBA, sectorsize); if (tmp != CL_CLEAN) { if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) { ret = tmp; tmp = 0; } else if (tmp == CL_VIRUS) { prtn_intxn_list_free(&prtncheck); return CL_VIRUS; } else { prtn_intxn_list_free(&prtncheck); return tmp; } } } else { prtncount++; } } } prtn_intxn_list_free(&prtncheck); return ret; }
static int gpt_prtn_intxn(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize) { prtn_intxn_list_t prtncheck; struct gpt_partition_entry gpe; unsigned i, pitxn; int ret = CL_CLEAN, tmp = CL_CLEAN; off_t pos; size_t maplen; uint32_t max_prtns = 0; int virus_found = 0; maplen = (*ctx->fmap)->real_len; /* convert endian to host to check partition table */ hdr.tableStartLBA = le64_to_host(hdr.tableStartLBA); hdr.tableNumEntries = le32_to_host(hdr.tableNumEntries); prtn_intxn_list_init(&prtncheck); /* check engine maxpartitions limit */ if (hdr.tableNumEntries < ctx->engine->maxpartitions) { max_prtns = hdr.tableNumEntries; } else { max_prtns = ctx->engine->maxpartitions; } pos = hdr.tableStartLBA * sectorsize; for (i = 0; i < max_prtns; ++i) { /* read in partition entry */ if (fmap_readn(*ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) { cli_dbgmsg("cli_scangpt: Invalid GPT partition entry\n"); prtn_intxn_list_free(&prtncheck); return CL_EFORMAT; } /* convert the endian to host */ gpe.firstLBA = le64_to_host(gpe.firstLBA); gpe.lastLBA = le64_to_host(gpe.lastLBA); if (gpe.firstLBA == 0) { /* empty partition, invalid */ } else if ((gpe.firstLBA > gpe.lastLBA) || (gpe.firstLBA < hdr.firstUsableLBA) || (gpe.lastLBA > hdr.lastUsableLBA)) { /* partition exists outside bounds specified by header or invalid */ } else if (((gpe.lastLBA+1) * sectorsize) > maplen) { /* partition exists outside bounds of the file map */ } else { tmp = prtn_intxn_list_check(&prtncheck, &pitxn, gpe.firstLBA, gpe.lastLBA - gpe.firstLBA + 1); if (tmp != CL_CLEAN) { if (tmp == CL_VIRUS) { cli_dbgmsg("cli_scangpt: detected intersection with partitions " "[%u, %u]\n", pitxn, i); ret = cli_append_virus(ctx, PRTN_INTXN_DETECTION); if (ret == CL_VIRUS) virus_found = 1; if (SCAN_ALLMATCHES || ret == CL_CLEAN) tmp = 0; else goto leave; } else { ret = tmp; goto leave; } } } /* increment the offsets to next partition entry */ pos += hdr.tableEntrySize; } leave: prtn_intxn_list_free(&prtncheck); if (virus_found) return CL_VIRUS; return ret; }