Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
libpkg: track lib32 and Linuxulator shlibs
Isaac Freund committed 1 year ago
commit 3882f0f5ce273cd2e6704669b47690f00b579964
parent 92695ba
8 files changed +134 -71
modified libpkg/pkg.c
@@ -22,6 +22,7 @@
#include "private/pkg.h"
#include "private/pkgdb.h"
#include "private/utils.h"
+
#include "xmalloc.h"

#define dbg(x, ...) pkg_dbg(PKG_DBG_PACKAGE, x, __VA_ARGS__)

@@ -898,34 +899,99 @@ pkg_addoption_description(struct pkg *pkg, const char *key,
	return (EPKG_OK);
}

+
enum pkg_shlib_flags
+
pkg_shlib_flags_from_abi(const struct pkg_abi *shlib_abi)
+
{
+
	enum pkg_shlib_flags flags = PKG_SHLIB_FLAGS_NONE;
+

+
	if (ctx.abi.os == PKG_OS_FREEBSD) {
+
		if (shlib_abi->os == PKG_OS_LINUX) {
+
			flags |= PKG_SHLIB_FLAGS_COMPAT_LINUX;
+
		}
+

+
		switch (ctx.abi.arch) {
+
		case PKG_ARCH_AMD64:
+
			if (shlib_abi->arch == PKG_ARCH_I386) {
+
				flags |= PKG_SHLIB_FLAGS_COMPAT_32;
+
			}
+
			break;
+
		case PKG_ARCH_AARCH64:
+
			if (shlib_abi->arch == PKG_ARCH_ARMV7) {
+
				flags |= PKG_SHLIB_FLAGS_COMPAT_32;
+
			}
+
			break;
+
		case PKG_ARCH_POWERPC64:
+
			if (shlib_abi->arch == PKG_ARCH_POWERPC) {
+
				flags |= PKG_SHLIB_FLAGS_COMPAT_32;
+
			}
+
			break;
+
		}
+
	}
+

+
	return (flags);
+
}
+

+
/*
+
 * Format examples:
+
 *
+
 * libfoo.so.1.0.0          - native
+
 * libfoo.so.1.0.0:32       - compat 32
+
 * libfoo.so.1.0.0:Linux    - compat Linux
+
 * libfoo.so.1.0.0:Linux:32 - compat Linux 32
+
 */
+
static char *
+
pkg_shlib_name_with_flags(const char *name, enum pkg_shlib_flags flags)
+
{
+
	const char *compat_os = "";
+
	if ((flags & PKG_SHLIB_FLAGS_COMPAT_LINUX) != 0) {
+
		compat_os = ":Linux";
+
	}
+

+
	const char *compat_arch = "";
+
	if ((flags & PKG_SHLIB_FLAGS_COMPAT_32) != 0) {
+
		compat_arch = ":32";
+
	}
+

+
	char *ret;
+
	xasprintf(&ret, "%s%s%s", name, compat_os, compat_arch);
+
	return (ret);
+
}
+

int
-
pkg_addshlib_required(struct pkg *pkg, const char *name)
+
pkg_addshlib_required(struct pkg *pkg, const char *name,
+
    enum pkg_shlib_flags flags)
{
	assert(pkg != NULL);
	assert(name != NULL && name[0] != '\0');

-
	if (match_ucl_lists(name,
+
	char *full_name = pkg_shlib_name_with_flags(name, flags);
+

+
	if (match_ucl_lists(full_name,
	    pkg_config_get("SHLIB_REQUIRE_IGNORE_GLOB"),
	    pkg_config_get("SHLIB_REQUIRE_IGNORE_REGEX"))) {
-
		dbg(3, "ignoring shlib %s required by package %s", name, pkg->name);
+
		dbg(3, "ignoring shlib %s required by package %s", full_name, pkg->name);
+
		free(full_name);
		return (EPKG_OK);
	}

	/* silently ignore duplicates in case of shlibs */
	tll_foreach(pkg->shlibs_required, s) {
-
		if (STREQ(s->item, name))
+
		if (STREQ(s->item, full_name)) {
+
			free(full_name);
			return (EPKG_OK);
+
		}
	}

-
	tll_push_back(pkg->shlibs_required, xstrdup(name));
+
	tll_push_back(pkg->shlibs_required, full_name);

-
	dbg(3, "added shlib deps for %s on %s", pkg->name, name);
+
	dbg(3, "added shlib deps for %s on %s", pkg->name, full_name);

	return (EPKG_OK);
}

int
-
pkg_addshlib_provided(struct pkg *pkg, const char *name)
+
pkg_addshlib_provided(struct pkg *pkg, const char *name,
+
    enum pkg_shlib_flags flags)
{
	assert(pkg != NULL);
	assert(name != NULL && name[0] != '\0');
@@ -934,15 +1000,19 @@ pkg_addshlib_provided(struct pkg *pkg, const char *name)
	if (strncmp(name, "lib", 3) != 0)
		return (EPKG_OK);

+
	char *full_name = pkg_shlib_name_with_flags(name, flags);
+

	/* silently ignore duplicates in case of shlibs */
	tll_foreach(pkg->shlibs_provided, s) {
-
		if (STREQ(s->item, name))
+
		if (STREQ(s->item, full_name)) {
+
			free(full_name);
			return (EPKG_OK);
+
		}
	}

-
	tll_push_back(pkg->shlibs_provided, xstrdup(name));
+
	tll_push_back(pkg->shlibs_provided, full_name);

-
	dbg(3, "added shlib provide %s for %s", name, pkg->name);
+
	dbg(3, "added shlib provide %s for %s", full_name, pkg->name);

	return (EPKG_OK);
}
modified libpkg/pkg_abi_macho.c
@@ -381,9 +381,9 @@ analyse_macho(int fd, struct pkg *pkg)
				xasprintf(&lib_with_version, "%s-%"PRIuFAST16".%"PRIuFAST16, basename, dylib->current_version.major, dylib->current_version.minor);
			}
			if (LC_ID_DYLIB == loadcmd) {
-
				pkg_addshlib_provided(pkg, lib_with_version);
+
				pkg_addshlib_provided(pkg, lib_with_version, PKG_SHLIB_FLAGS_NONE);
			} else {
-
				pkg_addshlib_required(pkg, lib_with_version);
+
				pkg_addshlib_required(pkg, lib_with_version, PKG_SHLIB_FLAGS_NONE);
			}
			free(lib_with_version);
			free(dylib);
modified libpkg/pkg_elf.c
@@ -58,26 +58,7 @@
#define roundup2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
#endif

-
static enum pkg_arch elf_parse_arch(Elf *elf, GElf_Ehdr *ehdr);
-

-
static bool
-
is_old_freebsd_armheader(const GElf_Ehdr *e)
-
{
-
	GElf_Word eabi;
-

-
	/*
-
	 * Old FreeBSD arm EABI binaries were created with zeroes in [EI_OSABI].
-
	 * Attempt to identify them by the little bit of valid info that is
-
	 * present:  32-bit ARM with EABI version 4 or 5 in the flags.  OABI
-
	 * binaries (prior to freebsd 10) have the correct [EI_OSABI] value.
-
	 */
-
	if (e->e_machine == EM_ARM && e->e_ident[EI_CLASS] == ELFCLASS32) {
-
		eabi = e->e_flags & 0xff000000;
-
		if (eabi == 0x04000000 || eabi == 0x05000000)
-
			return (true);
-
	}
-
	return (false);
-
}
+
static void elf_parse_abi(Elf *elf, GElf_Ehdr *ehdr, struct pkg_abi *abi);

#ifndef HAVE_ELF_NOTE
typedef Elf32_Nhdr Elf_Note;
@@ -140,9 +121,8 @@ analyse_elf(struct pkg *pkg, const char *fpath)
		goto cleanup;
	}

-
	/* Elf file has sections header */
+
	/* Parse the needed information from the dynamic section header */
	Elf_Scn *scn = NULL;
-
	Elf_Scn *note = NULL;
	Elf_Scn *dynamic = NULL;
	size_t numdyn = 0;
	size_t sh_link = 0;
@@ -154,20 +134,7 @@ analyse_elf(struct pkg *pkg, const char *fpath)
					elf_errmsg(-1));
			goto cleanup;
		}
-
		switch (shdr.sh_type) {
-
		case SHT_NOTE:;
-
			Elf_Data *data = elf_getdata(scn, NULL);
-
			if (data == NULL) {
-
				ret = EPKG_END; /* Some error occurred, ignore this file */
-
				goto cleanup;
-
			}
-
			if (data->d_buf != NULL) {
-
				Elf_Note *en = (Elf_Note *)data->d_buf;
-
				if (en->n_type == NT_ABI_TAG)
-
					note = scn;
-
			}
-
			break;
-
		case SHT_DYNAMIC:
+
		if (shdr.sh_type == SHT_DYNAMIC) {
			dynamic = scn;
			sh_link = shdr.sh_link;
			if (shdr.sh_entsize == 0) {
@@ -177,29 +144,30 @@ analyse_elf(struct pkg *pkg, const char *fpath)
			numdyn = shdr.sh_size / shdr.sh_entsize;
			break;
		}
-

-
		if (note != NULL && dynamic != NULL)
-
			break;
	}

-
	/*
-
	 * note == NULL usually means a shared object for use with dlopen(3)
-
	 * dynamic == NULL means not a dynamically linked elf
-
	 */
	if (dynamic == NULL) {
		ret = EPKG_END;
		goto cleanup; /* not a dynamically linked elf: no results */
	}

-
	if (elf_parse_arch(e, &elfhdr) != ctx.abi.arch) {
+
	/* A shared object for use with dlopen(3) may lack a NOTE section and
+
           will therefore have unknown elf_abi.os. */
+
	struct pkg_abi elf_abi;
+
	elf_parse_abi(e, &elfhdr, &elf_abi);
+
	if (elf_abi.os == PKG_OS_UNKNOWN || elf_abi.arch == PKG_ARCH_UNKNOWN) {
		ret = EPKG_END;
-
		goto cleanup; /* Invalid ABI */
+
		goto cleanup;
	}

-
	if (ctx.abi.os == PKG_OS_FREEBSD && elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD &&
-
	    !is_old_freebsd_armheader(&elfhdr)) {
+
	enum pkg_shlib_flags flags = pkg_shlib_flags_from_abi(&elf_abi);
+
	if ((flags & PKG_SHLIB_FLAGS_COMPAT_LINUX) == 0 && elf_abi.os != ctx.abi.os) {
		ret = EPKG_END;
-
		goto cleanup;
+
		goto cleanup; /* Incompatible OS */
+
	}
+
	if ((flags & PKG_SHLIB_FLAGS_COMPAT_32) == 0 && elf_abi.arch != ctx.abi.arch) {
+
		ret = EPKG_END;
+
		goto cleanup; /* Incompatible architecture */
	}

	Elf_Data *data = elf_getdata(dynamic, NULL);
@@ -222,10 +190,12 @@ analyse_elf(struct pkg *pkg, const char *fpath)
			continue;
		}

+

+

		if (dyn->d_tag == DT_SONAME) {
-
			pkg_addshlib_provided(pkg, shlib);
+
			pkg_addshlib_provided(pkg, shlib, flags);
		} else if (dyn->d_tag == DT_NEEDED) {
-
			pkg_addshlib_required(pkg, shlib);
+
			pkg_addshlib_required(pkg, shlib, flags);
		}
	}

modified libpkg/pkg_manifest.c
@@ -427,13 +427,13 @@ pkg_array(struct pkg *pkg, const ucl_object_t *obj, uint32_t attr)
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed required shared library");
			else
-
				pkg_addshlib_required(pkg, ucl_object_tostring(cur));
+
				pkg_addshlib_required(pkg, ucl_object_tostring(cur), PKG_SHLIB_FLAGS_NONE);
			break;
		case MANIFEST_SHLIBS_PROVIDED:
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed provided shared library");
			else
-
				pkg_addshlib_provided(pkg, ucl_object_tostring(cur));
+
				pkg_addshlib_provided(pkg, ucl_object_tostring(cur), PKG_SHLIB_FLAGS_NONE);
			break;
		case MANIFEST_CONFLICTS:
			if (cur->type != UCL_STRING)
modified libpkg/pkgdb_iterator.c
@@ -586,6 +586,13 @@ pkgdb_load_group(sqlite3 *sqlite, struct pkg *pkg)
}

static int
+
addshlib_required_raw(struct pkg *pkg, const char *name)
+
{
+
	tll_push_back(pkg->shlibs_required, xstrdup(name));
+
	return (EPKG_OK);
+
}
+

+
static int
pkgdb_load_shlib_required(sqlite3 *sqlite, struct pkg *pkg)
{
	const char	sql[] = ""
@@ -598,9 +605,15 @@ pkgdb_load_shlib_required(sqlite3 *sqlite, struct pkg *pkg)
	assert(pkg != NULL);

	return (load_val(sqlite, pkg, sql, PKG_LOAD_SHLIBS_REQUIRED,
-
	    pkg_addshlib_required, PKG_ATTR_SHLIBS_REQUIRED));
+
	    addshlib_required_raw, PKG_ATTR_SHLIBS_REQUIRED));
}

+
static int
+
addshlib_provided_raw(struct pkg *pkg, const char *name)
+
{
+
	tll_push_back(pkg->shlibs_provided, xstrdup(name));
+
	return (EPKG_OK);
+
}

static int
pkgdb_load_shlib_provided(sqlite3 *sqlite, struct pkg *pkg)
@@ -615,7 +628,7 @@ pkgdb_load_shlib_provided(sqlite3 *sqlite, struct pkg *pkg)
	assert(pkg != NULL);

	return (load_val(sqlite, pkg, sql, PKG_LOAD_SHLIBS_PROVIDED,
-
	    pkg_addshlib_provided, PKG_SHLIBS_PROVIDED));
+
	    addshlib_provided_raw, PKG_SHLIBS_PROVIDED));
}

static int
modified libpkg/private/pkg.h
@@ -792,8 +792,19 @@ int pkg_kv_add(kvlist_t *kv, const char *key, const char *value, const char *tit
const char *pkg_kv_get(const kvlist_t *kv, const char *key);
int pkg_adduser(struct pkg *pkg, const char *name);
int pkg_addgroup(struct pkg *pkg, const char *group);
-
int pkg_addshlib_required(struct pkg *pkg, const char *name);
-
int pkg_addshlib_provided(struct pkg *pkg, const char *name);
+

+
enum pkg_shlib_flags {
+
	PKG_SHLIB_FLAGS_NONE = 0,
+
	PKG_SHLIB_FLAGS_COMPAT_32 = 1 << 0,
+
	PKG_SHLIB_FLAGS_COMPAT_LINUX = 1 << 1,
+
};
+
/* Determine shlib flags by comparing the shlib abi with ctx.abi */
+
enum pkg_shlib_flags pkg_shlib_flags_from_abi(const struct pkg_abi *shlib_abi);
+
int pkg_addshlib_required(struct pkg *pkg, const char *name, enum pkg_shlib_flags);
+
/* No checking for duplicates or filtering */
+
int pkg_addshlib_required_raw(struct pkg *pkg, const char *name);
+
int pkg_addshlib_provided(struct pkg *pkg, const char *name, enum pkg_shlib_flags);
+

int pkg_addconflict(struct pkg *pkg, const char *name);
int pkg_addprovide(struct pkg *pkg, const char *name);
int pkg_addrequire(struct pkg *pkg, const char *name);
modified tests/frontend/test_environment.sh.in
@@ -111,9 +111,7 @@ bin_meta() {
			XABI=FreeBSD:14:riscv64
			XALTABI=freebsd:14:riscv:64:hf
			XFreeBSD_version=1401000
-
# This riscv64 binary does not have the OS set to FreeBSD in its ELF header
-
# TODO: handle this in pkg_elf.c
-
#			Xshlibs_required="libc.so.7"
+
			Xshlibs_required="libc.so.7"
			;;
		*dfly.bin)
			XABI=dragonfly:5.10:x86:64
modified tests/lib/pkg_elf.c
@@ -49,6 +49,7 @@ ATF_TC_BODY(analyse_elf, tc)
	struct pkg *p = NULL;
	char *binpath = NULL;

+
	ctx.abi.os = PKG_OS_FREEBSD;
	ctx.abi.arch = PKG_ARCH_AMD64;

	xasprintf(&binpath, "%s/frontend/libtestfbsd.so.1", atf_tc_get_config_var(tc, "srcdir"));