Blame src/driver/pe_unit_ctx.c

e2e2c2
/***************************************************************/
e2e2c2
/*  perk: PE Resource Kit                                      */
425fb8
/*  Copyright (C) 2015--2021  SysDeer Technologies, LLC        */
e2e2c2
/*  Released under GPLv2 and GPLv3; see COPYING.PERK.          */
e2e2c2
/***************************************************************/
e2e2c2
81e8b3
#include <stdint.h>
d7ed3e
#include <stddef.h>
81e8b3
#include <stdlib.h>
81e8b3
#include <string.h>
81e8b3
#include <sys/mman.h>
d7ed3e
81e8b3
#include <perk/perk.h>
d9d2d9
#include <perk/perk_arbits.h>
d9d2d9
#include "perk_ar_impl.h"
eb4c04
#include "perk_driver_impl.h"
9b7081
#include "perk_errinfo_impl.h"
81e8b3
118b74
static int pe_lib_free_unit_ctx_impl(struct pe_unit_ctx_impl * ctx, int ret)
81e8b3
{
d9d2d9
	struct pe_image_meta ** pmeta;
81e8b3
	if (ctx) {
d9d2d9
		for (pmeta=ctx->objmeta; pmeta && *pmeta; pmeta++)
d9d2d9
			pe_meta_free_image_meta(*pmeta);
d9d2d9
d9d2d9
		pe_ar_free_archive_meta(ctx->armeta);
57ddbe
		pe_meta_free_image_meta(ctx->meta);
a7c639
		pe_raw_unmap_raw_image(&ctx->map);
d9d2d9
		free(ctx->objmeta);
81e8b3
		free(ctx);
81e8b3
	}
81e8b3
9b7081
	return ret;
81e8b3
}
81e8b3
d9d2d9
static int pe_lib_create_object_vector_or_verify_archive(
d9d2d9
	const struct pe_driver_ctx *    dctx,
d9d2d9
	struct pe_unit_ctx_impl *       ctx)
d9d2d9
{
d9d2d9
	struct pe_archive_meta *        actx;
d9d2d9
	struct pe_archive_meta_impl *   ictx;
d9d2d9
	struct pe_driver_ctx_impl *     idctx;
d9d2d9
	bool                            fvector;
d9d2d9
	bool                            fstrict;
d9d2d9
	bool                            fpurearch;
d9d2d9
	struct pe_image_meta *          meta;
d9d2d9
	struct pe_image_meta **         objmeta;
d9d2d9
	size_t                          veclen;
d9d2d9
	struct pe_raw_image             map;
d9d2d9
	struct ar_meta_member_info **   pmember;
d9d2d9
	struct pe_error_info **         errinfp;
d9d2d9
	enum pe_abi                     m_abi;
d9d2d9
	enum pe_subtype                 m_subtype;
d9d2d9
d9d2d9
	fvector   = (dctx->cctx->drvflags & PERK_DRIVER_AR_OBJECT_VECTOR);
d9d2d9
	fstrict   = (dctx->cctx->drvflags & PERK_DRIVER_AR_STRICT_PE);
d9d2d9
	fpurearch = (dctx->cctx->drvflags & PERK_DRIVER_AR_STRICT_PE_ARCH);
d9d2d9
d9d2d9
	if (!fvector && !fstrict && !fpurearch)
d9d2d9
		return 0;
d9d2d9
d9d2d9
	actx   = ctx->armeta;
d9d2d9
	ictx   = pe_archive_meta_ictx(actx);
d9d2d9
	idctx  = pe_get_driver_ictx(dctx);
d9d2d9
	veclen = ictx->nentries + 1;
d9d2d9
d9d2d9
	if (fvector && !(ctx->objmeta = calloc(veclen,sizeof(meta))))
d9d2d9
		return PERK_BUFFER_ERROR(dctx);
d9d2d9
d9d2d9
	if (!actx->a_memberv)
d9d2d9
		return 0;
d9d2d9
d9d2d9
	for (pmember=actx->a_memberv,objmeta=ctx->objmeta; *pmember; pmember++) {
d9d2d9
		errinfp = idctx->errinfp;
d9d2d9
d9d2d9
		switch (pmember[0]->ar_member_attr) {
d9d2d9
			case AR_MEMBER_ATTR_ARCHIVE:
d9d2d9
				return PERK_CUSTOM_ERROR(dctx,
d9d2d9
					PERK_ERR_AR_NESTED_ARCHIVE);
d9d2d9
d9d2d9
			case AR_MEMBER_ATTR_ARMAP:
d9d2d9
			case AR_MEMBER_ATTR_NAMESTRS:
d9d2d9
			case AR_MEMBER_ATTR_LINKINFO:
d9d2d9
				break;
d9d2d9
d9d2d9
			default:
d9d2d9
				map.map_addr = pmember[0]->ar_object_data;
d9d2d9
				map.map_size = pmember[0]->ar_object_size;
d9d2d9
d9d2d9
				if (!pe_meta_get_image_meta(dctx,&map,&meta)) {
d9d2d9
					if (fpurearch && (objmeta == ctx->objmeta)) {
d9d2d9
						m_abi     = meta->m_abi;
d9d2d9
						m_subtype = meta->m_subtype;
d9d2d9
d9d2d9
					} else if (fpurearch) {
d9d2d9
						if ((meta->m_abi != m_abi) || (meta->m_subtype != m_subtype))
d9d2d9
							return PERK_CUSTOM_ERROR(dctx,
d9d2d9
								PERK_ERR_AR_MIXED_PE_MEMBERS);
d9d2d9
					}
d9d2d9
d9d2d9
					if (fvector) {
d9d2d9
						*objmeta++ = meta;
d9d2d9
					} else {
d9d2d9
						pe_meta_free_image_meta(meta);
d9d2d9
					};
d9d2d9
d9d2d9
d9d2d9
				} else if (fstrict || fpurearch) {
d9d2d9
					return PERK_CUSTOM_ERROR(dctx,
d9d2d9
						PERK_ERR_AR_NON_PE_MEMBERS);
d9d2d9
d9d2d9
				} else {
d9d2d9
					 idctx->errinfp = errinfp;
d9d2d9
d9d2d9
					for (; *errinfp; )
d9d2d9
						*errinfp++ = 0;
d9d2d9
				}
d9d2d9
d9d2d9
				break;
d9d2d9
		}
d9d2d9
	}
d9d2d9
d9d2d9
	return 0;
d9d2d9
}
d9d2d9
118b74
int pe_lib_get_unit_ctx(
a9788e
	const struct pe_driver_ctx *	dctx,
a9788e
	const char *			path,
a9788e
	struct pe_unit_ctx **		pctx)
81e8b3
{
d7ed3e
	struct pe_unit_ctx_impl *	ctx;
720609
	int				prot;
d9d2d9
	char *                          mark;
d9d2d9
	size_t                          siglen;
81e8b3
9b7081
	if (!dctx)
cee41b
		return PERK_CUSTOM_ERROR(
cee41b
			dctx,PERK_ERR_NULL_CONTEXT);
9b7081
9b7081
	else if (!(ctx = calloc(1,sizeof(*ctx))))
9b7081
		return PERK_BUFFER_ERROR(dctx);
81e8b3
c29b50
	pe_driver_set_ectx(
c29b50
		dctx,0,path);
c29b50
5b008c
	prot = (dctx->cctx->drvflags & PERK_DRIVER_MAP_WRITE_ACCESS)
81e8b3
		? PROT_READ | PROT_WRITE
81e8b3
		: PROT_READ;
81e8b3
a7c639
	if (pe_raw_map_raw_image(dctx,-1,path,prot,&ctx->map))
118b74
		return pe_lib_free_unit_ctx_impl(ctx,
cee41b
			PERK_NESTED_ERROR(dctx));
81e8b3
d9d2d9
	if (ctx->map.map_size < (siglen = sizeof(struct ar_raw_signature)))
d9d2d9
		return pe_lib_free_unit_ctx_impl(ctx,
d9d2d9
			PERK_CUSTOM_ERROR(
d9d2d9
				dctx,
d9d2d9
				PERK_ERR_INVALID_IMAGE));
d9d2d9
d9d2d9
	if (!strncmp((mark = ctx->map.map_addr),AR_SIGNATURE,siglen)) {
d9d2d9
		ctx->armap.map_addr = ctx->map.map_addr;
d9d2d9
		ctx->armap.map_size = ctx->map.map_size;
d9d2d9
d9d2d9
		if (pe_ar_get_archive_meta(dctx,&ctx->armap,&ctx->armeta))
d9d2d9
			return pe_lib_free_unit_ctx_impl(ctx,
d9d2d9
				PERK_NESTED_ERROR(dctx));
d9d2d9
d9d2d9
		if (pe_lib_create_object_vector_or_verify_archive(dctx,ctx) < 0)
d9d2d9
			return pe_lib_free_unit_ctx_impl(ctx,
d9d2d9
				PERK_NESTED_ERROR(dctx));
d9d2d9
d9d2d9
	} else if (pe_meta_get_image_meta(dctx,&ctx->map,&ctx->meta)) {
118b74
		return pe_lib_free_unit_ctx_impl(ctx,
9b7081
			PERK_NESTED_ERROR(dctx));
d9d2d9
	}
81e8b3
345bea
	ctx->path	  = path;
345bea
	ctx->uctx.path	  = &ctx->path;
345bea
	ctx->uctx.meta	  = ctx->meta;
345bea
	ctx->uctx.armeta  = ctx->armeta;
d7ed3e
d7ed3e
	*pctx = &ctx->uctx;
81e8b3
	return 0;
81e8b3
}
81e8b3
118b74
void pe_lib_free_unit_ctx(struct pe_unit_ctx * ctx)
81e8b3
{
d7ed3e
	struct pe_unit_ctx_impl *	ictx;
d7ed3e
	uintptr_t			addr;
d7ed3e
d7ed3e
	if (ctx) {
d7ed3e
		addr = (uintptr_t)ctx - offsetof(struct pe_unit_ctx_impl,uctx);
d7ed3e
		ictx = (struct pe_unit_ctx_impl *)addr;
118b74
		pe_lib_free_unit_ctx_impl(ictx,0);
d7ed3e
	}
81e8b3
}