summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormatthew <matthew@openbsd.org>2012-08-20 23:25:07 +0000
committermatthew <matthew@openbsd.org>2012-08-20 23:25:07 +0000
commit5f7066906156ece39fb432bab1cea4415d608bfc (patch)
treec17c7fb24eb672c57598476e74a77656ffd85203
parentMAX_LINE_SIZE is supposed to define the max length of a SMTP line ... (diff)
downloadwireguard-openbsd-5f7066906156ece39fb432bab1cea4415d608bfc.tar.xz
wireguard-openbsd-5f7066906156ece39fb432bab1cea4415d608bfc.zip
Add support for .openbsd.randomdata sections and PT_OPENBSD_RANDOMIZE
segments to the kernel, ld (2.15), and ld.so. Tested on alpha, amd64, i386, macppc, and sparc64 (thanks naddy, mpi, and okan!). Idea discussed for some time; committing now for further testing. ok deraadt
-rw-r--r--gnu/usr.bin/binutils/bfd/elf.c31
-rw-r--r--gnu/usr.bin/binutils/binutils/readelf.c1
-rw-r--r--gnu/usr.bin/binutils/include/elf/common.h3
-rw-r--r--gnu/usr.bin/binutils/ld/scripttempl/elf.sc7
-rw-r--r--libexec/ld.so/SPECS.randomdata48
-rw-r--r--libexec/ld.so/library.c15
-rw-r--r--libexec/ld.so/library_mquery.c8
-rw-r--r--sys/kern/exec_elf.c27
-rw-r--r--sys/kern/exec_subr.c27
-rw-r--r--sys/sys/exec.h3
-rw-r--r--sys/sys/exec_elf.h7
11 files changed, 169 insertions, 8 deletions
diff --git a/gnu/usr.bin/binutils/bfd/elf.c b/gnu/usr.bin/binutils/bfd/elf.c
index b0cadb6ddec..901fd2ca52d 100644
--- a/gnu/usr.bin/binutils/bfd/elf.c
+++ b/gnu/usr.bin/binutils/bfd/elf.c
@@ -968,6 +968,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
case PT_TLS: pt = "TLS"; break;
case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
case PT_GNU_STACK: pt = "STACK"; break;
+ case PT_OPENBSD_RANDOMIZE: pt = "OPENBSD_RANDOMIZE"; break;
default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
}
fprintf (f, "%8s off 0x", pt);
@@ -2291,6 +2292,10 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index)
case PT_GNU_STACK:
return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
+ case PT_OPENBSD_RANDOMIZE:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index,
+ "openbsd_randomize");
+
default:
/* Check for any processor-specific program segment types.
If no handler for them, default to making "segment" sections. */
@@ -3194,7 +3199,7 @@ map_sections_to_segments (bfd *abfd)
bfd_boolean writable;
int tls_count = 0;
asection *first_tls = NULL;
- asection *dynsec, *eh_frame_hdr;
+ asection *dynsec, *eh_frame_hdr, *randomdata;
bfd_size_type amt;
if (elf_tdata (abfd)->segment_map != NULL)
@@ -3514,6 +3519,24 @@ map_sections_to_segments (bfd *abfd)
pm = &m->next;
}
+ /* If there is a .openbsd.randomdata section, throw in a PT_OPENBSD_RANDOMIZE
+ segment. */
+ randomdata = bfd_get_section_by_name (abfd, ".openbsd.randomdata");
+ if (randomdata != NULL && (randomdata->flags & SEC_LOAD) != 0)
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_OPENBSD_RANDOMIZE;
+ m->count = 1;
+ m->sections[0] = randomdata->output_section;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
free (sections);
sections = NULL;
@@ -4126,6 +4149,12 @@ get_program_header_size (bfd *abfd)
++segs;
}
+ if (bfd_get_section_by_name (abfd, ".openbsd.randomdata") != NULL)
+ {
+ /* We need a PT_OPENBSD_RANDOMIZE segment. */
+ ++segs;
+ }
+
if (elf_tdata (abfd)->eh_frame_hdr)
{
/* We need a PT_GNU_EH_FRAME segment. */
diff --git a/gnu/usr.bin/binutils/binutils/readelf.c b/gnu/usr.bin/binutils/binutils/readelf.c
index e95a501dabb..2f9ecce43ee 100644
--- a/gnu/usr.bin/binutils/binutils/readelf.c
+++ b/gnu/usr.bin/binutils/binutils/readelf.c
@@ -2144,6 +2144,7 @@ get_segment_type (unsigned long p_type)
case PT_GNU_EH_FRAME:
return "GNU_EH_FRAME";
case PT_GNU_STACK: return "STACK";
+ case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE";
default:
if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
diff --git a/gnu/usr.bin/binutils/include/elf/common.h b/gnu/usr.bin/binutils/include/elf/common.h
index 84ef2b53723..562543338ce 100644
--- a/gnu/usr.bin/binutils/include/elf/common.h
+++ b/gnu/usr.bin/binutils/include/elf/common.h
@@ -290,6 +290,9 @@
#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
+#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6
+
+
/* Program segment permissions, in program header p_flags field. */
#define PF_X (1 << 0) /* Segment is executable */
diff --git a/gnu/usr.bin/binutils/ld/scripttempl/elf.sc b/gnu/usr.bin/binutils/ld/scripttempl/elf.sc
index 28a5a4fb2c7..031bab72c04 100644
--- a/gnu/usr.bin/binutils/ld/scripttempl/elf.sc
+++ b/gnu/usr.bin/binutils/ld/scripttempl/elf.sc
@@ -319,6 +319,13 @@ cat <<EOF
.fini_array ${RELOCATING-0} : { *(.fini_array) }
${RELOCATING+${CREATE_SHLIB-PROVIDE (__fini_array_end = .);}}
+ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__openbsd_randomdata_start = .);}}
+ .openbsd.randomdata ${RELOCATING-0} :
+ {
+ *(.openbsd.randomdata${RELOCATING+ .openbsd.randomdata.*})
+ }
+ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__openbsd_randomdata_end = .);}}
+
.data ${RELOCATING-0} :
{
${RELOCATING+${DATA_START_SYMBOLS}}
diff --git a/libexec/ld.so/SPECS.randomdata b/libexec/ld.so/SPECS.randomdata
new file mode 100644
index 00000000000..434de2ee3de
--- /dev/null
+++ b/libexec/ld.so/SPECS.randomdata
@@ -0,0 +1,48 @@
+$OpenBSD: SPECS.randomdata,v 1.1 2012/08/20 23:25:07 matthew Exp $
+
+This document describes the OpenBSD operating system supplement for
+adding "random data" sections to the ELF ABI. These sections can be
+useful for holding values like GCC's stack-smashing protector cookies
+and offer additional benefits like ensuring the data is initialized
+before any constructor methods are called and allowing the dynamic
+linker to mark the memory as read-only after initialization.
+
+
+Program Header
+
+OpenBSD defines the following operating system-specific segment type:
+
+ Name Value
+ PT_OPENBSD_RANDOMIZE 0x65a3dbe6
+
+
+ PT_OPENBSD_RANDOMIZE
+
+ The array element specifies the location and size of a random data
+ section. The system will initialize the specified memory range
+ with random data. The memory range must be separately mapped
+ (e.g., by use of a PT_LOAD segment).
+
+
+Special Sections
+
+OpenBSD defines the following operating system-specific special
+sections:
+
+ Name Type Attributes
+ .openbsd.randomdata SHT_PROGBITS SHF_ALLOC
+
+
+ .openbsd.randomdata
+
+ This section holds the random data section.
+
+
+Implementation Notes
+
+On OpenBSD, PT_OPENBSD_RANDOMIZE segments are handled alongside
+PT_LOAD segments: the kernel handles initializing random data segments
+in executables and program interpreters (i.e., ld.so), while ld.so
+handles initializing them in shared libraries. Additionally, the
+kernel limits the total number of PT_OPENBSD_RANDOMIZE segment bytes
+in an executable or interpreter to 1024 bytes.
diff --git a/libexec/ld.so/library.c b/libexec/ld.so/library.c
index 1dd2013e6df..60c69f370c6 100644
--- a/libexec/ld.so/library.c
+++ b/libexec/ld.so/library.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: library.c,v 1.66 2012/06/12 20:32:17 matthew Exp $ */
+/* $OpenBSD: library.c,v 1.67 2012/08/20 23:25:07 matthew Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -181,7 +181,8 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
- if (phdp->p_type == PT_LOAD) {
+ switch (phdp->p_type) {
+ case PT_LOAD: {
char *start = (char *)(TRUNC_PG(phdp->p_vaddr)) + loff;
Elf_Addr off = (phdp->p_vaddr & align);
Elf_Addr size = off + phdp->p_filesz;
@@ -233,6 +234,16 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
return(0);
}
}
+ break;
+ }
+
+ case PT_OPENBSD_RANDOMIZE:
+ _dl_randombuf((char *)(phdp->p_vaddr + loff),
+ phdp->p_memsz);
+ break;
+
+ default:
+ break;
}
}
diff --git a/libexec/ld.so/library_mquery.c b/libexec/ld.so/library_mquery.c
index aedfd091f8b..abbde2e533d 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.43 2012/07/21 06:46:58 matthew Exp $ */
+/* $OpenBSD: library_mquery.c,v 1.44 2012/08/20 23:25:07 matthew Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -266,6 +266,12 @@ retry:
load_end = (Elf_Addr)ld->start + ROUND_PG(ld->size);
}
+ phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
+ for (i = 0; i < ehdr->e_phnum; i++, phdp++)
+ if (phdp->p_type == PT_OPENBSD_RANDOMIZE)
+ _dl_randombuf((char *)(phdp->p_vaddr + LOFF),
+ phdp->p_memsz);
+
prebind_data = prebind_load_fd(libfile, libname);
_dl_close(libfile);
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c
index 4e9f314965f..7cfa7d11ea6 100644
--- a/sys/kern/exec_elf.c
+++ b/sys/kern/exec_elf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_elf.c,v 1.86 2012/03/09 13:01:28 ariane Exp $ */
+/* $OpenBSD: exec_elf.c,v 1.87 2012/08/20 23:25:07 matthew Exp $ */
/*
* Copyright (c) 1996 Per Fogelstrom
@@ -130,6 +130,9 @@ extern char *syscallnames[];
*/
#define ELF_MAX_VALID_PHDR 32
+/* Limit on total PT_OPENBSD_RANDOMIZE bytes. */
+#define ELF_RANDOMIZE_LIMIT 1024
+
/*
* This is the basic elf emul. elf_probe_funcs may change to other emuls.
*/
@@ -327,6 +330,7 @@ ELFNAME(load_file)(struct proc *p, char *path, struct exec_package *epp,
Elf_Addr pos = *last;
int file_align;
int loop;
+ size_t randomizequota = ELF_RANDOMIZE_LIMIT;
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);
if ((error = namei(&nd)) != 0) {
@@ -469,6 +473,16 @@ ELFNAME(load_file)(struct proc *p, char *path, struct exec_package *epp,
case PT_NOTE:
break;
+ case PT_OPENBSD_RANDOMIZE:
+ if (ph[i].p_memsz > randomizequota) {
+ error = ENOMEM;
+ goto bad1;
+ }
+ randomizequota -= ph[i].p_memsz;
+ NEW_VMCMD(&epp->ep_vmcmds, vmcmd_randomize,
+ ph[i].p_memsz, ph[i].p_vaddr + pos, NULLVP, 0, 0);
+ break;
+
default:
break;
}
@@ -506,6 +520,7 @@ ELFNAME2(exec,makecmds)(struct proc *p, struct exec_package *epp)
char *interp = NULL;
u_long pos = 0, phsize;
u_int8_t os = OOS_NULL;
+ size_t randomizequota = ELF_RANDOMIZE_LIMIT;
if (epp->ep_hdrvalid < sizeof(Elf_Ehdr))
return (ENOEXEC);
@@ -692,6 +707,16 @@ native:
phdr = pp->p_vaddr;
break;
+ case PT_OPENBSD_RANDOMIZE:
+ if (ph[i].p_memsz > randomizequota) {
+ error = ENOMEM;
+ goto bad;
+ }
+ randomizequota -= ph[i].p_memsz;
+ NEW_VMCMD(&epp->ep_vmcmds, vmcmd_randomize,
+ ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 0);
+ break;
+
default:
/*
* Not fatal, we don't need to understand everything
diff --git a/sys/kern/exec_subr.c b/sys/kern/exec_subr.c
index b712404f3b3..301214722d6 100644
--- a/sys/kern/exec_subr.c
+++ b/sys/kern/exec_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_subr.c,v 1.29 2011/06/29 12:16:17 tedu Exp $ */
+/* $OpenBSD: exec_subr.c,v 1.30 2012/08/20 23:25:07 matthew Exp $ */
/* $NetBSD: exec_subr.c,v 1.9 1994/12/04 03:10:42 mycroft Exp $ */
/*
@@ -42,6 +42,7 @@
#include <sys/resourcevar.h>
#include <uvm/uvm.h>
+#include <dev/rndvar.h>
#ifdef DEBUG
/*
@@ -289,6 +290,30 @@ vmcmd_map_zero(struct proc *p, struct exec_vmcmd *cmd)
}
/*
+ * vmcmd_randomize():
+ * handle vmcmd which specifies a randomized address space region.
+ */
+
+int
+vmcmd_randomize(struct proc *p, struct exec_vmcmd *cmd)
+{
+ char *buf;
+ int error;
+
+ if (cmd->ev_len == 0)
+ return (0);
+ if (cmd->ev_len > 1024)
+ return (EINVAL);
+
+ buf = malloc(cmd->ev_len, M_TEMP, M_WAITOK);
+ arc4random_buf(buf, cmd->ev_len);
+ error = copyout(buf, (void *)cmd->ev_addr, cmd->ev_len);
+ free(buf, M_TEMP);
+
+ return (error);
+}
+
+/*
* exec_setup_stack(): Set up the stack segment for an a.out
* executable.
*
diff --git a/sys/sys/exec.h b/sys/sys/exec.h
index 6791d2bf167..ecb4239d40b 100644
--- a/sys/sys/exec.h
+++ b/sys/sys/exec.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec.h,v 1.25 2009/07/09 22:29:56 thib Exp $ */
+/* $OpenBSD: exec.h,v 1.26 2012/08/20 23:25:07 matthew Exp $ */
/* $NetBSD: exec.h,v 1.59 1996/02/09 18:25:09 christos Exp $ */
/*-
@@ -174,6 +174,7 @@ void kill_vmcmds(struct exec_vmcmd_set *evsp);
int vmcmd_map_pagedvn(struct proc *, struct exec_vmcmd *);
int vmcmd_map_readvn(struct proc *, struct exec_vmcmd *);
int vmcmd_map_zero(struct proc *, struct exec_vmcmd *);
+int vmcmd_randomize(struct proc *, struct exec_vmcmd *);
void *copyargs(struct exec_package *,
struct ps_strings *,
void *, void *);
diff --git a/sys/sys/exec_elf.h b/sys/sys/exec_elf.h
index 530048b2fb2..17288b80d93 100644
--- a/sys/sys/exec_elf.h
+++ b/sys/sys/exec_elf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_elf.h,v 1.49 2011/09/20 16:42:01 pirofti Exp $ */
+/* $OpenBSD: exec_elf.h,v 1.50 2012/08/20 23:25:07 matthew Exp $ */
/*
* Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
*
@@ -426,6 +426,9 @@ typedef struct {
#define PT_LOPROC 0x70000000 /* reserved range for processor */
#define PT_HIPROC 0x7fffffff /* specific segment types */
+#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */
+
+
/* Segment flags - p_flags */
#define PF_X 0x1 /* Executable */
#define PF_W 0x2 /* Writable */
@@ -478,6 +481,8 @@ typedef struct {
#define DT_JMPREL 23 /* add. of PLT's relocation entries */
#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
#define DT_NUM 25 /* Number used. */
+#define DT_LOOS 0x6000000d /* reserved range for OS */
+#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */
#define DT_LOPROC 0x70000000 /* reserved range for processor */
#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */