summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2019-03-18 15:28:27 +0000
committerPatrick Mooney <pmooney@pfmooney.com>2019-03-18 18:35:01 +0000
commit90e27ef5fc2bdeb7f9934f4e77140ef5f1aa9392 (patch)
treed2bc1bebe96fa972da877fa01f2b921bc4129287 /usr/src
parentf596c0900965f1168f07b20b94337167854044c3 (diff)
downloadillumos-joyent-90e27ef5fc2bdeb7f9934f4e77140ef5f1aa9392.tar.gz
OS-6158 signed math leads getelfshdr astray
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Cody Peter Mello <melloc@writev.io> Approved by: Mike Gerdts <mike.gerdts@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_brand.c28
-rw-r--r--usr/src/uts/common/brand/sn1/sn1_brand.c6
-rw-r--r--usr/src/uts/common/brand/solaris10/s10_brand.c6
-rw-r--r--usr/src/uts/common/exec/elf/elf.c1090
-rw-r--r--usr/src/uts/common/exec/elf/elf_impl.h17
-rw-r--r--usr/src/uts/common/exec/intp/intp.c6
-rw-r--r--usr/src/uts/common/exec/java/java.c4
-rw-r--r--usr/src/uts/common/exec/shbin/shbin.c6
-rw-r--r--usr/src/uts/common/fs/proc/prioctl.c10
-rw-r--r--usr/src/uts/common/fs/proc/prsubr.c21
-rw-r--r--usr/src/uts/common/os/brand.c8
-rw-r--r--usr/src/uts/common/os/core.c20
-rw-r--r--usr/src/uts/common/os/exec.c8
-rw-r--r--usr/src/uts/common/sys/brand.h11
-rw-r--r--usr/src/uts/common/sys/exec.h28
-rw-r--r--usr/src/uts/common/sys/prsystm.h4
16 files changed, 681 insertions, 592 deletions
diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c
index d388b14c70..0f78bca605 100644
--- a/usr/src/uts/common/brand/lx/os/lx_brand.c
+++ b/usr/src/uts/common/brand/lx/os/lx_brand.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright 2018, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -235,7 +235,7 @@ void (*lx_cgrp_freelwp)(vfs_t *, uint_t, id_t, pid_t);
uint64_t lx_maxstack64 = LX_MAXSTACK64;
static int lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
- struct intpdata *idata, int level, long *execsz, int setid,
+ struct intpdata *idata, int level, size_t *execsz, int setid,
caddr_t exec_file, struct cred *cred, int *brand_action);
static boolean_t lx_native_exec(uint8_t, const char **);
@@ -2043,12 +2043,6 @@ restoreexecenv(struct execenv *ep, stack_t *sp)
lwp->lwp_sigaltstack.ss_flags = sp->ss_flags;
}
-extern int elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
-
-extern int elf32exec(struct vnode *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
-
static uintptr_t
lx_map_vdso(struct uarg *args, struct cred *cred)
{
@@ -2113,10 +2107,10 @@ lx_map_vdso(struct uarg *args, struct cred *cred)
/* ARGSUSED4 */
static int
lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
- struct intpdata *idata, int level, long *execsz, int setid,
+ struct intpdata *idata, int level, size_t *execsz, int setid,
caddr_t exec_file, struct cred *cred, int *brand_action)
{
- int error, i;
+ int error;
vnode_t *nvp;
Ehdr ehdr;
Addr uphdr_vaddr;
@@ -2183,8 +2177,8 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
Ehdr ehdr;
Phdr *phdrp;
caddr_t phdrbase = NULL;
- ssize_t phdrsize = 0;
- int nphdrs, hsize;
+ size_t phdrsize = 0;
+ uint_t nphdrs, hsize;
if ((error = elfreadhdr(vp, cred, &ehdr, &nphdrs, &phdrbase,
&phdrsize)) != 0) {
@@ -2194,7 +2188,7 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
hsize = ehdr.e_phentsize;
/* LINTED: alignment */
phdrp = (Phdr *)phdrbase;
- for (i = nphdrs; i > 0; i--) {
+ for (uint_t i = nphdrs; i > 0; i--) {
switch (phdrp->p_type) {
case PT_GNU_STACK:
if ((phdrp->p_flags & PF_X) == 0) {
@@ -2212,8 +2206,8 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
Elf32_Ehdr ehdr;
Elf32_Phdr *phdrp;
caddr_t phdrbase = NULL;
- ssize_t phdrsize = 0;
- int nphdrs, hsize;
+ size_t phdrsize = 0;
+ uint_t nphdrs, hsize;
if ((error = elf32readhdr(vp, cred, &ehdr, &nphdrs, &phdrbase,
&phdrsize)) != 0) {
@@ -2223,7 +2217,7 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
hsize = ehdr.e_phentsize;
/* LINTED: alignment */
phdrp = (Elf32_Phdr *)phdrbase;
- for (i = nphdrs; i > 0; i--) {
+ for (uint_t i = nphdrs; i > 0; i--) {
switch (phdrp->p_type) {
case PT_GNU_STACK:
if ((phdrp->p_flags & PF_X) == 0) {
@@ -2538,7 +2532,7 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
* So we set AT_ENTRY to be the entry point of the linux executable,
* but leave AT_BASE to be the address of the Solaris linker.
*/
- for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
+ for (uint_t i = 0; i < __KERN_NAUXV_IMPL; i++) {
switch (up->u_auxv[i].a_type) {
case AT_ENTRY:
up->u_auxv[i].a_un.a_val = edp.ed_entry;
diff --git a/usr/src/uts/common/brand/sn1/sn1_brand.c b/usr/src/uts/common/brand/sn1/sn1_brand.c
index a2383ca076..ebdabce2b5 100644
--- a/usr/src/uts/common/brand/sn1/sn1_brand.c
+++ b/usr/src/uts/common/brand/sn1/sn1_brand.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/errno.h>
@@ -58,7 +58,7 @@ void sn1_forklwp(klwp_t *, klwp_t *);
void sn1_freelwp(klwp_t *);
void sn1_lwpexit(klwp_t *);
int sn1_elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
/* sn1 brand */
struct brand_ops sn1_brops = {
@@ -254,7 +254,7 @@ sn1_init_brand_data(zone_t *zone, kmutex_t *zsl)
int
sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
- int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
+ int level, size_t *execsz, int setid, caddr_t exec_file, cred_t *cred,
int *brand_action)
{
return (brand_solaris_elfexec(vp, uap, args, idatap, level, execsz,
diff --git a/usr/src/uts/common/brand/solaris10/s10_brand.c b/usr/src/uts/common/brand/solaris10/s10_brand.c
index c5a9d10f58..4de7cbcc05 100644
--- a/usr/src/uts/common/brand/solaris10/s10_brand.c
+++ b/usr/src/uts/common/brand/solaris10/s10_brand.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/errno.h>
@@ -61,7 +61,7 @@ void s10_forklwp(klwp_t *, klwp_t *);
void s10_freelwp(klwp_t *);
void s10_lwpexit(klwp_t *);
int s10_elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
void s10_sigset_native_to_s10(sigset_t *);
void s10_sigset_s10_to_native(sigset_t *);
@@ -423,7 +423,7 @@ s10_init_brand_data(zone_t *zone, kmutex_t *zsl)
int
s10_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
- int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
+ int level, size_t *execsz, int setid, caddr_t exec_file, cred_t *cred,
int *brand_action)
{
return (brand_solaris_elfexec(vp, uap, args, idatap, level, execsz,
diff --git a/usr/src/uts/common/exec/elf/elf.c b/usr/src/uts/common/exec/elf/elf.c
index 0b4e70cad3..cf5e0bdfd9 100644
--- a/usr/src/uts/common/exec/elf/elf.c
+++ b/usr/src/uts/common/exec/elf/elf.c
@@ -80,15 +80,32 @@ extern volatile size_t aslr_max_brk_skew;
#define ORIGIN_STR "ORIGIN"
#define ORIGIN_STR_SIZE 6
-static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
-static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
- ssize_t *);
-static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
- ssize_t *, caddr_t *, ssize_t *);
-static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
-static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t,
- Phdr **, Phdr **, Phdr **, Phdr **, Phdr *,
- caddr_t *, caddr_t *, intptr_t *, intptr_t *, size_t, long *, size_t *);
+static int getelfhead(vnode_t *, cred_t *, Ehdr *, uint_t *, uint_t *,
+ uint_t *);
+static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, uint_t, caddr_t *,
+ size_t *);
+static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, uint_t, uint_t,
+ caddr_t *, size_t *, caddr_t *, size_t *);
+static size_t elfsize(const Ehdr *, uint_t, const caddr_t, uintptr_t *);
+static int mapelfexec(vnode_t *, Ehdr *, uint_t, caddr_t, Phdr **, Phdr **,
+ Phdr **, Phdr **, Phdr *, caddr_t *, caddr_t *, intptr_t *, uintptr_t *,
+ size_t, size_t *, size_t *);
+
+#ifdef _ELF32_COMPAT
+/* Link against the non-compat instances when compiling the 32-bit version. */
+extern size_t elf_datasz_max;
+extern void elf_ctx_resize_scratch(elf_core_ctx_t *, size_t);
+extern uint_t elf_nphdr_max;
+extern uint_t elf_nshdr_max;
+extern size_t elf_shstrtab_max;
+#else
+size_t elf_datasz_max = 1 * 1024 * 1024;
+uint_t elf_nphdr_max = 1000;
+uint_t elf_nshdr_max = 10000;
+size_t elf_shstrtab_max = 100 * 1024;
+#endif
+
+
typedef enum {
STR_CTF,
@@ -110,8 +127,8 @@ static const char *shstrtab_data[] = {
};
typedef struct shstrtab {
- int sst_ndx[STR_NUM];
- int sst_cur;
+ uint_t sst_ndx[STR_NUM];
+ uint_t sst_cur;
} shstrtab_t;
static void
@@ -121,10 +138,10 @@ shstrtab_init(shstrtab_t *s)
s->sst_cur = 1;
}
-static int
+static uint_t
shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
{
- int ret;
+ uint_t ret;
if ((ret = s->sst_ndx[type]) != 0)
return (ret);
@@ -144,7 +161,7 @@ shstrtab_size(const shstrtab_t *s)
static void
shstrtab_dump(const shstrtab_t *s, char *buf)
{
- int i, ndx;
+ uint_t i, ndx;
*buf = '\0';
for (i = 0; i < STR_NUM; i++) {
@@ -206,6 +223,23 @@ handle_secflag_dt(proc_t *p, uint_t dt, uint_t val)
return (0);
}
+
+#ifndef _ELF32_COMPAT
+void
+elf_ctx_resize_scratch(elf_core_ctx_t *ctx, size_t sz)
+{
+ size_t target = MIN(sz, elf_datasz_max);
+
+ if (target > ctx->ecc_bufsz) {
+ if (ctx->ecc_buf != NULL) {
+ kmem_free(ctx->ecc_buf, ctx->ecc_bufsz);
+ }
+ ctx->ecc_buf = kmem_alloc(target, KM_SLEEP);
+ ctx->ecc_bufsz = target;
+ }
+}
+#endif /* _ELF32_COMPAT */
+
/*
* Map in the executable pointed to by vp. Returns 0 on success. Note that
* this function currently has the maximum number of arguments allowed by
@@ -218,20 +252,18 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
intptr_t *voffset, caddr_t exec_file, char **interpp, caddr_t *bssbase,
caddr_t *brkbase, size_t *brksize, uintptr_t *lddatap, uintptr_t *minaddrp)
{
- size_t len;
+ size_t len, phdrsize;
struct vattr vat;
caddr_t phdrbase = NULL;
- ssize_t phdrsize;
- int nshdrs, shstrndx, nphdrs;
+ uint_t nshdrs, shstrndx, nphdrs;
int error = 0;
Phdr *uphdr = NULL;
Phdr *junk = NULL;
Phdr *dynphdr = NULL;
Phdr *dtrphdr = NULL;
char *interp = NULL;
- uintptr_t lddata;
- long execsz;
- intptr_t minaddr;
+ uintptr_t lddata, minaddr;
+ size_t execsz;
if (lddatap != NULL)
*lddatap = NULL;
@@ -287,7 +319,8 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
interp = kmem_alloc(MAXPATHLEN, KM_SLEEP);
- if ((error = vn_rdwr(UIO_READ, vp, interp, dynphdr->p_filesz,
+ if ((error = vn_rdwr(UIO_READ, vp, interp,
+ (ssize_t)dynphdr->p_filesz,
(offset_t)dynphdr->p_offset, UIO_SYSSPACE, 0,
(rlim64_t)0, CRED(), &resid)) != 0 || resid != 0 ||
interp[dynphdr->p_filesz - 1] != '\0') {
@@ -329,8 +362,9 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
* in mapelfexec() and use the p_vaddr of the first PT_LOAD
* section as the base address of the object.
*/
- Phdr *phdr = (Phdr *)phdrbase;
- int i, hsize = ehdr->e_phentsize;
+ const Phdr *phdr = (Phdr *)phdrbase;
+ const uint_t hsize = ehdr->e_phentsize;
+ uint_t i;
for (i = nphdrs; i > 0; i--) {
if (phdr->p_type == PT_LOAD) {
@@ -358,14 +392,14 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
/*ARGSUSED*/
int
elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
- int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
+ int level, size_t *execsz, int setid, caddr_t exec_file, cred_t *cred,
int *brand_action)
{
caddr_t phdrbase = NULL;
caddr_t bssbase = 0;
caddr_t brkbase = 0;
size_t brksize = 0;
- ssize_t dlnsize, nsize = 0;
+ size_t dlnsize, nsize = 0;
aux_entry_t *aux;
int error;
ssize_t resid;
@@ -377,16 +411,14 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
Phdr *uphdr = NULL;
Phdr *junk = NULL;
size_t len;
+ size_t postfixsize = 0;
size_t i;
- ssize_t phdrsize;
- int postfixsize = 0;
- int hsize;
Phdr *phdrp;
Phdr *dataphdrp = NULL;
Phdr *dtrphdr;
Phdr *capphdr = NULL;
Cap *cap = NULL;
- ssize_t capsize;
+ size_t capsize;
int hasu = 0;
int hasauxv = 0;
int hasintp = 0;
@@ -404,7 +436,8 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
struct execenv exenv;
} *bigwad; /* kmem_alloc this behemoth so we don't blow stack */
Ehdr *ehdrp;
- int nshdrs, shstrndx, nphdrs;
+ uint_t nshdrs, shstrndx, nphdrs;
+ size_t phdrsize;
char *dlnp;
char *pathbufp;
rlim64_t limit;
@@ -512,7 +545,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* determine any non-default stack protections,
* and still have this code be machine independent.
*/
- hsize = ehdrp->e_phentsize;
+ const uint_t hsize = ehdrp->e_phentsize;
phdrp = (Phdr *)phdrbase;
for (i = nphdrs; i > 0; i--) {
switch (phdrp->p_type) {
@@ -688,7 +721,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)dyn,
(ssize_t)dynsize, (offset_t)(dynoffset + i),
UIO_SYSSPACE, 0, (rlim64_t)0,
- CRED(), &resid)) != 0) {
+ CRED(), NULL)) != 0) {
uprintf("%s: cannot read .dynamic section\n",
exec_file);
goto out;
@@ -716,13 +749,13 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
if (capphdr != NULL &&
(capsize = capphdr->p_filesz) > 0 &&
capsize <= 16 * sizeof (*cap)) {
- int ncaps = capsize / sizeof (*cap);
+ const uint_t ncaps = capsize / sizeof (*cap);
Cap *cp;
cap = kmem_alloc(capsize, KM_SLEEP);
if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
- capsize, (offset_t)capphdr->p_offset,
- UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
+ (ssize_t)capsize, (offset_t)capphdr->p_offset,
+ UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), NULL)) != 0) {
uprintf("%s: Cannot read capabilities section\n",
exec_file);
goto out;
@@ -763,17 +796,18 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
dtrphdr = NULL;
- if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
+ error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
&stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
- len, execsz, &brksize)) != 0)
- goto bad;
+ len, execsz, &brksize);
+ /*
+ * Our uphdr has been dynamically allocated if (and only if) its
+ * program header flags are clear. To avoid leaks, this must be
+ * checked regardless of whether mapelfexec() emitted an error.
+ */
+ dynuphdr = (uphdr != NULL && uphdr->p_flags == 0);
- if (uphdr != NULL) {
- /*
- * Our uphdr has been dynamically allocated if (and only if)
- * its program header flags are clear.
- */
- dynuphdr = (uphdr->p_flags == 0);
+ if (error != 0) {
+ goto bad;
}
if (uphdr != NULL && intphdr == NULL)
@@ -792,8 +826,14 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
dlnsize = intphdr->p_filesz + nsize;
- if (dlnsize > MAXPATHLEN || dlnsize <= 0)
+ /*
+ * Make sure none of the component pieces of dlnsize result in
+ * an oversized or zeroed result.
+ */
+ if (intphdr->p_filesz > MAXPATHLEN || dlnsize > MAXPATHLEN ||
+ dlnsize == 0 || dlnsize < intphdr->p_filesz) {
goto bad;
+ }
if (nsize != 0) {
bcopy(args->brand_nroot, dlnp, nsize - 1);
@@ -804,7 +844,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* Read in "interpreter" pathname.
*/
if ((error = vn_rdwr(UIO_READ, vp, dlnp + nsize,
- intphdr->p_filesz, (offset_t)intphdr->p_offset,
+ (ssize_t)intphdr->p_filesz, (offset_t)intphdr->p_offset,
UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
uprintf("%s: Cannot obtain interpreter pathname\n",
exec_file);
@@ -1100,7 +1140,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
#endif /* defined(__amd64) */
ADDAUX(aux, AT_NULL, 0)
- postfixsize = (char *)aux - (char *)bigwad->elfargs;
+ postfixsize = (uintptr_t)aux - (uintptr_t)bigwad->elfargs;
/*
* We make assumptions above when we determine how many aux
@@ -1111,8 +1151,8 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* We detect that now and error out.
*/
if (postfixsize != args->auxsize) {
- DTRACE_PROBE2(elfexec_badaux, int, postfixsize,
- int, args->auxsize);
+ DTRACE_PROBE2(elfexec_badaux, size_t, postfixsize,
+ size_t, args->auxsize);
goto bad;
}
ASSERT(postfixsize <= __KERN_NAUXV_IMPL * sizeof (aux_entry_t));
@@ -1140,7 +1180,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
bzero(up->u_auxv, sizeof (up->u_auxv));
up->u_commpagep = args->commpage;
if (postfixsize) {
- int num_auxv;
+ size_t num_auxv;
/*
* Copy the aux vector to the user stack.
@@ -1219,32 +1259,23 @@ out:
* Compute the memory size requirement for the ELF file.
*/
static size_t
-elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
+elfsize(const Ehdr *ehdrp, uint_t nphdrs, const caddr_t phdrbase,
+ uintptr_t *lddata)
{
- size_t len;
- Phdr *phdrp = (Phdr *)phdrbase;
- int hsize = ehdrp->e_phentsize;
- int first = 1;
- int dfirst = 1; /* first data segment */
- uintptr_t loaddr = 0;
+ const Phdr *phdrp = (Phdr *)phdrbase;
+ const uint_t hsize = ehdrp->e_phentsize;
+ boolean_t dfirst = B_TRUE;
+ uintptr_t loaddr = UINTPTR_MAX;
uintptr_t hiaddr = 0;
- uintptr_t lo, hi;
- int i;
+ uint_t i;
for (i = nphdrs; i > 0; i--) {
if (phdrp->p_type == PT_LOAD) {
- lo = phdrp->p_vaddr;
- hi = lo + phdrp->p_memsz;
- if (first) {
- loaddr = lo;
- hiaddr = hi;
- first = 0;
- } else {
- if (loaddr > lo)
- loaddr = lo;
- if (hiaddr < hi)
- hiaddr = hi;
- }
+ const uintptr_t lo = phdrp->p_vaddr;
+ const uintptr_t hi = lo + phdrp->p_memsz;
+
+ loaddr = MIN(lo, loaddr);
+ hiaddr = MAX(hi, hiaddr);
/*
* save the address of the first data segment
@@ -1254,16 +1285,18 @@ elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
if ((lddata != NULL) && dfirst &&
(phdrp->p_flags & PF_W)) {
*lddata = lo;
- dfirst = 0;
+ dfirst = B_FALSE;
}
}
phdrp = (Phdr *)((caddr_t)phdrp + hsize);
}
- len = hiaddr - (loaddr & PAGEMASK);
- len = roundup(len, PAGESIZE);
+ if (hiaddr <= loaddr) {
+ /* No non-zero PT_LOAD segment found */
+ return (0);
+ }
- return (len);
+ return (roundup(hiaddr - (loaddr & PAGEMASK), PAGESIZE));
}
/*
@@ -1273,8 +1306,8 @@ elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
* EINVAL Format recognized but execution not supported
*/
static int
-getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
- int *nphdrs)
+getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, uint_t *nshdrs,
+ uint_t *shstrndx, uint_t *nphdrs)
{
int error;
ssize_t resid;
@@ -1283,10 +1316,10 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
* We got here by the first two bytes in ident,
* now read the entire ELF header.
*/
- if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)ehdr,
- sizeof (Ehdr), (offset_t)0, UIO_SYSSPACE, 0,
- (rlim64_t)0, credp, &resid)) != 0)
+ if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)ehdr, sizeof (Ehdr),
+ (offset_t)0, UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid)) != 0) {
return (error);
+ }
/*
* Since a separate version is compiled for handling 32-bit and
@@ -1295,8 +1328,9 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
*/
if (resid != 0 ||
ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
- ehdr->e_ident[EI_MAG3] != ELFMAG3)
+ ehdr->e_ident[EI_MAG3] != ELFMAG3) {
return (ENOEXEC);
+ }
if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) ||
#if defined(_ILP32) || defined(_ELF32_COMPAT)
@@ -1305,8 +1339,9 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
#endif
!elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine,
- ehdr->e_flags))
+ ehdr->e_flags)) {
return (EINVAL);
+ }
*nshdrs = ehdr->e_shnum;
*shstrndx = ehdr->e_shstrndx;
@@ -1314,7 +1349,7 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
/*
* If e_shnum, e_shstrndx, or e_phnum is its sentinel value, we need
- * to read in the section header at index zero to acces the true
+ * to read in the section header at index zero to access the true
* values for those fields.
*/
if ((*nshdrs == 0 && ehdr->e_shoff != 0) ||
@@ -1326,7 +1361,7 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&shdr,
sizeof (shdr), (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0,
- (rlim64_t)0, credp, &resid)) != 0)
+ (rlim64_t)0, credp, NULL)) != 0)
return (error);
if (*nshdrs == 0)
@@ -1340,33 +1375,29 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
return (0);
}
-#ifdef _ELF32_COMPAT
-extern size_t elf_nphdr_max;
+/*
+ * We use members through p_flags on 32-bit files and p_memsz on 64-bit files,
+ * so e_phentsize must be at least large enough to include those members.
+ */
+#if !defined(_LP64) || defined(_ELF32_COMPAT)
+#define MINPHENTSZ (offsetof(Phdr, p_flags) + \
+ sizeof (((Phdr *)NULL)->p_flags))
#else
-size_t elf_nphdr_max = 1000;
+#define MINPHENTSZ (offsetof(Phdr, p_memsz) + \
+ sizeof (((Phdr *)NULL)->p_memsz))
#endif
static int
-getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
- caddr_t *phbasep, ssize_t *phsizep)
+getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, uint_t nphdrs,
+ caddr_t *phbasep, size_t *phsizep)
{
- ssize_t resid, minsize;
int err;
/*
- * Since we're going to be using e_phentsize to iterate down the
- * array of program headers, it must be 8-byte aligned or else
- * a we might cause a misaligned access. We use all members through
- * p_flags on 32-bit ELF files and p_memsz on 64-bit ELF files so
- * e_phentsize must be at least large enough to include those
- * members.
+ * Ensure that e_phentsize is large enough for required fields to be
+ * accessible and will maintain 8-byte alignment.
*/
-#if !defined(_LP64) || defined(_ELF32_COMPAT)
- minsize = offsetof(Phdr, p_flags) + sizeof (((Phdr *)NULL)->p_flags);
-#else
- minsize = offsetof(Phdr, p_memsz) + sizeof (((Phdr *)NULL)->p_memsz);
-#endif
- if (ehdr->e_phentsize < minsize || (ehdr->e_phentsize & 3))
+ if (ehdr->e_phentsize < MINPHENTSZ || (ehdr->e_phentsize & 3))
return (EINVAL);
*phsizep = nphdrs * ehdr->e_phentsize;
@@ -1378,9 +1409,9 @@ getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
*phbasep = kmem_alloc(*phsizep, KM_SLEEP);
}
- if ((err = vn_rdwr(UIO_READ, vp, *phbasep, *phsizep,
+ if ((err = vn_rdwr(UIO_READ, vp, *phbasep, (ssize_t)*phsizep,
(offset_t)ehdr->e_phoff, UIO_SYSSPACE, 0, (rlim64_t)0,
- credp, &resid)) != 0) {
+ credp, NULL)) != 0) {
kmem_free(*phbasep, *phsizep);
*phbasep = NULL;
return (err);
@@ -1389,21 +1420,14 @@ getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
return (0);
}
-#ifdef _ELF32_COMPAT
-extern size_t elf_nshdr_max;
-extern size_t elf_shstrtab_max;
-#else
-size_t elf_nshdr_max = 10000;
-size_t elf_shstrtab_max = 100 * 1024;
-#endif
-
+#define MINSHDRSZ (offsetof(Shdr, sh_entsize) + \
+ sizeof (((Shdr *)NULL)->sh_entsize))
static int
-getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
- int nshdrs, int shstrndx, caddr_t *shbasep, ssize_t *shsizep,
- char **shstrbasep, ssize_t *shstrsizep)
+getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, uint_t nshdrs,
+ uint_t shstrndx, caddr_t *shbasep, size_t *shsizep, char **shstrbasep,
+ size_t *shstrsizep)
{
- ssize_t resid, minsize;
int err;
Shdr *shdr;
@@ -1415,9 +1439,8 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
* must be at least large enough to include that member. The index
* of the string table section must also be valid.
*/
- minsize = offsetof(Shdr, sh_entsize) + sizeof (shdr->sh_entsize);
- if (ehdr->e_shentsize < minsize || (ehdr->e_shentsize & 3) ||
- shstrndx >= nshdrs)
+ if (ehdr->e_shentsize < MINSHDRSZ || (ehdr->e_shentsize & 3) ||
+ nshdrs == 0 || shstrndx >= nshdrs)
return (EINVAL);
*shsizep = nshdrs * ehdr->e_shentsize;
@@ -1429,16 +1452,16 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
*shbasep = kmem_alloc(*shsizep, KM_SLEEP);
}
- if ((err = vn_rdwr(UIO_READ, vp, *shbasep, *shsizep,
+ if ((err = vn_rdwr(UIO_READ, vp, *shbasep, (ssize_t)*shsizep,
(offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, (rlim64_t)0,
- credp, &resid)) != 0) {
+ credp, NULL)) != 0) {
kmem_free(*shbasep, *shsizep);
return (err);
}
/*
- * Pull the section string table out of the vnode; fail if the size
- * is zero.
+ * Grab the section string table. Walking through the shdrs is
+ * pointless if their names cannot be interrogated.
*/
shdr = (Shdr *)(*shbasep + shstrndx * ehdr->e_shentsize);
if ((*shstrsizep = shdr->sh_size) == 0) {
@@ -1456,9 +1479,9 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
*shstrbasep = kmem_alloc(*shstrsizep, KM_SLEEP);
}
- if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, *shstrsizep,
+ if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, (ssize_t)*shstrsizep,
(offset_t)shdr->sh_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
- credp, &resid)) != 0) {
+ credp, NULL)) != 0) {
kmem_free(*shbasep, *shsizep);
kmem_free(*shstrbasep, *shstrsizep);
return (err);
@@ -1474,17 +1497,12 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
}
-#ifdef _ELF32_COMPAT
-int
-elf32readhdr(vnode_t *vp, cred_t *credp, Ehdr *ehdrp, int *nphdrs,
- caddr_t *phbasep, ssize_t *phsizep)
-#else
int
-elfreadhdr(vnode_t *vp, cred_t *credp, Ehdr *ehdrp, int *nphdrs,
- caddr_t *phbasep, ssize_t *phsizep)
-#endif
+elfreadhdr(vnode_t *vp, cred_t *credp, Ehdr *ehdrp, uint_t *nphdrs,
+ caddr_t *phbasep, size_t *phsizep)
{
- int error, nshdrs, shstrndx;
+ int error;
+ uint_t nshdrs, shstrndx;
if ((error = getelfhead(vp, credp, ehdrp, &nshdrs, &shstrndx,
nphdrs)) != 0 ||
@@ -1500,7 +1518,7 @@ static int
mapelfexec(
vnode_t *vp,
Ehdr *ehdr,
- int nphdrs,
+ uint_t nphdrs,
caddr_t phdrbase,
Phdr **uphdr,
Phdr **intphdr,
@@ -1510,21 +1528,21 @@ mapelfexec(
caddr_t *bssbase,
caddr_t *brkbase,
intptr_t *voffset,
- intptr_t *minaddr,
+ uintptr_t *minaddrp,
size_t len,
- long *execsz,
+ size_t *execsz,
size_t *brksize)
{
Phdr *phdr;
- int i, prot, error, lastprot = 0;
+ int error, page, prot, lastprot = 0;
caddr_t addr = NULL;
- size_t zfodsz;
- int ptload = 0;
- int page;
+ caddr_t minaddr = (caddr_t)UINTPTR_MAX;
+ uint_t i;
+ size_t zfodsz, memsz;
+ boolean_t ptload = B_FALSE;
off_t offset;
- int hsize = ehdr->e_phentsize;
- caddr_t mintmp = (caddr_t)-1;
- uintptr_t lastaddr = NULL;
+ const uint_t hsize = ehdr->e_phentsize;
+ uintptr_t lastaddr = 0;
extern int use_brk_lpg;
if (ehdr->e_type == ET_DYN) {
@@ -1540,7 +1558,6 @@ mapelfexec(
map_addr(&addr, len, (offset_t)0, 1, flags);
if (addr == NULL)
return (ENOMEM);
- *voffset = (intptr_t)addr;
/*
* Despite the fact that mmapobj(2) refuses to load them, we
@@ -1575,8 +1592,8 @@ mapelfexec(
* prelink(8) contraption -- goggles on!
*/
if ((vaddr = addr) != NULL) {
- if (as_gap(curproc->p_as, len,
- &addr, &len, AH_LO, NULL) == -1 || addr != vaddr) {
+ if (as_gap(curproc->p_as, len, &addr, &len,
+ AH_LO, NULL) == -1 || addr != vaddr) {
addr = NULL;
}
}
@@ -1608,7 +1625,7 @@ mapelfexec(
for (i = nphdrs; i > 0; i--) {
switch (phdr->p_type) {
case PT_LOAD:
- ptload = 1;
+ ptload = B_TRUE;
prot = PROT_USER;
if (phdr->p_flags & PF_R)
prot |= PROT_READ;
@@ -1648,11 +1665,20 @@ mapelfexec(
}
/*
+ * The ELF spec dictates that p_filesz may not be
+ * larger than p_memsz in PT_LOAD segments.
+ */
+ if (phdr->p_filesz > phdr->p_memsz) {
+ error = EINVAL;
+ goto bad;
+ }
+
+ /*
* Keep track of the segment with the lowest starting
* address.
*/
- if (addr < mintmp)
- mintmp = addr;
+ if (addr < minaddr)
+ minaddr = addr;
/*
* Segments need not correspond to page boundaries:
@@ -1707,14 +1733,22 @@ mapelfexec(
if (brksize != NULL && use_brk_lpg &&
zfodsz != 0 && phdr == dataphdrp &&
(prot & PROT_WRITE)) {
- size_t tlen = P2NPHASE((uintptr_t)addr +
+ const size_t tlen = P2NPHASE((uintptr_t)addr +
phdr->p_filesz, PAGESIZE);
if (zfodsz > tlen) {
+ const caddr_t taddr = addr +
+ phdr->p_filesz + tlen;
+
+ /*
+ * Since a hole in the AS large enough
+ * for this object as calculated by
+ * elfsize() is available, we do not
+ * need to fear overflow for 'taddr'.
+ */
curproc->p_brkpageszc =
page_szc(map_pgsz(MAPPGSZ_HEAP,
- curproc, addr + phdr->p_filesz +
- tlen, zfodsz - tlen, 0));
+ curproc, taddr, zfodsz - tlen, 0));
}
}
@@ -1756,7 +1790,12 @@ mapelfexec(
*brkbase = addr + phdr->p_memsz;
}
- *execsz += btopr(phdr->p_memsz);
+ memsz = btopr(phdr->p_memsz);
+ if ((*execsz + memsz) < *execsz) {
+ error = ENOMEM;
+ goto bad;
+ }
+ *execsz += memsz;
break;
case PT_INTERP:
@@ -1808,9 +1847,9 @@ mapelfexec(
phdr = (Phdr *)((caddr_t)phdr + hsize);
}
- if (minaddr != NULL) {
- ASSERT(mintmp != (caddr_t)-1);
- *minaddr = (intptr_t)mintmp;
+ if (minaddrp != NULL) {
+ ASSERT(minaddr != (caddr_t)UINTPTR_MAX);
+ *minaddrp = (uintptr_t)minaddr;
}
if (brkbase != NULL && secflag_enabled(curproc, PROC_SEC_ASLR)) {
@@ -1882,24 +1921,39 @@ elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
return (0);
}
+
/*
* Copy the section data from one vnode to the section of another vnode.
*/
static void
-copy_scn(Shdr *src, vnode_t *src_vp, Shdr *dst, vnode_t *dst_vp, Off *doffset,
- void *buf, size_t size, cred_t *credp, rlim64_t rlimit)
+elf_copy_scn(elf_core_ctx_t *ctx, const Shdr *src, vnode_t *src_vp, Shdr *dst)
{
- ssize_t resid;
- size_t len, n = src->sh_size;
- offset_t off = 0;
+ size_t n = src->sh_size;
+ u_offset_t off = 0;
+ const u_offset_t soff = src->sh_offset;
+ const u_offset_t doff = ctx->ecc_doffset;
+ void *buf = ctx->ecc_buf;
+ vnode_t *dst_vp = ctx->ecc_vp;
+ cred_t *credp = ctx->ecc_credp;
+
+ /* Protect the copy loop below from overflow on the offsets */
+ if (n > OFF_MAX || (n + soff) > OFF_MAX || (n + doff) > OFF_MAX ||
+ (n + soff) < n || (n + doff) < n) {
+ dst->sh_size = 0;
+ dst->sh_offset = 0;
+ return;
+ }
while (n != 0) {
- len = MIN(size, n);
- if (vn_rdwr(UIO_READ, src_vp, buf, len, src->sh_offset + off,
+ const size_t len = MIN(ctx->ecc_bufsz, n);
+ ssize_t resid;
+
+ if (vn_rdwr(UIO_READ, src_vp, buf, (ssize_t)len,
+ (offset_t)(soff + off),
UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid) != 0 ||
- resid >= len ||
- core_write(dst_vp, UIO_SYSSPACE, *doffset + off,
- buf, len - resid, rlimit, credp) != 0) {
+ resid >= len || resid < 0 ||
+ core_write(dst_vp, UIO_SYSSPACE, (offset_t)(doff + off),
+ buf, len - resid, ctx->ecc_rlimit, credp) != 0) {
dst->sh_size = 0;
dst->sh_offset = 0;
return;
@@ -1911,62 +1965,222 @@ copy_scn(Shdr *src, vnode_t *src_vp, Shdr *dst, vnode_t *dst_vp, Off *doffset,
off += len - resid;
}
- *doffset += src->sh_size;
+ ctx->ecc_doffset += src->sh_size;
}
-#ifdef _ELF32_COMPAT
-extern size_t elf_datasz_max;
-#else
-size_t elf_datasz_max = 1 * 1024 * 1024;
-#endif
+/*
+ * Walk sections for a given ELF object, counting (or copying) those of
+ * interest (CTF, symtab, strtab).
+ */
+static uint_t
+elf_process_obj_scns(elf_core_ctx_t *ctx, vnode_t *mvp, caddr_t saddr,
+ Shdr *v, uint_t idx, uint_t remain, shstrtab_t *shstrtab)
+{
+ Ehdr ehdr;
+ const core_content_t content = ctx->ecc_content;
+ cred_t *credp = ctx->ecc_credp;
+ Shdr *ctf = NULL, *symtab = NULL, *strtab = NULL;
+ uintptr_t off = 0;
+ uint_t nshdrs, shstrndx, nphdrs, count = 0;
+ u_offset_t *doffp = &ctx->ecc_doffset;
+ boolean_t ctf_link = B_FALSE;
+ caddr_t shbase;
+ size_t shsize, shstrsize;
+ char *shstrbase;
+
+ if ((content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) == 0) {
+ return (0);
+ }
+
+ if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx, &nphdrs) != 0 ||
+ getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx, &shbase, &shsize,
+ &shstrbase, &shstrsize) != 0) {
+ return (0);
+ }
+
+ /* Starting at index 1 skips SHT_NULL which is expected at index 0 */
+ off = ehdr.e_shentsize;
+ for (uint_t i = 1; i < nshdrs; i++, off += ehdr.e_shentsize) {
+ Shdr *shdr, *symchk = NULL, *strchk;
+ const char *name;
+
+ shdr = (Shdr *)(shbase + off);
+ if (shdr->sh_name >= shstrsize || shdr->sh_type == SHT_NULL)
+ continue;
+
+ name = shstrbase + shdr->sh_name;
+
+ if (ctf == NULL &&
+ (content & CC_CONTENT_CTF) != 0 &&
+ strcmp(name, shstrtab_data[STR_CTF]) == 0) {
+ ctf = shdr;
+ if (ctf->sh_link != 0 && ctf->sh_link < nshdrs) {
+ /* check linked symtab below */
+ symchk = (Shdr *)(shbase +
+ shdr->sh_link * ehdr.e_shentsize);
+ ctf_link = B_TRUE;
+ } else {
+ continue;
+ }
+ } else if (symtab == NULL &&
+ (content & CC_CONTENT_SYMTAB) != 0 &&
+ strcmp(name, shstrtab_data[STR_SYMTAB]) == 0) {
+ symchk = shdr;
+ } else {
+ continue;
+ }
+
+ ASSERT(symchk != NULL);
+ if ((symchk->sh_type != SHT_DYNSYM &&
+ symchk->sh_type != SHT_SYMTAB) ||
+ symchk->sh_link == 0 || symchk->sh_link >= nshdrs) {
+ ctf_link = B_FALSE;
+ continue;
+ }
+ strchk = (Shdr *)(shbase + symchk->sh_link * ehdr.e_shentsize);
+ if (strchk->sh_type != SHT_STRTAB) {
+ ctf_link = B_FALSE;
+ continue;
+ }
+ symtab = symchk;
+ strtab = strchk;
+
+ if (symtab != NULL && ctf != NULL) {
+ /* No other shdrs are of interest at this point */
+ break;
+ }
+ }
+
+ if (ctf != NULL)
+ count += 1;
+ if (symtab != NULL)
+ count += 2;
+ if (v == NULL || count == 0 || count > remain) {
+ count = MIN(count, remain);
+ goto done;
+ }
+
+ /* output CTF section */
+ if (ctf != NULL) {
+ elf_ctx_resize_scratch(ctx, ctf->sh_size);
+
+ v[idx].sh_name = shstrtab_ndx(shstrtab, STR_CTF);
+ v[idx].sh_addr = (Addr)(uintptr_t)saddr;
+ v[idx].sh_type = SHT_PROGBITS;
+ v[idx].sh_addralign = 4;
+ *doffp = roundup(*doffp, v[idx].sh_addralign);
+ v[idx].sh_offset = *doffp;
+ v[idx].sh_size = ctf->sh_size;
+
+ if (ctf_link) {
+ /*
+ * The linked symtab (and strtab) will be output
+ * immediately after this CTF section. Its shdr index
+ * directly follows this one.
+ */
+ v[idx].sh_link = idx + 1;
+ ASSERT(symtab != NULL);
+ } else {
+ v[idx].sh_link = 0;
+ }
+ elf_copy_scn(ctx, ctf, mvp, &v[idx]);
+ idx++;
+ }
+
+ /* output SYMTAB/STRTAB sections */
+ if (symtab != NULL) {
+ uint_t symtab_name, strtab_name;
+
+ elf_ctx_resize_scratch(ctx,
+ MAX(symtab->sh_size, strtab->sh_size));
+
+ if (symtab->sh_type == SHT_DYNSYM) {
+ symtab_name = shstrtab_ndx(shstrtab, STR_DYNSYM);
+ strtab_name = shstrtab_ndx(shstrtab, STR_DYNSTR);
+ } else {
+ symtab_name = shstrtab_ndx(shstrtab, STR_SYMTAB);
+ strtab_name = shstrtab_ndx(shstrtab, STR_STRTAB);
+ }
+
+ v[idx].sh_name = symtab_name;
+ v[idx].sh_type = symtab->sh_type;
+ v[idx].sh_addr = symtab->sh_addr;
+ if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
+ v[idx].sh_addr += (Addr)(uintptr_t)saddr;
+ v[idx].sh_addralign = symtab->sh_addralign;
+ *doffp = roundup(*doffp, v[idx].sh_addralign);
+ v[idx].sh_offset = *doffp;
+ v[idx].sh_size = symtab->sh_size;
+ v[idx].sh_link = idx + 1;
+ v[idx].sh_entsize = symtab->sh_entsize;
+ v[idx].sh_info = symtab->sh_info;
+
+ elf_copy_scn(ctx, symtab, mvp, &v[idx]);
+ idx++;
+
+ v[idx].sh_name = strtab_name;
+ v[idx].sh_type = SHT_STRTAB;
+ v[idx].sh_flags = SHF_STRINGS;
+ v[idx].sh_addr = strtab->sh_addr;
+ if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
+ v[idx].sh_addr += (Addr)(uintptr_t)saddr;
+ v[idx].sh_addralign = strtab->sh_addralign;
+ *doffp = roundup(*doffp, v[idx].sh_addralign);
+ v[idx].sh_offset = *doffp;
+ v[idx].sh_size = strtab->sh_size;
+
+ elf_copy_scn(ctx, strtab, mvp, &v[idx]);
+ idx++;
+ }
+
+done:
+ kmem_free(shstrbase, shstrsize);
+ kmem_free(shbase, shsize);
+ return (count);
+}
/*
- * This function processes mappings that correspond to load objects to
- * examine their respective sections for elfcore(). It's called once with
- * v set to NULL to count the number of sections that we're going to need
- * and then again with v set to some allocated buffer that we fill in with
- * all the section data.
+ * Walk mappings in process address space, examining those which correspond to
+ * loaded objects. It is called twice from elfcore: Once to simply count
+ * relevant sections, and again later to copy those sections once an adequate
+ * buffer has been allocated for the shdr details.
*/
static int
-process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
- Shdr *v, int nv, rlim64_t rlimit, Off *doffsetp, int *nshdrsp)
+elf_process_scns(elf_core_ctx_t *ctx, Shdr *v, uint_t nv, uint_t *nshdrsp)
{
vnode_t *lastvp = NULL;
struct seg *seg;
- int i, j;
- void *data = NULL;
- size_t datasz = 0;
+ uint_t idx = 0, remain;
shstrtab_t shstrtab;
- struct as *as = p->p_as;
+ struct as *as = ctx->ecc_p->p_as;
int error = 0;
- if (v != NULL)
+ ASSERT(AS_WRITE_HELD(as));
+
+ if (v != NULL) {
+ ASSERT(nv != 0);
+
shstrtab_init(&shstrtab);
+ remain = nv;
+ } else {
+ ASSERT(nv == 0);
+
+ /*
+ * The shdrs are being counted, rather than outputting them
+ * into a buffer. Leave room for two entries: the SHT_NULL at
+ * index 0 and the shstrtab at the end.
+ */
+ remain = UINT_MAX - 2;
+ }
- i = 1;
+ /* Per the ELF spec, shdr index 0 is reserved. */
+ idx = 1;
for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
- uint_t prot;
vnode_t *mvp;
void *tmp = NULL;
- caddr_t saddr = seg->s_base;
- caddr_t naddr;
- caddr_t eaddr;
+ caddr_t saddr = seg->s_base, naddr, eaddr;
size_t segsize;
-
- Ehdr ehdr;
- int nshdrs, shstrndx, nphdrs;
- caddr_t shbase;
- ssize_t shsize;
- char *shstrbase;
- ssize_t shstrsize;
-
- Shdr *shdr;
- const char *name;
- size_t sz;
- uintptr_t off;
-
- int ctf_ndx = 0;
- int symtab_ndx = 0;
+ uint_t count, prot;
/*
* Since we're just looking for text segments of load
@@ -1992,222 +2206,51 @@ process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC)
continue;
- if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx,
- &nphdrs) != 0 ||
- getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx,
- &shbase, &shsize, &shstrbase, &shstrsize) != 0)
- continue;
-
- off = ehdr.e_shentsize;
- for (j = 1; j < nshdrs; j++, off += ehdr.e_shentsize) {
- Shdr *symtab = NULL, *strtab;
-
- shdr = (Shdr *)(shbase + off);
-
- if (shdr->sh_name >= shstrsize)
- continue;
-
- name = shstrbase + shdr->sh_name;
-
- if (strcmp(name, shstrtab_data[STR_CTF]) == 0) {
- if ((content & CC_CONTENT_CTF) == 0 ||
- ctf_ndx != 0)
- continue;
-
- if (shdr->sh_link > 0 &&
- shdr->sh_link < nshdrs) {
- symtab = (Shdr *)(shbase +
- shdr->sh_link * ehdr.e_shentsize);
- }
-
- if (v != NULL && i < nv - 1) {
- if (shdr->sh_size > datasz &&
- shdr->sh_size <= elf_datasz_max) {
- if (data != NULL)
- kmem_free(data, datasz);
+ count = elf_process_obj_scns(ctx, mvp, saddr, v, idx, remain,
+ &shstrtab);
- datasz = shdr->sh_size;
- data = kmem_alloc(datasz,
- KM_SLEEP);
- }
-
- v[i].sh_name = shstrtab_ndx(&shstrtab,
- STR_CTF);
- v[i].sh_addr = (Addr)(uintptr_t)saddr;
- v[i].sh_type = SHT_PROGBITS;
- v[i].sh_addralign = 4;
- *doffsetp = roundup(*doffsetp,
- v[i].sh_addralign);
- v[i].sh_offset = *doffsetp;
- v[i].sh_size = shdr->sh_size;
- if (symtab == NULL) {
- v[i].sh_link = 0;
- } else if (symtab->sh_type ==
- SHT_SYMTAB &&
- symtab_ndx != 0) {
- v[i].sh_link =
- symtab_ndx;
- } else {
- v[i].sh_link = i + 1;
- }
-
- copy_scn(shdr, mvp, &v[i], vp,
- doffsetp, data, datasz, credp,
- rlimit);
- }
-
- ctf_ndx = i++;
-
- /*
- * We've already dumped the symtab.
- */
- if (symtab != NULL &&
- symtab->sh_type == SHT_SYMTAB &&
- symtab_ndx != 0)
- continue;
-
- } else if (strcmp(name,
- shstrtab_data[STR_SYMTAB]) == 0) {
- if ((content & CC_CONTENT_SYMTAB) == 0 ||
- symtab != 0)
- continue;
-
- symtab = shdr;
- }
-
- if (symtab != NULL) {
- if ((symtab->sh_type != SHT_DYNSYM &&
- symtab->sh_type != SHT_SYMTAB) ||
- symtab->sh_link == 0 ||
- symtab->sh_link >= nshdrs)
- continue;
-
- strtab = (Shdr *)(shbase +
- symtab->sh_link * ehdr.e_shentsize);
-
- if (strtab->sh_type != SHT_STRTAB)
- continue;
-
- if (v != NULL && i < nv - 2) {
- sz = MAX(symtab->sh_size,
- strtab->sh_size);
- if (sz > datasz &&
- sz <= elf_datasz_max) {
- if (data != NULL)
- kmem_free(data, datasz);
-
- datasz = sz;
- data = kmem_alloc(datasz,
- KM_SLEEP);
- }
-
- if (symtab->sh_type == SHT_DYNSYM) {
- v[i].sh_name = shstrtab_ndx(
- &shstrtab, STR_DYNSYM);
- v[i + 1].sh_name = shstrtab_ndx(
- &shstrtab, STR_DYNSTR);
- } else {
- v[i].sh_name = shstrtab_ndx(
- &shstrtab, STR_SYMTAB);
- v[i + 1].sh_name = shstrtab_ndx(
- &shstrtab, STR_STRTAB);
- }
-
- v[i].sh_type = symtab->sh_type;
- v[i].sh_addr = symtab->sh_addr;
- if (ehdr.e_type == ET_DYN ||
- v[i].sh_addr == 0)
- v[i].sh_addr +=
- (Addr)(uintptr_t)saddr;
- v[i].sh_addralign =
- symtab->sh_addralign;
- *doffsetp = roundup(*doffsetp,
- v[i].sh_addralign);
- v[i].sh_offset = *doffsetp;
- v[i].sh_size = symtab->sh_size;
- v[i].sh_link = i + 1;
- v[i].sh_entsize = symtab->sh_entsize;
- v[i].sh_info = symtab->sh_info;
-
- copy_scn(symtab, mvp, &v[i], vp,
- doffsetp, data, datasz, credp,
- rlimit);
-
- v[i + 1].sh_type = SHT_STRTAB;
- v[i + 1].sh_flags = SHF_STRINGS;
- v[i + 1].sh_addr = symtab->sh_addr;
- if (ehdr.e_type == ET_DYN ||
- v[i + 1].sh_addr == 0)
- v[i + 1].sh_addr +=
- (Addr)(uintptr_t)saddr;
- v[i + 1].sh_addralign =
- strtab->sh_addralign;
- *doffsetp = roundup(*doffsetp,
- v[i + 1].sh_addralign);
- v[i + 1].sh_offset = *doffsetp;
- v[i + 1].sh_size = strtab->sh_size;
-
- copy_scn(strtab, mvp, &v[i + 1], vp,
- doffsetp, data, datasz, credp,
- rlimit);
- }
-
- if (symtab->sh_type == SHT_SYMTAB)
- symtab_ndx = i;
- i += 2;
- }
- }
-
- kmem_free(shstrbase, shstrsize);
- kmem_free(shbase, shsize);
+ ASSERT(count <= remain);
+ ASSERT(v == NULL || (idx + count) < nv);
+ remain -= count;
+ idx += count;
lastvp = mvp;
}
if (v == NULL) {
- if (i == 1)
+ if (idx == 1) {
*nshdrsp = 0;
- else
- *nshdrsp = i + 1;
- goto done;
+ } else {
+ /* Include room for the shrstrtab at the end */
+ *nshdrsp = idx + 1;
+ }
+ return (0);
}
- if (i != nv - 1) {
+ if (idx != nv - 1) {
cmn_err(CE_WARN, "elfcore: core dump failed for "
- "process %d; address space is changing", p->p_pid);
- error = EIO;
- goto done;
+ "process %d; address space is changing",
+ ctx->ecc_p->p_pid);
+ return (EIO);
}
- v[i].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
- v[i].sh_size = shstrtab_size(&shstrtab);
- v[i].sh_addralign = 1;
- *doffsetp = roundup(*doffsetp, v[i].sh_addralign);
- v[i].sh_offset = *doffsetp;
- v[i].sh_flags = SHF_STRINGS;
- v[i].sh_type = SHT_STRTAB;
-
- if (v[i].sh_size > datasz) {
- if (data != NULL)
- kmem_free(data, datasz);
-
- datasz = v[i].sh_size;
- data = kmem_alloc(datasz,
- KM_SLEEP);
+ v[idx].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
+ v[idx].sh_size = shstrtab_size(&shstrtab);
+ v[idx].sh_addralign = 1;
+ v[idx].sh_offset = ctx->ecc_doffset;
+ v[idx].sh_flags = SHF_STRINGS;
+ v[idx].sh_type = SHT_STRTAB;
+
+ elf_ctx_resize_scratch(ctx, v[idx].sh_size);
+ VERIFY3U(ctx->ecc_bufsz, >=, v[idx].sh_size);
+ shstrtab_dump(&shstrtab, ctx->ecc_buf);
+
+ error = core_write(ctx->ecc_vp, UIO_SYSSPACE, ctx->ecc_doffset,
+ ctx->ecc_buf, v[idx].sh_size, ctx->ecc_rlimit, ctx->ecc_credp);
+ if (error == 0) {
+ ctx->ecc_doffset += v[idx].sh_size;
}
- shstrtab_dump(&shstrtab, data);
-
- if ((error = core_write(vp, UIO_SYSSPACE, *doffsetp,
- data, v[i].sh_size, rlimit, credp)) != 0)
- goto done;
-
- *doffsetp += v[i].sh_size;
-
-done:
- if (data != NULL)
- kmem_free(data, datasz);
-
return (error);
}
@@ -2215,27 +2258,30 @@ int
elfcore(vnode_t *vp, proc_t *p, cred_t *credp, rlim64_t rlimit, int sig,
core_content_t content)
{
- offset_t poffset, soffset;
- Off doffset;
- int error, i, nphdrs, nshdrs;
- int overflow = 0;
+ u_offset_t poffset, soffset, doffset;
+ int error;
+ uint_t i, nphdrs, nshdrs;
struct seg *seg;
struct as *as = p->p_as;
- union {
- Ehdr ehdr;
- Phdr phdr[1];
- Shdr shdr[1];
- } *bigwad;
- size_t bigsize;
- size_t phdrsz, shdrsz;
+ void *bigwad;
+ size_t bigsize, phdrsz, shdrsz;
Ehdr *ehdr;
- Phdr *v;
- caddr_t brkbase;
- size_t brksize;
- caddr_t stkbase;
- size_t stksize;
- int ntries = 0;
+ Phdr *phdr;
+ Shdr shdr0;
+ caddr_t brkbase, stkbase;
+ size_t brksize, stksize;
+ boolean_t overflowed = B_FALSE, retried = B_FALSE;
klwp_t *lwp = ttolwp(curthread);
+ elf_core_ctx_t ctx = {
+ .ecc_vp = vp,
+ .ecc_p = p,
+ .ecc_credp = credp,
+ .ecc_rlimit = rlimit,
+ .ecc_content = content,
+ .ecc_doffset = 0,
+ .ecc_buf = NULL,
+ .ecc_bufsz = 0
+ };
top:
/*
@@ -2253,28 +2299,32 @@ top:
*/
nshdrs = 0;
if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) {
- (void) process_scns(content, p, credp, NULL, NULL, NULL, 0,
- NULL, &nshdrs);
+ VERIFY0(elf_process_scns(&ctx, NULL, 0, &nshdrs));
}
AS_LOCK_EXIT(as);
- ASSERT(nshdrs == 0 || nshdrs > 1);
-
/*
- * The core file contents may required zero section headers, but if
+ * The core file contents may require zero section headers, but if
* we overflow the 16 bits allotted to the program header count in
* the ELF header, we'll need that program header at index zero.
*/
- if (nshdrs == 0 && nphdrs >= PN_XNUM)
+ if (nshdrs == 0 && nphdrs >= PN_XNUM) {
nshdrs = 1;
+ }
+ /*
+ * Allocate a buffer which is sized adequately to hold the ehdr, phdrs
+ * or shdrs needed to produce the core file. It is used for the three
+ * tasks sequentially, not simultaneously, so it does not need space
+ * for all three data at once, only the largest one.
+ */
+ VERIFY(nphdrs >= 2);
phdrsz = nphdrs * sizeof (Phdr);
shdrsz = nshdrs * sizeof (Shdr);
-
- bigsize = MAX(sizeof (*bigwad), MAX(phdrsz, shdrsz));
+ bigsize = MAX(sizeof (Ehdr), MAX(phdrsz, shdrsz));
bigwad = kmem_alloc(bigsize, KM_SLEEP);
- ehdr = &bigwad->ehdr;
+ ehdr = (Ehdr *)bigwad;
bzero(ehdr, sizeof (*ehdr));
ehdr->e_ident[EI_MAG0] = ELFMAG0;
@@ -2310,6 +2360,11 @@ top:
#endif /* !defined(_LP64) || defined(_ELF32_COMPAT) */
+ poffset = sizeof (Ehdr);
+ soffset = sizeof (Ehdr) + phdrsz;
+ doffset = sizeof (Ehdr) + phdrsz + shdrsz;
+ bzero(&shdr0, sizeof (shdr0));
+
/*
* If the count of program headers or section headers or the index
* of the section string table can't fit in the mere 16 bits
@@ -2317,50 +2372,52 @@ top:
* extended formats and put the real values in the section header
* as index 0.
*/
- ehdr->e_version = EV_CURRENT;
- ehdr->e_ehsize = sizeof (Ehdr);
-
- if (nphdrs >= PN_XNUM)
+ if (nphdrs >= PN_XNUM) {
ehdr->e_phnum = PN_XNUM;
- else
+ shdr0.sh_info = nphdrs;
+ } else {
ehdr->e_phnum = (unsigned short)nphdrs;
-
- ehdr->e_phoff = sizeof (Ehdr);
- ehdr->e_phentsize = sizeof (Phdr);
+ }
if (nshdrs > 0) {
- if (nshdrs >= SHN_LORESERVE)
+ if (nshdrs >= SHN_LORESERVE) {
ehdr->e_shnum = 0;
- else
+ shdr0.sh_size = nshdrs;
+ } else {
ehdr->e_shnum = (unsigned short)nshdrs;
+ }
- if (nshdrs - 1 >= SHN_LORESERVE)
+ if (nshdrs - 1 >= SHN_LORESERVE) {
ehdr->e_shstrndx = SHN_XINDEX;
- else
+ shdr0.sh_link = nshdrs - 1;
+ } else {
ehdr->e_shstrndx = (unsigned short)(nshdrs - 1);
+ }
- ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * nphdrs;
+ ehdr->e_shoff = soffset;
ehdr->e_shentsize = sizeof (Shdr);
}
+ ehdr->e_version = EV_CURRENT;
+ ehdr->e_ehsize = sizeof (Ehdr);
+ ehdr->e_phoff = poffset;
+ ehdr->e_phentsize = sizeof (Phdr);
+
if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr,
- sizeof (Ehdr), rlimit, credp))
+ sizeof (Ehdr), rlimit, credp)) {
goto done;
+ }
- poffset = sizeof (Ehdr);
- soffset = sizeof (Ehdr) + phdrsz;
- doffset = sizeof (Ehdr) + phdrsz + shdrsz;
-
- v = &bigwad->phdr[0];
- bzero(v, phdrsz);
+ phdr = (Phdr *)bigwad;
+ bzero(phdr, phdrsz);
- setup_old_note_header(&v[0], p);
- v[0].p_offset = doffset = roundup(doffset, sizeof (Word));
- doffset += v[0].p_filesz;
+ setup_old_note_header(&phdr[0], p);
+ phdr[0].p_offset = doffset = roundup(doffset, sizeof (Word));
+ doffset += phdr[0].p_filesz;
- setup_note_header(&v[1], p);
- v[1].p_offset = doffset = roundup(doffset, sizeof (Word));
- doffset += v[1].p_filesz;
+ setup_note_header(&phdr[1], p);
+ phdr[1].p_offset = doffset = roundup(doffset, sizeof (Word));
+ doffset += phdr[1].p_filesz;
mutex_enter(&p->p_lock);
@@ -2392,21 +2449,23 @@ top:
prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
- if ((size = (size_t)(naddr - saddr)) == 0)
- continue;
- if (i == nphdrs) {
- overflow++;
+ if ((size = (size_t)(naddr - saddr)) == 0) {
+ ASSERT(tmp == NULL);
continue;
+ } else if (i == nphdrs) {
+ pr_getprot_done(&tmp);
+ overflowed = B_TRUE;
+ break;
}
- v[i].p_type = PT_LOAD;
- v[i].p_vaddr = (Addr)(uintptr_t)saddr;
- v[i].p_memsz = size;
+ phdr[i].p_type = PT_LOAD;
+ phdr[i].p_vaddr = (Addr)(uintptr_t)saddr;
+ phdr[i].p_memsz = size;
if (prot & PROT_READ)
- v[i].p_flags |= PF_R;
+ phdr[i].p_flags |= PF_R;
if (prot & PROT_WRITE)
- v[i].p_flags |= PF_W;
+ phdr[i].p_flags |= PF_W;
if (prot & PROT_EXEC)
- v[i].p_flags |= PF_X;
+ phdr[i].p_flags |= PF_X;
/*
* Figure out which mappings to include in the core.
@@ -2468,20 +2527,23 @@ top:
}
doffset = roundup(doffset, sizeof (Word));
- v[i].p_offset = doffset;
- v[i].p_filesz = size;
+ phdr[i].p_offset = doffset;
+ phdr[i].p_filesz = size;
doffset += size;
exclude:
i++;
}
- ASSERT(tmp == NULL);
+ VERIFY(tmp == NULL);
+ if (overflowed)
+ break;
}
AS_LOCK_EXIT(as);
- if (overflow || i != nphdrs) {
- if (ntries++ == 0) {
+ if (overflowed || i != nphdrs) {
+ if (!retried) {
+ retried = B_TRUE;
+ overflowed = B_FALSE;
kmem_free(bigwad, bigsize);
- overflow = 0;
goto top;
}
cmn_err(CE_WARN, "elfcore: core dump failed for "
@@ -2491,23 +2553,25 @@ exclude:
}
if ((error = core_write(vp, UIO_SYSSPACE, poffset,
- v, phdrsz, rlimit, credp)) != 0)
+ phdr, phdrsz, rlimit, credp)) != 0) {
goto done;
+ }
- if ((error = write_old_elfnotes(p, sig, vp, v[0].p_offset, rlimit,
- credp)) != 0)
+ if ((error = write_old_elfnotes(p, sig, vp, phdr[0].p_offset, rlimit,
+ credp)) != 0) {
goto done;
-
- if ((error = write_elfnotes(p, sig, vp, v[1].p_offset, rlimit,
- credp, content)) != 0)
+ }
+ if ((error = write_elfnotes(p, sig, vp, phdr[1].p_offset, rlimit,
+ credp, content)) != 0) {
goto done;
+ }
for (i = 2; i < nphdrs; i++) {
prkillinfo_t killinfo;
sigqueue_t *sq;
int sig, j;
- if (v[i].p_filesz == 0)
+ if (phdr[i].p_filesz == 0)
continue;
/*
@@ -2518,8 +2582,8 @@ exclude:
* this from mappings that were excluded due to the core file
* content settings.
*/
- if ((error = core_seg(p, vp, v[i].p_offset,
- (caddr_t)(uintptr_t)v[i].p_vaddr, v[i].p_filesz,
+ if ((error = core_seg(p, vp, phdr[i].p_offset,
+ (caddr_t)(uintptr_t)phdr[i].p_vaddr, phdr[i].p_filesz,
rlimit, credp)) == 0) {
continue;
}
@@ -2532,14 +2596,14 @@ exclude:
* bytes. This undocumented interface will let us
* understand the nature of the failure.
*/
- (void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
+ (void) core_write(vp, UIO_SYSSPACE, phdr[i].p_offset,
&error, sizeof (error), rlimit, credp);
- v[i].p_filesz = 0;
- v[i].p_flags |= PF_SUNW_FAILURE;
+ phdr[i].p_filesz = 0;
+ phdr[i].p_flags |= PF_SUNW_FAILURE;
if ((error = core_write(vp, UIO_SYSSPACE,
- poffset + sizeof (v[i]) * i, &v[i], sizeof (v[i]),
- rlimit, credp)) != 0)
+ poffset + sizeof (Phdr) * i, &phdr[i],
+ sizeof (Phdr), rlimit, credp)) != 0)
goto done;
continue;
@@ -2581,15 +2645,15 @@ exclude:
}
#endif
- (void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
+ (void) core_write(vp, UIO_SYSSPACE, phdr[i].p_offset,
&killinfo, sizeof (killinfo), rlimit, credp);
/*
* For the segment on which we took the signal, indicate that
* its data now refers to a siginfo.
*/
- v[i].p_filesz = 0;
- v[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED |
+ phdr[i].p_filesz = 0;
+ phdr[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED |
PF_SUNW_SIGINFO;
/*
@@ -2597,50 +2661,46 @@ exclude:
* is due to a signal.
*/
for (j = i + 1; j < nphdrs; j++) {
- v[j].p_filesz = 0;
- v[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED;
+ phdr[j].p_filesz = 0;
+ phdr[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED;
}
/*
* Finally, write out our modified program headers.
*/
if ((error = core_write(vp, UIO_SYSSPACE,
- poffset + sizeof (v[i]) * i, &v[i],
- sizeof (v[i]) * (nphdrs - i), rlimit, credp)) != 0)
+ poffset + sizeof (Phdr) * i, &phdr[i],
+ sizeof (Phdr) * (nphdrs - i), rlimit, credp)) != 0) {
goto done;
+ }
break;
}
if (nshdrs > 0) {
- bzero(&bigwad->shdr[0], shdrsz);
-
- if (nshdrs >= SHN_LORESERVE)
- bigwad->shdr[0].sh_size = nshdrs;
-
- if (nshdrs - 1 >= SHN_LORESERVE)
- bigwad->shdr[0].sh_link = nshdrs - 1;
-
- if (nphdrs >= PN_XNUM)
- bigwad->shdr[0].sh_info = nphdrs;
+ Shdr *shdr = (Shdr *)bigwad;
+ bzero(shdr, shdrsz);
if (nshdrs > 1) {
+ ctx.ecc_doffset = doffset;
AS_LOCK_ENTER(as, RW_WRITER);
- if ((error = process_scns(content, p, credp, vp,
- &bigwad->shdr[0], nshdrs, rlimit, &doffset,
- NULL)) != 0) {
- AS_LOCK_EXIT(as);
+ error = elf_process_scns(&ctx, shdr, nshdrs, NULL);
+ AS_LOCK_EXIT(as);
+ if (error != 0) {
goto done;
}
- AS_LOCK_EXIT(as);
}
+ /* Copy any extended format data destined for the first shdr */
+ bcopy(&shdr0, shdr, sizeof (shdr0));
- if ((error = core_write(vp, UIO_SYSSPACE, soffset,
- &bigwad->shdr[0], shdrsz, rlimit, credp)) != 0)
- goto done;
+ error = core_write(vp, UIO_SYSSPACE, soffset, shdr, shdrsz,
+ rlimit, credp);
}
done:
+ if (ctx.ecc_bufsz != 0) {
+ kmem_free(ctx.ecc_buf, ctx.ecc_bufsz);
+ }
kmem_free(bigwad, bigsize);
return (error);
}
@@ -2665,7 +2725,7 @@ static struct modlexec modlexec = {
#ifdef _LP64
extern int elf32exec(vnode_t *vp, execa_t *uap, uarg_t *args,
- intpdata_t *idatap, int level, long *execsz,
+ intpdata_t *idatap, int level, size_t *execsz,
int setid, caddr_t exec_file, cred_t *cred,
int *brand_action);
extern int elf32core(vnode_t *vp, proc_t *p, cred_t *credp,
diff --git a/usr/src/uts/common/exec/elf/elf_impl.h b/usr/src/uts/common/exec/elf/elf_impl.h
index 010d5e6256..504cf84dd2 100644
--- a/usr/src/uts/common/exec/elf/elf_impl.h
+++ b/usr/src/uts/common/exec/elf/elf_impl.h
@@ -22,12 +22,13 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
#ifndef _ELF_ELF_IMPL_H
#define _ELF_ELF_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -71,6 +72,17 @@ typedef struct {
char name[8];
} Note;
+typedef struct {
+ vnode_t *ecc_vp;
+ proc_t *ecc_p;
+ cred_t *ecc_credp;
+ rlim64_t ecc_rlimit;
+ core_content_t ecc_content;
+ u_offset_t ecc_doffset;
+ void *ecc_buf;
+ size_t ecc_bufsz;
+} elf_core_ctx_t;
+
#ifdef _ELF32_COMPAT
/*
* These are defined only for the 32-bit compatibility
@@ -79,6 +91,7 @@ typedef struct {
#define elfexec elf32exec
#define elfnote elf32note
#define elfcore elf32core
+#define elfreadhdr elf32readhdr
#define mapexec_brand mapexec32_brand
#define setup_note_header setup_note_header32
#define write_elfnotes write_elfnotes32
diff --git a/usr/src/uts/common/exec/intp/intp.c b/usr/src/uts/common/exec/intp/intp.c
index 512cab2b66..388d913ea0 100644
--- a/usr/src/uts/common/exec/intp/intp.c
+++ b/usr/src/uts/common/exec/intp/intp.c
@@ -22,7 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
- * Copyright 2016, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -56,7 +56,7 @@
#include <sys/modctl.h>
extern int intpexec(struct vnode *, struct execa *, struct uarg *,
- struct intpdata *, int, long *, int, caddr_t, struct cred *, int *);
+ struct intpdata *, int, size_t *, int, caddr_t, struct cred *, int *);
static struct execsw esw = {
intpmagicstr,
@@ -196,7 +196,7 @@ intpexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred,
diff --git a/usr/src/uts/common/exec/java/java.c b/usr/src/uts/common/exec/java/java.c
index 5170fda5cb..a61a6f105f 100644
--- a/usr/src/uts/common/exec/java/java.c
+++ b/usr/src/uts/common/exec/java/java.c
@@ -21,7 +21,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2015, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -85,7 +85,7 @@ char *jexec_arg = "-jar";
/*ARGSUSED3*/
static int
javaexec(vnode_t *vp, struct execa *uap, struct uarg *args,
- struct intpdata *idatap, int level, long *execsz, int setid,
+ struct intpdata *idatap, int level, size_t *execsz, int setid,
caddr_t execfile, cred_t *cred, int *brand_action)
{
struct intpdata idata;
diff --git a/usr/src/uts/common/exec/shbin/shbin.c b/usr/src/uts/common/exec/shbin/shbin.c
index 016d87b9ef..7b653a4c98 100644
--- a/usr/src/uts/common/exec/shbin/shbin.c
+++ b/usr/src/uts/common/exec/shbin/shbin.c
@@ -22,7 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2015, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/types.h>
@@ -55,7 +55,7 @@ shbinexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred,
@@ -159,7 +159,7 @@ shbinexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred,
diff --git a/usr/src/uts/common/fs/proc/prioctl.c b/usr/src/uts/common/fs/proc/prioctl.c
index 470c66362b..6aabe28200 100644
--- a/usr/src/uts/common/fs/proc/prioctl.c
+++ b/usr/src/uts/common/fs/proc/prioctl.c
@@ -22,7 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -943,7 +943,7 @@ startover:
case PIOCNMAP: /* get number of memory mappings */
{
- int n;
+ uint_t n;
struct as *as = p->p_as;
if ((p->p_flag & SSYS) || as == &kas)
@@ -956,7 +956,7 @@ startover:
mutex_enter(&p->p_lock);
}
prunlock(pnp);
- if (copyout(&n, cmaddr, sizeof (int)))
+ if (copyout(&n, cmaddr, sizeof (uint_t)))
error = EFAULT;
break;
}
@@ -2562,7 +2562,7 @@ startover:
case PIOCNMAP: /* get number of memory mappings */
{
- int n;
+ uint_t n;
struct as *as = p->p_as;
if ((p->p_flag & SSYS) || as == &kas)
@@ -2575,7 +2575,7 @@ startover:
mutex_enter(&p->p_lock);
}
prunlock(pnp);
- if (copyout(&n, cmaddr, sizeof (int)))
+ if (copyout(&n, cmaddr, sizeof (uint_t)))
error = EFAULT;
break;
}
diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c
index 2062970885..3b4a7f36d0 100644
--- a/usr/src/uts/common/fs/proc/prsubr.c
+++ b/usr/src/uts/common/fs/proc/prsubr.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -1403,10 +1403,10 @@ prgetaction32(proc_t *p, user_t *up, uint_t sig, struct sigaction32 *sp)
/*
* Count the number of segments in this process's address space.
*/
-int
+uint_t
prnsegs(struct as *as, int reserved)
{
- int n = 0;
+ uint_t n = 0;
struct seg *seg;
ASSERT(as != &kas && AS_WRITE_HELD(as));
@@ -1423,8 +1423,21 @@ prnsegs(struct as *as, int reserved)
for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
(void) pr_getprot(seg, reserved, &tmp,
&saddr, &naddr, eaddr);
- if (saddr != naddr)
+ if (saddr != naddr) {
n++;
+ /*
+ * prnsegs() was formerly designated to return
+ * an 'int' despite having no ability or use
+ * for negative results. As part of changing
+ * it to 'uint_t', keep the old effective limit
+ * of INT_MAX in place.
+ */
+ if (n == INT_MAX) {
+ pr_getprot_done(&tmp);
+ ASSERT(tmp == NULL);
+ return (n);
+ }
+ }
}
ASSERT(tmp == NULL);
diff --git a/usr/src/uts/common/os/brand.c b/usr/src/uts/common/os/brand.c
index 62c3bbe2d6..60e8150a0d 100644
--- a/usr/src/uts/common/os/brand.c
+++ b/usr/src/uts/common/os/brand.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/kmem.h>
@@ -671,9 +671,9 @@ restoreexecenv(struct execenv *ep, stack_t *sp)
/*ARGSUSED*/
int
brand_solaris_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args,
- intpdata_t *idatap, int level, long *execsz, int setid, caddr_t exec_file,
- cred_t *cred, int *brand_action, struct brand *pbrand, char *bname,
- char *brandlib, char *brandlib32)
+ intpdata_t *idatap, int level, size_t *execsz, int setid,
+ caddr_t exec_file, cred_t *cred, int *brand_action, struct brand *pbrand,
+ char *bname, char *brandlib, char *brandlib32)
{
vnode_t *nvp;
diff --git a/usr/src/uts/common/os/core.c b/usr/src/uts/common/os/core.c
index 437f26e6e0..a147b1cf0f 100644
--- a/usr/src/uts/common/os/core.c
+++ b/usr/src/uts/common/os/core.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016, Joyent Inc.
+ * Copyright 2019 Joyent Inc.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
@@ -795,7 +795,7 @@ clock_t core_delay_usec = 10000;
* using core_write() below, and so it has the same failure semantics.
*/
int
-core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
+core_seg(proc_t *p, vnode_t *vp, u_offset_t offset, caddr_t addr, size_t size,
rlim64_t rlimit, cred_t *credp)
{
caddr_t eaddr;
@@ -803,6 +803,11 @@ core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
size_t len;
int err = 0;
+ if (offset > OFF_MAX || offset + size > OFF_MAX ||
+ offset + size < offset) {
+ return (EOVERFLOW);
+ }
+
eaddr = addr + size;
for (base = addr; base < eaddr; base += len) {
len = eaddr - base;
@@ -843,15 +848,20 @@ core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
* unexpectedly returns zero but no progress has been made, we return ENOSPC.
*/
int
-core_write(vnode_t *vp, enum uio_seg segflg, offset_t offset,
+core_write(vnode_t *vp, enum uio_seg segflg, u_offset_t offset,
const void *buf, size_t len, rlim64_t rlimit, cred_t *credp)
{
ssize_t resid = len;
int error = 0;
+ if (offset > OFF_MAX || offset + len > OFF_MAX ||
+ offset + len < offset) {
+ return (EOVERFLOW);
+ }
+
while (len != 0) {
- error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len, offset,
- segflg, 0, rlimit, credp, &resid);
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len,
+ (offset_t)offset, segflg, 0, rlimit, credp, &resid);
if (error != 0)
break;
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index 500bd1ecb6..24b6f0e2eb 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -26,7 +26,7 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/*
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/types.h>
@@ -144,7 +144,7 @@ exec_common(const char *fname, const char **argp, const char **envp,
proc_t *p = ttoproc(curthread);
klwp_t *lwp = ttolwp(curthread);
struct user *up = PTOU(p);
- long execsz; /* temporary count of exec size */
+ size_t execsz; /* temporary count of exec size */
int i;
int error;
char exec_file[MAXCOMLEN+1];
@@ -603,7 +603,7 @@ gexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
caddr_t exec_file,
struct cred *cred,
int *brand_action)
@@ -1491,7 +1491,7 @@ noexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred)
diff --git a/usr/src/uts/common/sys/brand.h b/usr/src/uts/common/sys/brand.h
index e33de24757..df22f492bf 100644
--- a/usr/src/uts/common/sys/brand.h
+++ b/usr/src/uts/common/sys/brand.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_BRAND_H
@@ -172,10 +172,9 @@ struct brand_ops {
void (*b_forklwp)(klwp_t *, klwp_t *);
void (*b_freelwp)(klwp_t *);
void (*b_lwpexit)(klwp_t *);
- int (*b_elfexec)(struct vnode *vp, struct execa *uap,
- struct uarg *args, struct intpdata *idata, int level,
- long *execsz, int setid, caddr_t exec_file,
- struct cred *cred, int *brand_action);
+ int (*b_elfexec)(struct vnode *, struct execa *, struct uarg *,
+ struct intpdata *, int, size_t *, int, caddr_t, struct cred *,
+ int *);
void (*b_sigset_native_to_brand)(sigset_t *);
void (*b_sigset_brand_to_native)(sigset_t *);
void (*b_sigfd_translate)(k_siginfo_t *);
@@ -258,7 +257,7 @@ extern int brand_solaris_cmd(int, uintptr_t, uintptr_t, uintptr_t,
extern void brand_solaris_copy_procdata(proc_t *, proc_t *,
struct brand *);
extern int brand_solaris_elfexec(vnode_t *, execa_t *, uarg_t *,
- intpdata_t *, int, long *, int, caddr_t, cred_t *, int *,
+ intpdata_t *, int, size_t *, int, caddr_t, cred_t *, int *,
struct brand *, char *, char *, char *);
extern void brand_solaris_exec(struct brand *);
extern int brand_solaris_fini(char **, struct modlinkage *,
diff --git a/usr/src/uts/common/sys/exec.h b/usr/src/uts/common/sys/exec.h
index 3b7ac5aa7c..12115b7e27 100644
--- a/usr/src/uts/common/sys/exec.h
+++ b/usr/src/uts/common/sys/exec.h
@@ -27,7 +27,7 @@
/* All Rights Reserved */
/*
- * Copyright 2016, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_EXEC_H
@@ -83,7 +83,7 @@ typedef struct uarg {
ssize_t arglen;
char *fname;
char *pathname;
- ssize_t auxsize;
+ size_t auxsize;
caddr_t stackend;
size_t stk_align;
size_t stk_size;
@@ -182,7 +182,7 @@ struct execsw {
int exec_maglen;
int (*exec_func)(struct vnode *vp, struct execa *uap,
struct uarg *args, struct intpdata *idata, int level,
- long *execsz, int setid, caddr_t exec_file,
+ size_t *execsz, int setid, caddr_t exec_file,
struct cred *cred, int *brand_action);
int (*exec_core)(struct vnode *vp, struct proc *p,
struct cred *cred, rlim64_t rlimit, int sig,
@@ -220,7 +220,7 @@ extern int exece(const char *fname, const char **argp, const char **envp);
extern int exec_common(const char *fname, const char **argp,
const char **envp, int brand_action);
extern int gexec(vnode_t **vp, struct execa *uap, struct uarg *args,
- struct intpdata *idata, int level, long *execsz, caddr_t exec_file,
+ struct intpdata *idata, int level, size_t *execsz, caddr_t exec_file,
struct cred *cred, int *brand_action);
extern struct execsw *allocate_execsw(char *name, char *magic,
size_t magic_size);
@@ -246,32 +246,32 @@ extern void exec_set_sp(size_t);
* when compiling the 32-bit compatability elf code in the elfexec module.
*/
extern int elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
extern int mapexec_brand(vnode_t *, uarg_t *, Ehdr *, Addr *,
intptr_t *, caddr_t, char **, caddr_t *, caddr_t *, size_t *,
uintptr_t *, uintptr_t *);
-extern int elfreadhdr(vnode_t *, cred_t *, Ehdr *, int *, caddr_t *,
- ssize_t *);
+extern int elfreadhdr(vnode_t *, cred_t *, Ehdr *, uint_t *, caddr_t *,
+ size_t *);
#endif /* !_ELF32_COMPAT */
#if defined(_LP64)
extern int elf32exec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
extern int mapexec32_brand(vnode_t *, uarg_t *, Elf32_Ehdr *, Elf32_Addr *,
intptr_t *, caddr_t, char **, caddr_t *, caddr_t *, size_t *,
uintptr_t *, uintptr_t *);
-extern int elf32readhdr(vnode_t *, cred_t *, Elf32_Ehdr *, int *, caddr_t *,
- ssize_t *);
+extern int elf32readhdr(vnode_t *, cred_t *, Elf32_Ehdr *, uint_t *, caddr_t *,
+ size_t *);
#endif /* _LP64 */
/*
* Utility functions for exec module core routines:
*/
-extern int core_seg(proc_t *, vnode_t *, offset_t, caddr_t,
- size_t, rlim64_t, cred_t *);
+extern int core_seg(proc_t *, vnode_t *, u_offset_t, caddr_t, size_t,
+ rlim64_t, cred_t *);
-extern int core_write(vnode_t *, enum uio_seg, offset_t,
- const void *, size_t, rlim64_t, cred_t *);
+extern int core_write(vnode_t *, enum uio_seg, u_offset_t, const void *,
+ size_t, rlim64_t, cred_t *);
/* a.out stuff */
diff --git a/usr/src/uts/common/sys/prsystm.h b/usr/src/uts/common/sys/prsystm.h
index 7adc920da2..75259dc421 100644
--- a/usr/src/uts/common/sys/prsystm.h
+++ b/usr/src/uts/common/sys/prsystm.h
@@ -28,7 +28,7 @@
/* All Rights Reserved */
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_PRSYSTM_H
@@ -86,7 +86,7 @@ extern void prgetcred(proc_t *, struct prcred *);
extern void prgetpriv(proc_t *, struct prpriv *);
extern size_t prgetprivsize(void);
extern void prgetsecflags(proc_t *, struct prsecflags *);
-extern int prnsegs(struct as *, int);
+extern uint_t prnsegs(struct as *, int);
extern void prexit(proc_t *);
extern void prfree(proc_t *);
extern void prlwpexit(kthread_t *);