-/* $OpenBSD: library.c,v 1.89 2022/12/04 15:42:07 deraadt Exp $ */
+/* $OpenBSD: library.c,v 1.90 2023/01/29 20:30:56 gnezdo Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
elf_object_t *
_dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
{
- struct mutate imut[MAXMUT], mut[MAXMUT];
+ struct range_vector imut, mut;
int libfile, i;
struct load_list *next_load, *load_list = NULL;
Elf_Addr maxva = 0, minva = ELF_NO_ADDR;
phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
/* Entire mapping can become immutable, minus exceptions chosen later */
- _dl_defer_immut(imut, loff, maxva - minva);
+ _dl_push_range_size(&imut, loff, maxva - minva);
for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
switch (phdp->p_type) {
case PT_GNU_RELRO:
relro_addr = phdp->p_vaddr + loff;
relro_size = phdp->p_memsz;
- _dl_defer_mut(mut, phdp->p_vaddr + loff, phdp->p_memsz);
+ _dl_push_range_size(&mut, relro_addr, relro_size);
break;
case PT_OPENBSD_MUTABLE:
- _dl_defer_mut(mut, phdp->p_vaddr + loff, phdp->p_memsz);
+ _dl_push_range_size(&mut, phdp->p_vaddr + loff,
+ phdp->p_memsz);
break;
default:
_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);
+ _dl_bcopy(&mut, &object->mut, sizeof mut);
+ _dl_bcopy(&imut, &object->imut, sizeof imut);
} else {
_dl_munmap((void *)libaddr, maxva - minva);
_dl_load_list_free(load_list);
-/* $OpenBSD: library_mquery.c,v 1.69 2022/12/04 15:42:07 deraadt Exp $ */
+/* $OpenBSD: library_mquery.c,v 1.70 2023/01/29 20:30:56 gnezdo Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
elf_object_t *
_dl_tryload_shlib(const char *libname, int type, int flags, int nodelete)
{
- struct mutate imut[MAXMUT], mut[MAXMUT];
+ struct range_vector imut, mut;
int libfile, i;
struct load_list *ld, *lowld = NULL;
elf_object_t *object;
}
/* Entire mapping can become immutable, minus exceptions chosen later */
- _dl_defer_immut(imut, LOFF + ld->moff, ROUND_PG(ld->size));
+ _dl_push_range_size(&imut, LOFF + ld->moff, ROUND_PG(ld->size));
ld->start = res;
}
case PT_GNU_RELRO:
relro_addr = phdp->p_vaddr + LOFF;
relro_size = phdp->p_memsz;
- _dl_defer_mut(mut, phdp->p_vaddr + LOFF, phdp->p_memsz);
+ _dl_push_range_size(&mut, relro_addr, relro_size);
break;
case PT_OPENBSD_MUTABLE:
- _dl_defer_mut(mut, phdp->p_vaddr + LOFF, phdp->p_memsz);
+ _dl_push_range_size(&mut, phdp->p_vaddr + LOFF,
+ phdp->p_memsz);
break;
}
}
_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);
+ _dl_bcopy(&mut, &object->mut, sizeof mut);
+ _dl_bcopy(&imut, &object->imut, sizeof imut);
} else {
_dl_load_list_free(lowld);
}
-/* $OpenBSD: loader.c,v 1.209 2022/12/25 09:39:37 visa Exp $ */
+/* $OpenBSD: loader.c,v 1.210 2023/01/29 20:30:56 gnezdo Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
}
void
-_dl_defer_immut(struct mutate *m, vaddr_t start, vsize_t len)
+_dl_push_range(struct range_vector *v, vaddr_t s, vaddr_t e)
{
- int i;
+ int i = v->count;
- for (i = 0; i < MAXMUT; i++) {
- if (m[i].valid == 0) {
- m[i].start = start;
- m[i].end = start + len;
- m[i].valid = 1;
- return;
- }
+ if (i == nitems(v->slice)) {
+ _dl_die("too many ranges");
+ }
+ /* Skips the empty ranges (s == e). */
+ if (s < e) {
+ v->slice[i].start = s;
+ v->slice[i].end = e;
+ v->count++;
+ } else if (s > e) {
+ _dl_die("invalid range");
}
- if (i == MAXMUT)
- _dl_die("too many _dl_defer_immut");
}
void
-_dl_defer_mut(struct mutate *m, vaddr_t start, size_t len)
+_dl_push_range_size(struct range_vector *v, vaddr_t s, vsize_t size)
{
- int i;
-
- for (i = 0; i < MAXMUT; i++) {
- if (m[i].valid == 0) {
- m[i].start = start;
- m[i].end = start + len;
- m[i].valid = 1;
- return;
- }
- }
- if (i == MAXMUT)
- _dl_die("too many _dl_defer_mut");
+ _dl_push_range(v, s, s + size);
}
+/*
+ * Finds the truly immutable ranges by taking mutable ones out. Implements
+ * interval difference of imut and mut. Interval splitting necessitates
+ * intermediate storage and complex double buffering.
+ */
void
_dl_apply_immutable(elf_object_t *object)
{
- struct mutate *m, *im, *imtail;
- int mut, imut;
-
+ struct range_vector acc[2]; /* flips out to avoid copying */
+ struct addr_range *m, *im;
+ int i, j, imut, in, out;
+
if (object->obj_type != OBJTYPE_LIB)
return;
- imtail = &object->imut[MAXMUT - 1];
-
- for (imut = 0; imut < MAXMUT; imut++) {
- im = &object->imut[imut];
- if (im->valid == 0)
- continue;
-
- for (mut = 0; mut < MAXMUT; mut++) {
- m = &object->mut[mut];
- if (m->valid == 0)
- continue;
- if (m->start <= im->start) {
- if (m->end < im->start) {
+ for (imut = 0; imut < object->imut.count; imut++) {
+ im = &object->imut.slice[imut];
+ out = 0;
+ acc[out].count = 0;
+ _dl_push_range(&acc[out], im->start, im->end);
+
+ for (i = 0; i < object->mut.count; i++) {
+ m = &object->mut.slice[i];
+ in = out;
+ out = 1 - in;
+ acc[out].count = 0;
+ for (j = 0; j < acc[in].count; j++) {
+ const vaddr_t ms = m->start, me = m->end;
+ const vaddr_t is = acc[in].slice[j].start,
+ ie = acc[in].slice[j].end;
+ if (ie <= ms || me <= is) {
+ /* is .. ie .. ms .. me -> is .. ie */
+ /* ms .. me .. is .. ie -> is .. ie */
+ _dl_push_range(&acc[out], is, ie);
+ } else if (ms <= is && ie <= me) {
+ /* PROVIDED: ms < ie && is < me */
+ /* ms .. is .. ie .. me -> [] */
;
- } else if (m->end >= im->end) {
- im->start = im->end = im->valid = 0;
+ } else if (ie <= me) {
+ /* is .. ms .. ie .. me -> is .. ms */
+ _dl_push_range(&acc[out], is, ms);
+ } else if (is < ms) {
+ /* is .. ms .. me .. ie -> is .. ms */
+ _dl_push_range(&acc[out], is, ms);
+ _dl_push_range(&acc[out], me, ie);
} else {
- im->start = m->end;
- }
- } else if (m->start > im->start) {
- if (m->end > im->end) {
- ;
- } else if (m->end == im->end) {
- im->end = m->start;
- } else if (m->end < im->end) {
- imtail->start = im->start;
- imtail->end = m->start;
- imtail->valid = 1;
- imtail--;
- imtail->start = m->end;
- imtail->end = im->end;
- imtail->valid = 1;
- imtail--;
- im->start = im->end = im->valid = 0;
+ /* ms .. is .. me .. ie -> me .. ie */
+ _dl_push_range(&acc[out], me, ie);
}
}
}
- }
- /* and now, install immutability for objects */
- for (imut = 0; imut < MAXMUT; imut++) {
- im = &object->imut[imut];
- if (im->valid == 0)
- continue;
- _dl_mimmutable((void *)im->start, im->end - im->start);
+ /* and now, install immutability for objects */
+ for (i = 0; i < acc[out].count; i++) {
+ const struct addr_range *ar = &acc[out].slice[i];
+ _dl_mimmutable((void *)ar->start, ar->end - ar->start);
+ }
+
}
+
}
-/* $OpenBSD: resolve.h,v 1.103 2022/12/04 15:42:07 deraadt Exp $ */
+/* $OpenBSD: resolve.h,v 1.104 2023/01/29 20:30:56 gnezdo Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
};
void object_vec_grow(struct object_vector *_vec, int _more);
-struct mutate {
+struct addr_range {
vaddr_t start;
vaddr_t end;
- int valid;
+};
+
+struct range_vector {
+ struct addr_range slice[40];
+ int count;
};
/*
/* nonzero if trace enabled for this object */
int traced;
-#define MAXMUT 40
- struct mutate imut[MAXMUT];
- struct mutate mut[MAXMUT];
+ struct range_vector imut;
+ struct range_vector mut;
};
struct dep_node {
void _dl_load_list_free(struct load_list *load_list);
void _dl_find_immutables(int type, elf_object_t *object, Elf_Ehdr *);
-void _dl_defer_mut(struct mutate *m, vaddr_t start, vsize_t len);
-void _dl_defer_immut(struct mutate *m, vaddr_t start, vsize_t len);
+void _dl_push_range_size(struct range_vector *v, vaddr_t start, vsize_t len);
void _dl_apply_immutable(elf_object_t *object);
typedef void lock_cb(int);