summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2024-01-16 19:07:32 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2024-01-16 19:07:32 +0000
commit75e0eea99f954e8d285f99fe99040d9bd3dd1d29 (patch)
treee467e75d58b3cc1334c4928cbb4bcb03692042f4
parent299830858df6b28127f1fa05a7edec8a98165ca5 (diff)
Read PT_OPENBSD_SYSCALLS in libc.so, and convert it to a table for
pinsyscalls(2). ok kettenis
-rw-r--r--libexec/ld.so/library.c39
-rw-r--r--libexec/ld.so/library_mquery.c38
-rw-r--r--libexec/ld.so/loader.c9
-rw-r--r--libexec/ld.so/resolve.c84
-rw-r--r--libexec/ld.so/resolve.h6
5 files changed, 142 insertions, 34 deletions
diff --git a/libexec/ld.so/library.c b/libexec/ld.so/library.c
index b203d4fcef7..bfff01fe5ba 100644
--- a/libexec/ld.so/library.c
+++ b/libexec/ld.so/library.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: library.c,v 1.93 2023/12/19 16:13:22 deraadt Exp $ */
+/* $OpenBSD: library.c,v 1.94 2024/01/16 19:07:31 deraadt Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -99,7 +99,7 @@ elf_object_t *
_dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
{
struct range_vector imut, mut;
- int libfile, i;
+ int libfile, libc = -1, i;
struct load_list *next_load, *load_list = NULL;
Elf_Addr maxva = 0, minva = ELF_NO_ADDR;
Elf_Addr libaddr, loff, align = _dl_pagesz - 1;
@@ -109,8 +109,8 @@ _dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
size_t exec_size = 0;
Elf_Dyn *dynp = NULL;
Elf_Ehdr *ehdr;
- Elf_Phdr *phdp;
- Elf_Phdr *ptls = NULL;
+ Elf_Phdr *phdp, *ptls = NULL;
+ Elf_Phdr *syscall_phdp = NULL;
struct stat sb;
#define powerof2(x) ((((x) - 1) & (x)) == 0)
@@ -139,7 +139,6 @@ _dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
if (flags & DF_1_NOOPEN) {
_dl_close(libfile);
return NULL;
-
}
_dl_read(libfile, hbuf, sizeof(hbuf));
@@ -316,11 +315,30 @@ _dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
_dl_push_range_size(&mut, phdp->p_vaddr + loff,
phdp->p_memsz);
break;
+ case PT_OPENBSD_SYSCALLS:
+ syscall_phdp = phdp;
+ break;
default:
break;
}
}
+ libc = _dl_islibc(dynp, loff);
+ if (libc) {
+ if (syscall_phdp)
+ _dl_pin(libfile, syscall_phdp, (void *)libaddr,
+ (size_t)((exec_start + exec_size) - libaddr),
+ exec_start, exec_size);
+
+ /*
+ * XXX msyscall() can be removed once pinsyscalls()
+ * is fully operational
+ */
+ /* Request permission for system calls in libc.so's text segment */
+ if (_dl_msyscall(exec_start, exec_size) == -1)
+ _dl_printf("msyscall %lx %lx error\n",
+ exec_start, exec_size);
+ }
_dl_close(libfile);
dynp = (Elf_Dyn *)((unsigned long)dynp + loff);
@@ -328,8 +346,6 @@ _dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
(Elf_Phdr *)((char *)libaddr + ehdr->e_phoff), ehdr->e_phnum,type,
libaddr, loff);
if (object) {
- char *soname = (char *)object->Dyn.info[DT_SONAME];
-
object->load_size = maxva - minva; /*XXX*/
object->load_list = load_list;
/* set inode, dev from stat info */
@@ -339,17 +355,10 @@ _dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
object->nodelete = nodelete;
object->relro_addr = relro_addr;
object->relro_size = relro_size;
+ object->islibc = libc;
_dl_set_sod(object->load_name, &object->sod);
if (ptls != NULL && ptls->p_memsz)
_dl_set_tls(object, ptls, libaddr, libname);
-
- /* Request permission for system calls in libc.so's text segment */
- if (soname != NULL && !_dl_traceld &&
- _dl_strncmp(soname, "libc.so.", 8) == 0) {
- if (_dl_msyscall(exec_start, exec_size) == -1)
- _dl_printf("msyscall %lx %lx error\n",
- exec_start, exec_size);
- }
_dl_bcopy(&mut, &object->mut, sizeof mut);
_dl_bcopy(&imut, &object->imut, sizeof imut);
} else {
diff --git a/libexec/ld.so/library_mquery.c b/libexec/ld.so/library_mquery.c
index 74070a86a5f..7e85a5c0f96 100644
--- a/libexec/ld.so/library_mquery.c
+++ b/libexec/ld.so/library_mquery.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: library_mquery.c,v 1.73 2023/12/19 16:13:22 deraadt Exp $ */
+/* $OpenBSD: library_mquery.c,v 1.74 2024/01/16 19:07:31 deraadt Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -102,15 +102,15 @@ elf_object_t *
_dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
{
struct range_vector imut, mut;
- int libfile, i;
+ int libfile, libc = -1, i;
struct load_list *ld, *lowld = NULL;
elf_object_t *object;
Elf_Dyn *dynp = NULL;
Elf_Ehdr *ehdr;
- Elf_Phdr *phdp;
+ Elf_Phdr *phdp, *ptls = NULL;
+ Elf_Phdr *syscall_phdp = NULL;
Elf_Addr load_end = 0;
Elf_Addr align = _dl_pagesz - 1, off, size;
- Elf_Phdr *ptls = NULL;
Elf_Addr relro_addr = 0, relro_size = 0;
struct stat sb;
char hbuf[4096], *exec_start;
@@ -325,9 +325,28 @@ retry:
_dl_push_range_size(&mut, phdp->p_vaddr + LOFF,
phdp->p_memsz);
break;
+ case PT_OPENBSD_SYSCALLS:
+ syscall_phdp = phdp;
+ break;
}
}
+ libc = _dl_islibc(dynp, LOFF);
+ if (libc) {
+ if (syscall_phdp)
+ _dl_pin(libfile, syscall_phdp, lowld->start,
+ (size_t)((exec_start + exec_size) - LOFF),
+ exec_start, exec_size);
+
+ /*
+ * XXX msyscall() can be removed once pinsyscalls()
+ * is fully operational
+ */
+ /* Request permission for system calls in libc.so's text segment */
+ if (_dl_msyscall(exec_start, exec_size) == -1)
+ _dl_printf("msyscall %lx %lx error\n",
+ exec_start, exec_size);
+ }
_dl_close(libfile);
dynp = (Elf_Dyn *)((unsigned long)dynp + LOFF);
@@ -335,8 +354,6 @@ retry:
(Elf_Phdr *)((char *)lowld->start + ehdr->e_phoff), ehdr->e_phnum,
type, (Elf_Addr)lowld->start, LOFF);
if (object) {
- char *soname = (char *)object->Dyn.info[DT_SONAME];
-
object->load_size = (Elf_Addr)load_end - (Elf_Addr)lowld->start;
object->load_list = lowld;
/* set inode, dev from stat info */
@@ -346,18 +363,11 @@ retry:
object->nodelete = nodelete;
object->relro_addr = relro_addr;
object->relro_size = relro_size;
+ object->islibc = libc;
_dl_set_sod(object->load_name, &object->sod);
if (ptls != NULL && ptls->p_memsz)
_dl_set_tls(object, ptls, (Elf_Addr)lowld->start,
libname);
-
- /* Request permission for system calls in libc.so's text segment */
- if (soname != NULL && !_dl_traceld &&
- _dl_strncmp(soname, "libc.so.", 8) == 0) {
- if (_dl_msyscall(exec_start, exec_size) == -1)
- _dl_printf("msyscall %lx %lx error\n",
- exec_start, exec_size);
- }
_dl_bcopy(&mut, &object->mut, sizeof mut);
_dl_bcopy(&imut, &object->imut, sizeof imut);
} else {
diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c
index de53dc85d58..07cd0d8e107 100644
--- a/libexec/ld.so/loader.c
+++ b/libexec/ld.so/loader.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: loader.c,v 1.219 2024/01/14 09:39:03 kettenis Exp $ */
+/* $OpenBSD: loader.c,v 1.220 2024/01/16 19:07:31 deraadt Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -440,11 +440,14 @@ _dl_load_dep_libs(elf_object_t *object, int flags, int booting)
_dl_cache_grpsym_list_setup(object);
+ /*
+ * XXX pinsyscall(SYS_execve,...) can be removed once pinsyscalls()
+ * is fully operational
+ */
for (obj = _dl_objects; booting && obj != NULL; obj = obj->next) {
- char *soname = (char *)obj->Dyn.info[DT_SONAME];
struct sym_res sr;
- if (!soname || _dl_strncmp(soname, "libc.so.", 8))
+ if (!obj->islibc)
continue;
sr = _dl_find_symbol("execve",
SYM_SEARCH_SELF|SYM_PLT|SYM_WARNNOTFOUND, NULL, obj);
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);
+}
diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h
index 8f3411dcfd1..0b3278e6f7a 100644
--- a/libexec/ld.so/resolve.h
+++ b/libexec/ld.so/resolve.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: resolve.h,v 1.106 2023/12/19 16:13:22 deraadt Exp $ */
+/* $OpenBSD: resolve.h,v 1.107 2024/01/16 19:07:31 deraadt Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -245,6 +245,7 @@ struct elf_object {
struct range_vector imut;
struct range_vector mut;
+ int islibc;
};
struct dep_node {
@@ -340,6 +341,9 @@ typedef void lock_cb(int);
void _dl_thread_kern_go(lock_cb *);
lock_cb *_dl_thread_kern_stop(void);
+int _dl_islibc(Elf_Dyn *_dynp, Elf_Addr loff);
+void _dl_pin(int, Elf_Phdr *, void *, size_t, void *, size_t);
+
char *_dl_getenv(const char *, char **) __boot;
void _dl_unsetenv(const char *, char **) __boot;