summaryrefslogtreecommitdiff
path: root/libexec/ld.so/resolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/ld.so/resolve.c')
-rw-r--r--libexec/ld.so/resolve.c84
1 files changed, 83 insertions, 1 deletions
diff --git a/libexec/ld.so/resolve.c b/libexec/ld.so/resolve.c
index 1916341158c..b6e21f9d005 100644
--- a/libexec/ld.so/resolve.c
+++ b/libexec/ld.so/resolve.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: resolve.c,v 1.100 2023/07/08 14:09:43 jasper Exp $ */
+/* $OpenBSD: resolve.c,v 1.101 2024/01/16 19:07:31 deraadt Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -29,6 +29,8 @@
#define _DYN_LOADER
#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
#include <limits.h>
#include <link.h>
@@ -36,6 +38,7 @@
#include "util.h"
#include "path.h"
#include "resolve.h"
+#include "syscall.h"
/* substitution types */
typedef enum {
@@ -745,3 +748,82 @@ _dl_debug_state(void)
{
/* Debugger stub */
}
+
+/*
+ * Search for DT_SONAME, and check if this is libc
+ */
+int
+_dl_islibc(Elf_Dyn *_dynp, Elf_Addr loff)
+{
+ Elf_Dyn *d, *dynp = (Elf_Dyn *)((unsigned long)_dynp + loff);
+ long base = 0;
+
+ for (d = dynp; d->d_tag != DT_NULL; d++)
+ if (d->d_tag == DT_STRTAB) {
+ base = d->d_un.d_ptr + loff;
+ break;
+ }
+ if (base == 0)
+ return 0;
+ for (d = dynp; d->d_tag != DT_NULL; d++)
+ if (d->d_tag == DT_SONAME) {
+ if (_dl_strncmp((char *)(base + d->d_un.d_ptr),
+ "libc.so.", 8) == 0)
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+void
+_dl_pin(int file, Elf_Phdr *phdp, void *base, size_t len,
+ void *exec_base, size_t exec_size)
+{
+ struct pinsyscalls {
+ u_int offset;
+ u_int sysno;
+ } *syscalls;
+ int npins = 0, nsyscalls, i;
+ u_int *pins = NULL;
+ vaddr_t offset;
+
+ if (phdp->p_filesz > SYS_MAXSYSCALL * 2 * sizeof(*syscalls) ||
+ phdp->p_filesz % sizeof(*syscalls) != 0 ||
+ phdp->p_offset & 0x3)
+ return;
+ syscalls = _dl_mmap(NULL, phdp->p_filesz, PROT_READ,
+ MAP_PRIVATE|MAP_FILE, file, phdp->p_offset);
+ if (syscalls == MAP_FAILED)
+ return;
+
+ /* Validate, and calculate pintable size */
+ nsyscalls = phdp->p_filesz / sizeof(*syscalls);
+ for (i = 0; i < nsyscalls; i++) {
+ if (syscalls[i].sysno < 0 ||
+ syscalls[i].sysno >= SYS_MAXSYSCALL ||
+ syscalls[i].offset >= len)
+ goto bad;
+ npins = MAXIMUM(npins, syscalls[i].sysno);
+ }
+ npins++;
+
+ /*
+ * Fill pintable: 0 = invalid, -1 = accept, else offset
+ * from base, rebase to text_start while at it
+ */
+ pins = _dl_calloc(npins, sizeof(u_int));
+ offset = exec_base - base;
+ for (i = 0; i < nsyscalls; i++) {
+ if (pins[syscalls[i].sysno])
+ pins[syscalls[i].sysno] = (u_int)-1; /* duplicated */
+ else
+ pins[syscalls[i].sysno] = syscalls[i].offset - offset;
+ }
+ base += offset;
+ len = len - offset;
+bad:
+ _dl_munmap(syscalls, phdp->p_filesz);
+ if (pins)
+ _dl_pinsyscalls(base, len, pins, npins);
+ _dl_free(pins);
+}