summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2002-12-18 19:20:03 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2002-12-18 19:20:03 +0000
commit8f09080005732280987e9c3a5d4dfb4b7ff1d0ff (patch)
tree40b3f487a7bc16dc52413c5ce00772fd5430b427
parent90f6776918c0b71f3eac3550935610833e3ed1ef (diff)
Prepare for an upcoming ELF executable change. This will allow ld.so to
protect the GOT and PLT sections of the executable from being overwritten. This behavior is enabled by changes in the executable/shared object layout, and does not occur without the ld changes.
-rw-r--r--libexec/ld.so/alpha/ldasm.S15
-rw-r--r--libexec/ld.so/alpha/rtld_machine.c57
-rw-r--r--libexec/ld.so/alpha/syscall.h4
-rw-r--r--libexec/ld.so/i386/ldasm.S27
-rw-r--r--libexec/ld.so/i386/rtld_machine.c56
-rw-r--r--libexec/ld.so/i386/syscall.h4
-rw-r--r--libexec/ld.so/mips/rtld_machine.c39
-rw-r--r--libexec/ld.so/powerpc/rtld_machine.c54
-rw-r--r--libexec/ld.so/powerpc/syscall.h28
-rw-r--r--libexec/ld.so/resolve.h6
-rw-r--r--libexec/ld.so/sparc/ldasm.S20
-rw-r--r--libexec/ld.so/sparc/rtld_machine.c65
-rw-r--r--libexec/ld.so/sparc/syscall.h4
-rw-r--r--libexec/ld.so/sparc64/ldasm.S20
-rw-r--r--libexec/ld.so/sparc64/rtld_machine.c56
-rw-r--r--libexec/ld.so/sparc64/syscall.h4
16 files changed, 443 insertions, 16 deletions
diff --git a/libexec/ld.so/alpha/ldasm.S b/libexec/ld.so/alpha/ldasm.S
index 68659b6e05e..c6917ff2e26 100644
--- a/libexec/ld.so/alpha/ldasm.S
+++ b/libexec/ld.so/alpha/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.10 2002/10/21 16:01:55 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.11 2002/12/18 19:20:01 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -290,3 +290,16 @@ LEAF_NOPROFILE(_dl_getdirentries, 4)
call_pal PAL_OSF1_callsys
RET
END(_dl_getdirentries)
+
+/* _dl_sigprocmask does not support NULL new mask */
+LEAF_NOPROFILE(_dl_sigprocmask, 4)
+ mov a2, a5
+ ldl a1, 0(a1) /* load the set from *set */
+ ldiq v0, SYS_sigprocmask
+ call_pal PAL_OSF1_callsys
+ /* What about syscalls failing? */
+ beq a5, 1f
+ stl v0, 0(a5)
+1: mov zero, v0
+ RET
+END(_dl_sigprocmask)
diff --git a/libexec/ld.so/alpha/rtld_machine.c b/libexec/ld.so/alpha/rtld_machine.c
index 0c10637104d..cde1b9e0b5a 100644
--- a/libexec/ld.so/alpha/rtld_machine.c
+++ b/libexec/ld.so/alpha/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.17 2002/11/14 15:15:54 drahn Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.18 2002/12/18 19:20:01 drahn Exp $ */
/*
* Copyright (c) 1999 Dale Rahn
@@ -44,6 +44,7 @@
#include <nlist.h>
#include <link.h>
+#include <signal.h>
#include "syscall.h"
#include "archdep.h"
@@ -189,6 +190,7 @@ _dl_bind(elf_object_t *object, Elf_Word reloff)
Elf_Addr *addr, ooff;
const Elf_Sym *sym, *this;
const char *symn;
+ sigset_t omask, nmask;
rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);
@@ -205,7 +207,23 @@ _dl_bind(elf_object_t *object, Elf_Word reloff)
_dl_printf("lazy binding failed!\n");
*((int *)0) = 0; /* XXX */
}
+ /* if PLT is protected, allow the write */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+ sigfillset(&nmask);
+ _dl_sigprocmask(SIG_BLOCK, &nmask, &omask);
+ _dl_mprotect(addr, sizeof(Elf_Addr),
+ PROT_READ|PROT_WRITE|PROT_EXEC);
+ }
+
*addr = ooff + this->st_value + rela->r_addend;
+
+ /* if PLT is (to be protected, change back to RO/X */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+ _dl_mprotect(addr, sizeof(Elf_Addr),
+ PROT_READ|PROT_EXEC);
+ _dl_sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+
return (void *)*addr;
}
@@ -217,9 +235,40 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
{
Elf_Addr *pltgot;
extern void _dl_bind_start(void); /* XXX */
+ Elf_Addr ooff;
+ const Elf_Sym *this;
+
pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
+ this = NULL;
+ ooff = _dl_find_symbol("__got_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__got_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_size = ooff + this->st_value - object->got_addr;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_size = ooff + this->st_value - object->plt_addr;
+
if (object->obj_type == OBJTYPE_LDR || !lazy || pltgot == NULL) {
_dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
return;
@@ -241,4 +290,10 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
pltgot[2] = (Elf_Addr)_dl_bind_start;
pltgot[3] = (Elf_Addr)object;
+ if (object->got_addr != NULL && object->got_size != 0)
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ|PROT_EXEC);
+ if (object->plt_addr != NULL && object->got_size != 0)
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC);
}
diff --git a/libexec/ld.so/alpha/syscall.h b/libexec/ld.so/alpha/syscall.h
index 6c65a0b9f81..11d2c9692f3 100644
--- a/libexec/ld.so/alpha/syscall.h
+++ b/libexec/ld.so/alpha/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.9 2002/07/24 04:11:10 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.10 2002/12/18 19:20:01 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -36,6 +36,7 @@
#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/signal.h>
#ifndef _dl_MAX_ERRNO
#define _dl_MAX_ERRNO 4096
@@ -57,6 +58,7 @@ int _dl_fstat(int, struct stat *);
int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
long _dl__syscall(quad_t, ...);
+int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/i386/ldasm.S b/libexec/ld.so/i386/ldasm.S
index b7af2be3792..c3ff47b5234 100644
--- a/libexec/ld.so/i386/ldasm.S
+++ b/libexec/ld.so/i386/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.2 2002/10/21 16:01:55 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.3 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -227,6 +227,31 @@ _dl_getdirentries:
ret
+ /* _dl_sigprocmask: does not handle NULL new set */
+
+ .section ".text"
+ .align 4
+ .global _dl_sigprocmask
+ .type _dl_sigprocmask,@function
+_dl_sigprocmask:
+ movl 8(%esp), %ecx
+ movl (%ecx),%ecx
+ movl %ecx,8(%esp) # to new mask arg
+ mov $SYS_sigprocmask, %eax
+ int $0x80
+ jb 1f /* error: result = -errno */
+ movl 12(%esp),%ecx # fetch old mask requested
+ testl %ecx,%ecx # test if old mask requested
+ jz 2f
+ movl %eax,(%ecx) # store old mask
+ xorl %eax,%eax
+2: ret
+
+1: /* error: result = -errno; - handled here. */
+ neg %eax
+ ret
+
+
.align 4
.global _dl_bind_start
.type _dl_bind_start,@function
diff --git a/libexec/ld.so/i386/rtld_machine.c b/libexec/ld.so/i386/rtld_machine.c
index 5495e42749b..e8ce94c1927 100644
--- a/libexec/ld.so/i386/rtld_machine.c
+++ b/libexec/ld.so/i386/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.5 2002/11/23 06:04:13 drahn Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.6 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -77,6 +77,7 @@
#include <nlist.h>
#include <link.h>
+#include <signal.h>
#include "syscall.h"
#include "archdep.h"
@@ -332,6 +333,7 @@ resolve_failed:
return (fails);
}
+#if 0
struct jmpslot {
u_short opcode;
u_short addr[2];
@@ -339,6 +341,7 @@ struct jmpslot {
#define JMPSLOT_RELOC_MASK 0xffff
};
#define JUMP 0xe990 /* NOP + JMP opcode */
+#endif
void
_dl_reloc_plt(Elf_Addr *where, Elf_Addr value)
@@ -357,6 +360,7 @@ _dl_bind(elf_object_t *object, int index)
const Elf_Sym *sym, *this;
const char *symn;
Elf_Addr ooff;
+ sigset_t omask, nmask;
rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
@@ -375,8 +379,23 @@ _dl_bind(elf_object_t *object, int index)
*((int *)0) = 0; /* XXX */
}
+ /* if GOT is protected, allow the write */
+ if (object->got_addr != NULL && object->got_size != 0) {
+ sigfillset(&nmask);
+ _dl_sigprocmask(SIG_BLOCK, &nmask, &omask);
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ|PROT_WRITE);
+ }
+
_dl_reloc_plt(addr, ooff + this->st_value);
+ /* put the GOT back to RO */
+ if (object->got_addr != NULL && object->got_size != 0) {
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ);
+ _dl_sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+
return((Elf_Addr)ooff + this->st_value);
}
@@ -388,6 +407,8 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
int i, num;
Elf_Rel *rel;
struct load_list *llist;
+ Elf_Addr ooff;
+ const Elf_Sym *this;
if (pltgot == NULL)
return; /* it is possible to have no PLT/GOT relocations */
@@ -398,6 +419,34 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
if (object->Dyn.info[DT_PLTREL] != DT_REL)
return;
+ this = NULL;
+ ooff = _dl_find_symbol("__got_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__got_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_size = ooff + this->st_value - object->got_addr;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_size = ooff + this->st_value - object->plt_addr;
+
if (!lazy) {
_dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
return;
@@ -420,4 +469,9 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
_dl_mprotect(llist->start, llist->size,
llist->prot);
}
+
+ /* PLT is already RO on i386, no point in mprotecting it, just GOT */
+ if (object->got_addr != NULL && object->got_size != 0)
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ);
}
diff --git a/libexec/ld.so/i386/syscall.h b/libexec/ld.so/i386/syscall.h
index c9719118dd1..f853ad4cb6c 100644
--- a/libexec/ld.so/i386/syscall.h
+++ b/libexec/ld.so/i386/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.1 2002/08/23 23:02:48 drahn Exp $ */
+/* $OpenBSD: syscall.h,v 1.2 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -37,6 +37,7 @@
#include <sys/syscall.h>
#include <sys/stat.h>
+#include <sys/signal.h>
#ifndef _dl_MAX_ERRNO
#define _dl_MAX_ERRNO 4096
@@ -57,6 +58,7 @@ int _dl_write(int, const char*, int);
int _dl_fstat(int, struct stat *);
int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
+int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/mips/rtld_machine.c b/libexec/ld.so/mips/rtld_machine.c
index b58e689e7fa..45467e3b9cf 100644
--- a/libexec/ld.so/mips/rtld_machine.c
+++ b/libexec/ld.so/mips/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.9 2002/11/14 15:15:54 drahn Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.10 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 1998-2002 Opsycon AB, Sweden.
@@ -129,6 +129,8 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
const Elf32_Sym *symp;
const Elf32_Sym *this;
const char *strt;
+ Elf_Addr ooff;
+ const Elf_Sym *this;
if (object->status & STAT_GOT_DONE)
return;
@@ -159,6 +161,34 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
n = object->Dyn.info[DT_MIPS_SYMTABNO - DT_LOPROC + DT_NUM] -
object->Dyn.info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
+ this = NULL;
+ ooff = _dl_find_symbol("__got_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__got_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_size = ooff + this->st_value - object->got_addr;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_size = ooff + this->st_value - object->plt_addr;
+
/*
* Then do all global references according to the ABI.
* Quickstart is not yet implemented.
@@ -195,4 +225,11 @@ DL_DEB(("got: '%s' = %x\n", strt + symp->st_name, symp->st_value));
symp++;
}
object->status |= STAT_GOT_DONE;
+
+ if (object->got_addr != NULL && object->got_size != 0)
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ);
+ if (object->plt_addr != NULL && object->plt_size != 0)
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC);
}
diff --git a/libexec/ld.so/powerpc/rtld_machine.c b/libexec/ld.so/powerpc/rtld_machine.c
index ac6cb26fa93..5e44c314f04 100644
--- a/libexec/ld.so/powerpc/rtld_machine.c
+++ b/libexec/ld.so/powerpc/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.18 2002/11/22 22:21:23 drahn Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.19 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 1999 Dale Rahn
@@ -39,6 +39,7 @@
#include <nlist.h>
#include <link.h>
+#include <signal.h>
#include "syscall.h"
#include "archdep.h"
@@ -450,10 +451,40 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
int i;
int index;
Elf32_Addr *r_addr;
+ Elf_Addr ooff;
+ const Elf_Sym *this;
if (object->Dyn.info[DT_PLTREL] != DT_RELA)
return;
+ this = NULL;
+ ooff = _dl_find_symbol("__got_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__got_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_size = ooff + this->st_value - object->got_addr;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_size = ooff + this->st_value - object->plt_addr;
+
if (!lazy) {
_dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
return;
@@ -483,6 +514,12 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
_dl_dcbf(&r_addr[0]);
_dl_dcbf(&r_addr[2]);
}
+ if (object->got_addr != NULL && object->got_size != 0)
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ|PROT_EXEC); /* only PPC is PROT_EXE */
+ if (object->plt_addr != NULL && object->plt_size != 0)
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC);
}
Elf_Addr
@@ -498,6 +535,7 @@ _dl_bind(elf_object_t *object, int reloff)
Elf32_Addr *pltcall;
Elf32_Addr *pltinfo;
Elf32_Addr *plttable;
+ sigset_t omask, nmask;
relas = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (reloff>>2);
@@ -515,6 +553,14 @@ _dl_bind(elf_object_t *object, int reloff)
*((int *)0) = 0; /* XXX */
}
+ /* if PLT is protected, allow the write */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+ sigfillset(&nmask);
+ _dl_sigprocmask(SIG_BLOCK, &nmask, &omask);
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_WRITE|PROT_EXEC);
+ }
+
value = ooff + this->st_value;
val = value - (Elf32_Addr)r_addr;
@@ -558,6 +604,12 @@ _dl_bind(elf_object_t *object, int reloff)
_dl_dcbf(&r_addr[0]);
}
+ /* if PLT is (to be protected, change back to RO/X */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC); /* only PPC is PROT_EXE */
+ _dl_sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
return (value);
}
diff --git a/libexec/ld.so/powerpc/syscall.h b/libexec/ld.so/powerpc/syscall.h
index 55bcb55b36f..92de932f7f5 100644
--- a/libexec/ld.so/powerpc/syscall.h
+++ b/libexec/ld.so/powerpc/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.13 2002/07/24 04:11:10 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.14 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -37,6 +37,7 @@
#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/signal.h>
static off_t _dl_lseek(int, off_t, int);
@@ -306,4 +307,29 @@ _dl_lseek(int fildes, off_t offset, int whence)
{
return _dl__syscall((quad_t)SYS_lseek, fildes, 0, offset, whence);
}
+
+static inline int
+_dl_sigprocmask (int how, const sigset_t *set, sigset_t *oset)
+{
+ sigset_t sig_store;
+ sigset_t sig_store1;
+ if (set != NULL) {
+ sig_store1 = *set;
+ } else {
+ sig_store1 = 0;
+ }
+
+ __asm__ volatile ("li 0,%1\n\t"
+ "mr 3,%2\n\t"
+ "mr 4,%3\n\t"
+ "sc\n\t"
+ "mr %0, 3"
+ : "=r" (sig_store)
+ : "I" (SYS_sigprocmask), "r" (how), "r" (sig_store1)
+ : "0", "3", "4");
+ if (oset != NULL)
+ *oset = sig_store;
+
+ return 0;
+}
#endif /*__DL_SYSCALL_H__*/
diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h
index 8e0060698d3..52a99e303c9 100644
--- a/libexec/ld.so/resolve.h
+++ b/libexec/ld.so/resolve.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: resolve.h,v 1.18 2002/11/14 15:15:54 drahn Exp $ */
+/* $OpenBSD: resolve.h,v 1.19 2002/12/18 19:20:01 drahn Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -61,6 +61,10 @@ typedef struct elf_object {
struct load_list *load_list;
u_int32_t load_size;
+ Elf_Addr got_addr;
+ size_t got_size;
+ Elf_Addr plt_addr;
+ size_t plt_size;
union {
u_long info[DT_NUM + DT_PROCNUM];
diff --git a/libexec/ld.so/sparc/ldasm.S b/libexec/ld.so/sparc/ldasm.S
index 9b3ff9fb81f..c7a3cf5f86c 100644
--- a/libexec/ld.so/sparc/ldasm.S
+++ b/libexec/ld.so/sparc/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.9 2002/11/23 19:50:45 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.10 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 2001 Jason L. Wright (jason@thought.net)
@@ -292,6 +292,24 @@ _dl_sysctl:
retl
sub %g0, %o0, %o0 ! error: result = -errno
+
+ /* _dl_sigprocmask does not support NULL new mask */
+ .section ".text"
+ .align 4
+ .globl _dl_sigprocmask
+ .type _dl_sigprocmask,@function
+_dl_sigprocmask:
+ ld [%o1], %o1
+ mov SYS_sigprocmask, %g1 ! call sys___sigprocmask
+ t ST_SYSCALL ! off to wonderland
+
+ cmp %o2, 0
+ bne,a 1f
+ st %o0, [%o2]
+1:
+ retl
+ clr %o0
+
/*
* V8 sparc .{,u}{mul,div,rem} replacements.
* We try to mimic them 100%. Full 64 bit sources or outputs, and
diff --git a/libexec/ld.so/sparc/rtld_machine.c b/libexec/ld.so/sparc/rtld_machine.c
index 73ccd4ffc3b..48c16f7fe98 100644
--- a/libexec/ld.so/sparc/rtld_machine.c
+++ b/libexec/ld.so/sparc/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.10 2002/11/23 19:14:25 drahn Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.11 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 1999 Dale Rahn
@@ -44,6 +44,7 @@
#include <nlist.h>
#include <link.h>
+#include <signal.h>
#include "syscall.h"
#include "archdep.h"
@@ -335,6 +336,7 @@ _dl_bind(elf_object_t *object, Elf_Word reloff)
const char *symn;
Elf_Addr value;
Elf_RelA *rela;
+ sigset_t omask, nmask;
rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);
@@ -353,8 +355,33 @@ _dl_bind(elf_object_t *object, Elf_Word reloff)
value = ooff + this->st_value;
+ /* if PLT is protected, allow the write */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+ sigfillset(&nmask);
+ _dl_sigprocmask(SIG_BLOCK, &nmask, &omask);
+#if 0
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_WRITE|PROT_EXEC);
+#else
+ _dl_mprotect((void*)addr,sizeof (Elf_Addr) * 3,
+ PROT_READ|PROT_WRITE|PROT_EXEC);
+#endif
+ }
+
_dl_reloc_plt(addr, value);
+ /* if PLT is (to be protected, change back to RO/X */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+#if 0
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC);
+#else
+ _dl_mprotect((void*)addr,sizeof (Elf_Addr) * 3,
+ PROT_READ|PROT_EXEC);
+#endif
+ _dl_sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+
return (value);
}
@@ -363,6 +390,8 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
{
Elf_Addr *pltgot;
extern void _dl_bind_start(void); /* XXX */
+ Elf_Addr ooff;
+ const Elf_Sym *this;
pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
@@ -393,11 +422,45 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
__asm __volatile("nop;nop;nop;nop;nop");
}
+ this = NULL;
+ ooff = _dl_find_symbol("__got_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__got_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_size = ooff + this->st_value - object->got_addr;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_size = ooff + this->st_value - object->plt_addr;
+
if (object->obj_type == OBJTYPE_LDR || !lazy || pltgot == NULL) {
_dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
return;
}
+ if (object->got_addr != NULL && object->got_size != 0)
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ);
+ if (object->plt_addr != NULL && object->plt_size != 0)
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC);
}
diff --git a/libexec/ld.so/sparc/syscall.h b/libexec/ld.so/sparc/syscall.h
index c11613b6120..ac19f7fb0ca 100644
--- a/libexec/ld.so/sparc/syscall.h
+++ b/libexec/ld.so/sparc/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.2 2002/11/23 19:14:25 drahn Exp $ */
+/* $OpenBSD: syscall.h,v 1.3 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -37,6 +37,7 @@
#include <sys/syscall.h>
#include <sys/stat.h>
+#include <sys/signal.h>
#ifndef _dl_MAX_ERRNO
#define _dl_MAX_ERRNO 4096
@@ -59,6 +60,7 @@ int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/sparc64/ldasm.S b/libexec/ld.so/sparc64/ldasm.S
index 574f065c1ea..2391fbe1b40 100644
--- a/libexec/ld.so/sparc64/ldasm.S
+++ b/libexec/ld.so/sparc64/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.15 2002/11/23 06:19:26 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.16 2002/12/18 19:20:02 drahn Exp $ */
/* $NetBSD: rtld_start.S,v 1.5 2001/08/14 22:17:48 eeh Exp $ */
/*
@@ -366,3 +366,21 @@ _dl_getdirentries:
t ST_SYSCALL ! off to wonderland
retl
sub %g0, %o0, %o0 ! error: result = -errno
+
+
+ /* _dl_sigprocmask does not support NULL new mask */
+ .section ".text"
+ .align 4
+ .globl _dl_sigprocmask
+ .type _dl_sigprocmask,@function
+_dl_sigprocmask:
+ ld [%o1], %o1 ! indirect for new mask
+ mov SYS_sigprocmask, %g1 ! call sys_sigprocmask
+ t ST_SYSCALL ! off to wonderland
+ ! what about errors?
+ cmp %o2, 0
+ bne,a 1f ! if oset != NULL
+ st %o0, [%o2] ! *oset = oldmask
+1:
+ retl
+ clr %o0
diff --git a/libexec/ld.so/sparc64/rtld_machine.c b/libexec/ld.so/sparc64/rtld_machine.c
index d44c20888a2..a46e471b300 100644
--- a/libexec/ld.so/sparc64/rtld_machine.c
+++ b/libexec/ld.so/sparc64/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.22 2002/11/14 15:15:54 drahn Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.23 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 1999 Dale Rahn
@@ -77,6 +77,7 @@
#include <nlist.h>
#include <link.h>
+#include <signal.h>
#include "syscall.h"
#include "archdep.h"
@@ -602,6 +603,7 @@ _dl_bind(elf_object_t *object, int index)
Elf_Addr ooff;
const Elf_Sym *sym, *this;
const char *symn;
+ sigset_t omask, nmask;
rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
if (ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)) {
@@ -641,8 +643,23 @@ _dl_bind(elf_object_t *object, int index)
*((int *)0) = 0; /* XXX */
}
+ /* if PLT is protected, allow the write */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+ sigfillset(&nmask);
+ _dl_sigprocmask(SIG_BLOCK, &nmask, &omask);
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_WRITE|PROT_EXEC);
+ }
+
_dl_reloc_plt(addr, ooff + this->st_value, rela);
+ /* if PLT is (to be protected), change back to RO/X */
+ if (object->plt_addr != NULL && object->plt_size != 0) {
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC);
+ _dl_sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+
return (void *)ooff + this->st_value;
}
@@ -682,10 +699,40 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
{
Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
Elf_Word *entry = (Elf_Word *)pltgot;
+ Elf_Addr ooff;
+ const Elf_Sym *this;
if (object->Dyn.info[DT_PLTREL] != DT_RELA)
return;
+ this = NULL;
+ ooff = _dl_find_symbol("__got_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__got_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->got_size = ooff + this->st_value - object->got_addr;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_start", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_addr = ooff + this->st_value;
+
+ this = NULL;
+ ooff = _dl_find_symbol("__plt_end", object, &this,
+ SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, SYM_NOTPLT,
+ NULL);
+ if (this != NULL)
+ object->plt_size = ooff + this->st_value - object->plt_addr;
+
if (!lazy) {
_dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
return;
@@ -695,4 +742,11 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
_dl_install_plt(&entry[8], (Elf_Addr)&_dl_bind_start_1);
pltgot[8] = (Elf_Addr)object;
+
+ if (object->got_addr != NULL && object->got_size != 0)
+ _dl_mprotect((void*)object->got_addr, object->got_size,
+ PROT_READ);
+ if (object->plt_addr != NULL && object->plt_size != 0)
+ _dl_mprotect((void*)object->plt_addr, object->plt_size,
+ PROT_READ|PROT_EXEC);
}
diff --git a/libexec/ld.so/sparc64/syscall.h b/libexec/ld.so/sparc64/syscall.h
index 2370348b169..cd39a0550c7 100644
--- a/libexec/ld.so/sparc64/syscall.h
+++ b/libexec/ld.so/sparc64/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.10 2002/07/24 04:11:10 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.11 2002/12/18 19:20:02 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -37,6 +37,7 @@
#include <sys/syscall.h>
#include <sys/stat.h>
+#include <sys/signal.h>
#ifndef _dl_MAX_ERRNO
#define _dl_MAX_ERRNO 4096
@@ -57,6 +58,7 @@ ssize_t _dl_write(int, const char*, size_t);
int _dl_fstat(int, struct stat *);
int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
+int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)