/****************************************************************/ /* mdso: midipix dso scavenger */ /* Copyright (C) 2015--2024 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.MDSO. */ /****************************************************************/ #include #include #include #include #include #include #include "mdso_object_impl.h" #include "mdso_errinfo_impl.h" #include "perk_structs.h" static void mdso_obj_write_objname(char * ch, off_t objidx) { ch[0] = 's'; ch[6] = (objidx % 10) + '0'; objidx /= 10; ch[5] = (objidx % 10) + '0'; objidx /= 10; ch[4] = (objidx % 10) + '0'; objidx /= 10; ch[3] = (objidx % 10) + '0'; objidx /= 10; ch[2] = (objidx % 10) + '0'; objidx /= 10; ch[1] = (objidx % 10) + '0'; objidx /= 10; ch[7] = '.'; ch[8] = 'o'; } static void mdso_argen_common_hdr( struct pe_raw_archive_common_hdr * arhdr, char * file_id, size_t size) { size_t slen; memset(arhdr,0x20,sizeof(*arhdr)); slen = strlen(file_id); memcpy(arhdr->ar_file_id,file_id,slen); arhdr->ar_file_id[slen] = '/'; arhdr->ar_uid[0] = '0'; arhdr->ar_gid[0] = '0'; arhdr->ar_file_mode[0] = '0'; arhdr->ar_time_date_stamp[0] = '0'; mdso_obj_write_dec(arhdr->ar_file_size,size); arhdr->ar_end_tag[0] = 0x60; arhdr->ar_end_tag[1] = 0x0a; } static void mdso_write_big_endian_long(unsigned char * ch, uint32_t val) { ch[3] = val; ch[2] = val >> 8; ch[1] = val >> 16; ch[0] = val >> 24; } int mdso_argen_common( const struct mdso_driver_ctx * dctx, const char ** symv, struct mdso_object * vobj) { int ret; const char ** psym; intptr_t nobj; uint32_t objlen; uint32_t hdrlen; uint32_t mapstrsnum; uint32_t mapstrslen; uint32_t symidx; void * addr; unsigned char * ar; unsigned char * mark; unsigned char * idx; char * mapstrs; struct pe_raw_archive_common_hdr * arhdr; struct mdso_object * pobj; struct mdso_object * aobj; struct mdso_object sobj[256]; char objname[16]; /* init */ memset(sobj,0,sizeof(sobj)); for (psym=symv; *psym; psym++) (void)0; if ((nobj = psym - symv) < 255) aobj = sobj; else if (nobj > 1024*1024) return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_VECTOR); else if (!(aobj = calloc(1,++nobj*sizeof(*aobj)))) return MDSO_SYSTEM_ERROR(dctx); /* objlen: archive signature, index header */ objlen = 8; objlen += sizeof(struct pe_raw_archive_common_hdr); /* objlen: member headers */ ret = mdso_objgen_dsometa(dctx,aobj); aobj->size += 1; aobj->size |= 1; aobj->size ^= 1; objlen += aobj->size; objlen += sizeof(struct pe_raw_archive_common_hdr); mapstrslen = aobj->mapstrslen; mapstrsnum = aobj->mapstrsnum; /* objlen: symentry */ for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) { ret = mdso_objgen_symentry(dctx,*psym,pobj); pobj->size += 1; pobj->size |= 1; pobj->size ^= 1; objlen += pobj->size; objlen += sizeof(struct pe_raw_archive_common_hdr); mapstrslen += pobj->mapstrslen; mapstrsnum += pobj->mapstrsnum; pobj++; } /* verify logic */ if (ret && (aobj == sobj)) return MDSO_NESTED_ERROR(dctx); if (ret) { free(aobj); return MDSO_NESTED_ERROR(dctx); } /* index: string block alignment */ mapstrslen += 1; mapstrslen |= 1; mapstrslen ^= 1; /* objlen: index size, padding */ objlen += sizeof(uint32_t) * (1 + mapstrsnum); objlen += mapstrslen; /* archive meta info, in-memory mapping */ if (vobj->addr && (vobj->size < objlen)) return MDSO_BUFFER_ERROR(dctx); if ((addr = vobj->addr)) { (void)0; } else { vobj->size = objlen; vobj->mapstrslen = mapstrslen; vobj->mapstrsnum = mapstrsnum; if (!vobj->name) return 0; else if (mdso_create_archive(dctx,vobj) < 0) return MDSO_NESTED_ERROR(dctx); } ar = (unsigned char *)vobj->addr; /* archive signature */ memcpy(ar,"!\n",8); mark = &ar[8]; /* archive header */ arhdr = (struct pe_raw_archive_common_hdr *)mark; hdrlen = sizeof(uint32_t) * (1 + mapstrsnum) + mapstrslen; mdso_argen_common_hdr(arhdr,"",hdrlen); mark += sizeof(*arhdr); /* archive index initialization */ mdso_write_big_endian_long(mark,mapstrsnum); mark += sizeof(uint32_t); idx = mark; mark += sizeof(uint32_t) * mapstrsnum; mapstrs = (char *)mark; mark += mapstrslen; /* .dsometa object */ aobj->mapstrs = mapstrs; aobj->arhdrpos = (uint32_t)(mark - ar); aobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr); aobj->addr = &mark[aobj->arhdrlen]; for (symidx=0; symidxmapstrsnum; symidx++) { mdso_write_big_endian_long(idx,aobj->arhdrpos); idx += sizeof(uint32_t); } ret = mdso_objgen_dsometa(dctx,aobj); mdso_argen_common_hdr( (struct pe_raw_archive_common_hdr *)mark, ".dsometa.o",aobj->size); mark += aobj->arhdrlen + aobj->size; mapstrs += aobj->mapstrslen; /* archive symentry objects */ for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) { /* symentry object */ pobj->mapstrs = mapstrs; pobj->arhdrpos = (uint32_t)(mark - ar); pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr); pobj->addr = &mark[pobj->arhdrlen]; for (symidx=0; symidxmapstrsnum; symidx++) { mdso_write_big_endian_long(idx,pobj->arhdrpos); idx += sizeof(uint32_t); } mdso_obj_write_objname(objname,psym - symv); ret = mdso_objgen_symentry(dctx,*psym,pobj); mdso_argen_common_hdr( (struct pe_raw_archive_common_hdr *)mark, objname,pobj->size); mark += pobj->arhdrlen + pobj->size; mapstrs += pobj->mapstrslen; pobj++; } /* aobj */ if (aobj != sobj) free(aobj); /* fs object unmap */ if (!addr) munmap(vobj->addr,vobj->size); /* verify */ if (ret) return MDSO_NESTED_ERROR(dctx); /* tada */ return 0; }