/* * Copyright 2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author(s): Peter Jones */ #include "libdpe.h" #include #include #include #include #define adjust(x,y) ((x) = (typeof (x))(((uint8_t *)(x)) + (y))) static void pe_fix_addresses(Pe *pe, int64_t offset) { pe->map_address += offset; adjust(pe->state.pe.mzhdr, offset); adjust(pe->state.pe.pehdr, offset); adjust(pe->state.pe.reserved0, offset); adjust(pe->state.pe.reserved1, offset); adjust(pe->state.pe.shdr, offset); size_t scncnt = get_shnum(pe->map_address, pe->maximum_size); /* in general this means we couldn't identify any sections, so * they must not need to be fixed up. */ if (scncnt == (size_t)-1l) return; for (size_t cnt = 0; cnt < scncnt; cnt++) { pe->state.pe.scns.data[cnt].shdr = &pe->state.pe.shdr[cnt]; adjust(pe->state.pe.scns.data[cnt].rawdata_base, offset); adjust(pe->state.pe.scns.data[cnt].data_base, offset); } } #undef adjust #define align(val, align) (((val) + (align) -1 ) & (- (align))) int pe_set_image_size(Pe *pe) { uint32_t image_size = 0; struct pe_hdr *pehdr = pe->state.pe.pehdr; struct pe32plus_opt_hdr *opthdr = pe->state.pe32plus_exe.opthdr; Pe_Scn *scn = NULL; struct section_header shdr, tmp_shdr; for (int i = 0; i < pehdr->sections; i++) { scn = pe_nextscn(pe, scn); if (scn == NULL) break; pe_getshdr(scn, &tmp_shdr); if (tmp_shdr.virtual_size > 0) memcpy (&shdr, &tmp_shdr, sizeof(shdr)); } int falign = pe_get_file_alignment(pe); int salign = pe_get_scn_alignment(pe); image_size = shdr.virtual_address - opthdr->image_base + align(align(shdr.virtual_size, falign), salign); pe->state.pe32plus_exe.opthdr->image_size = image_size; return 0; } int pe_extend_file(Pe *pe, size_t size, uint32_t *new_space, int align) { int error; void *new = NULL; if (align) align = ALIGNMENT_PADDING(pe->maximum_size, align); int extra = size + align; int rc = ftruncate(pe->fildes, pe->maximum_size + extra); if (rc < 0) return -1; error = munmap(pe->map_address, pe->maximum_size); if (error != 0) err(1, "munmap"); new = mmap(pe->map_address, pe->maximum_size + extra, PROT_WRITE | PROT_READ, MAP_SHARED, pe->fildes, 0); if (new == MAP_FAILED) { err(1, "mmap"); __libpe_seterrno (PE_E_NOMEM); return -1; } if (new != pe->map_address) pe_fix_addresses(pe, (uint8_t *)new-(uint8_t *)pe->map_address); char *addr = compute_mem_addr(pe, pe->maximum_size); memset(addr, '\0', extra); *new_space = compute_file_addr(pe, addr + align); pe->maximum_size = pe->maximum_size + extra; return 0; } int pe_shorten_file(Pe *pe, size_t size) { void *new = NULL; int error; error = munmap(pe->map_address, pe->maximum_size); if (error != 0) err(1, "munmap"); new = mmap(pe->map_address, pe->maximum_size - size, PROT_READ | PROT_WRITE, MAP_SHARED, pe->fildes, 0); if (new == MAP_FAILED) { err(1, "mmap"); __libpe_seterrno (PE_E_NOMEM); return -1; } int rc = ftruncate(pe->fildes, pe->maximum_size - size); if (rc < 0) return -1; pe->maximum_size -= size; return 0; } int pe_freespace(Pe *pe, uint32_t offset, size_t size) { void *addr = compute_mem_addr(pe, offset); memset(addr, '\0', size); if (offset + size == pe->maximum_size) pe_shorten_file(pe, size); /* XXX PJFIX TODO: this should actually de-allocate the space, *if* * it's the certificate list, when it isn't at the end of the file, * too. */ return 0; }