Print this page
OS-4460 exec brands processes that still have multiple threads
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-4188 NULL dereference in lwp_hash_in
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-4119 lxbrand panic when running native perl inside lx zone
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-4151 setbrand hooks should be sane during fork
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-4129 lxbrand should not abuse p_brand_data for storing exit signal
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-3712 lx brand: DTrace pid provider induces core dumps on 64-bit processes
OS-3517 lx brand: branded zones don't interpret .interp section
OS-3149 lx brand always sends SIGCHLD to parent processes, regardless of how clone was invoked
OS-2887 lxbrand add WALL, WCLONE, WNOTHREAD support to waitid
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
OS-2877 lx_librtld_db falls to load due to NULL DT_DEBUG
OS-2834 ship lx brand
*** 18,27 ****
--- 18,28 ----
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
*/
#include <sys/kmem.h>
#include <sys/errno.h>
#include <sys/systm.h>
*** 43,61 ****
struct brand_mach_ops native_mach_ops = {
NULL, NULL
};
#else /* !__sparcv9 */
struct brand_mach_ops native_mach_ops = {
! NULL, NULL, NULL, NULL
};
#endif /* !__sparcv9 */
brand_t native_brand = {
BRAND_VER_1,
"native",
NULL,
! &native_mach_ops
};
/*
* Used to maintain a list of all the brands currently loaded into the
* kernel.
--- 44,63 ----
struct brand_mach_ops native_mach_ops = {
NULL, NULL
};
#else /* !__sparcv9 */
struct brand_mach_ops native_mach_ops = {
! NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
#endif /* !__sparcv9 */
brand_t native_brand = {
BRAND_VER_1,
"native",
NULL,
! &native_mach_ops,
! 0
};
/*
* Used to maintain a list of all the brands currently loaded into the
* kernel.
*** 308,357 ****
}
}
mutex_exit(&brand_list_lock);
}
! void
! brand_setbrand(proc_t *p)
{
brand_t *bp = p->p_zone->zone_brand;
! ASSERT(bp != NULL);
! ASSERT(p->p_brand == &native_brand);
/*
! * We should only be called from exec(), when we know the process
! * is single-threaded.
*/
! ASSERT(p->p_tlist == p->p_tlist->t_forw);
p->p_brand = bp;
ASSERT(PROC_IS_BRANDED(p));
BROP(p)->b_setbrand(p);
}
void
! brand_clearbrand(proc_t *p, boolean_t no_lwps)
{
brand_t *bp = p->p_zone->zone_brand;
! klwp_t *lwp = NULL;
! ASSERT(bp != NULL);
! ASSERT(!no_lwps || (p->p_tlist == NULL));
/*
! * If called from exec_common() or proc_exit(),
! * we know the process is single-threaded.
! * If called from fork_fail, p_tlist is NULL.
*/
! if (!no_lwps) {
! ASSERT(p->p_tlist == p->p_tlist->t_forw);
! lwp = p->p_tlist->t_lwp;
}
! ASSERT(PROC_IS_BRANDED(p));
! BROP(p)->b_proc_exit(p, lwp);
! p->p_brand = &native_brand;
}
#if defined(__sparcv9)
/*
* Currently, only sparc has system level brand syscall interposition.
--- 310,425 ----
}
}
mutex_exit(&brand_list_lock);
}
! int
! brand_setbrand(proc_t *p, boolean_t lwps_ok)
{
brand_t *bp = p->p_zone->zone_brand;
+ void *brand_data = NULL;
! VERIFY(MUTEX_NOT_HELD(&p->p_lock));
! VERIFY(bp != NULL);
/*
! * Process branding occurs during fork() and exec(). When it happens
! * during fork(), the LWP count will always be 0 since branding is
! * performed as part of getproc(), before LWPs have been associated.
! * The same is not true during exec(), where a multi-LWP process may
! * undergo branding just prior to gexec(). This is to ensure
! * exec-related brand hooks are available. While it may seem
! * complicated to brand a multi-LWP process, the two possible outcomes
! * simplify things:
! *
! * 1. The exec() succeeds: LWPs besides the caller will be killed and
! * any further branding will occur in a single-LWP context.
! * 2. The exec() fails: The process will be promptly unbranded since
! * the hooks are no longer needed.
! *
! * To prevent inconsistent brand state from being encountered during
! * the exec(), LWPs beyond the caller which are associated with this
! * process must be held temporarily. They will be released either when
! * they are killed in the exec() success, or when the brand is cleared
! * after exec() failure.
*/
! if (lwps_ok) {
! /*
! * We've been called from a exec() context tolerating the
! * existence of multiple LWPs during branding is necessary.
! */
! VERIFY(p == curproc);
! VERIFY(p->p_tlist != NULL);
+ if (p->p_tlist != p->p_tlist->t_forw) {
+ /*
+ * Multiple LWPs are present. Hold all but the caller.
+ */
+ if (!holdlwps(SHOLDFORK1)) {
+ return (-1);
+ }
+ }
+ } else {
+ /*
+ * Processes branded during fork() should not have LWPs at all.
+ */
+ VERIFY(p->p_tlist == NULL);
+ }
+
+ if (bp->b_data_size > 0) {
+ brand_data = kmem_zalloc(bp->b_data_size, KM_SLEEP);
+ }
+
+ mutex_enter(&p->p_lock);
+ ASSERT(!PROC_IS_BRANDED(p));
p->p_brand = bp;
+ p->p_brand_data = brand_data;
ASSERT(PROC_IS_BRANDED(p));
BROP(p)->b_setbrand(p);
+ mutex_exit(&p->p_lock);
+ return (0);
}
void
! brand_clearbrand(proc_t *p, boolean_t lwps_ok)
{
brand_t *bp = p->p_zone->zone_brand;
! void *brand_data;
+ VERIFY(MUTEX_NOT_HELD(&p->p_lock));
+ VERIFY(bp != NULL);
+ VERIFY(PROC_IS_BRANDED(p));
+
+ mutex_enter(&p->p_lock);
+ p->p_brand = &native_brand;
+ brand_data = p->p_brand_data;
+ p->p_brand_data = NULL;
+
+ if (lwps_ok) {
+ VERIFY(p == curproc);
/*
! * A process with multiple LWPs is being de-branded after
! * failing an exec. The other LWPs were held as part of the
! * procedure, so they must be resumed now.
*/
! if (p->p_tlist != NULL && p->p_tlist != p->p_tlist->t_forw) {
! continuelwps(p);
}
+ } else {
+ /*
+ * While clearing the brand, it's ok for one LWP to be present.
+ * This happens when a native binary is executed inside a
+ * branded zone, since the brand will be removed during the
+ * course of a successful exec.
+ */
+ VERIFY(p->p_tlist == NULL || p->p_tlist == p->p_tlist->t_forw);
+ }
+ mutex_exit(&p->p_lock);
! if (brand_data != NULL) {
! kmem_free(brand_data, bp->b_data_size);
! }
}
#if defined(__sparcv9)
/*
* Currently, only sparc has system level brand syscall interposition.
*** 481,491 ****
*/
if (cmd == B_EXEC_BRAND)
return (ENOSYS);
/* For all other operations this must be a branded process. */
! if (p->p_brand == &native_brand)
return (ENOSYS);
ASSERT(p->p_brand == pbrand);
ASSERT(p->p_brand_data != NULL);
--- 549,559 ----
*/
if (cmd == B_EXEC_BRAND)
return (ENOSYS);
/* For all other operations this must be a branded process. */
! if (!PROC_IS_BRANDED(p))
return (ENOSYS);
ASSERT(p->p_brand == pbrand);
ASSERT(p->p_brand_data != NULL);
*** 599,627 ****
/*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, char *brandlinker, char *brandlinker32)
{
vnode_t *nvp;
Ehdr ehdr;
Addr uphdr_vaddr;
intptr_t voffset;
! int interp;
int i, err;
struct execenv env;
struct execenv origenv;
stack_t orig_sigaltstack;
struct user *up = PTOU(curproc);
proc_t *p = ttoproc(curthread);
klwp_t *lwp = ttolwp(curthread);
brand_proc_data_t *spd;
brand_elf_data_t sed, *sedp;
- char *linker;
uintptr_t lddata; /* lddata of executable's linker */
ASSERT(curproc->p_brand == pbrand);
ASSERT(curproc->p_brand_data != NULL);
--- 667,694 ----
/*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)
{
vnode_t *nvp;
Ehdr ehdr;
Addr uphdr_vaddr;
intptr_t voffset;
! char *interp;
int i, err;
struct execenv env;
struct execenv origenv;
stack_t orig_sigaltstack;
struct user *up = PTOU(curproc);
proc_t *p = ttoproc(curthread);
klwp_t *lwp = ttolwp(curthread);
brand_proc_data_t *spd;
brand_elf_data_t sed, *sedp;
uintptr_t lddata; /* lddata of executable's linker */
ASSERT(curproc->p_brand == pbrand);
ASSERT(curproc->p_brand_data != NULL);
*** 634,649 ****
* We will exec the brand library and then map in the target
* application and (optionally) the brand's default linker.
*/
if (args->to_model == DATAMODEL_NATIVE) {
args->emulator = brandlib;
- linker = brandlinker;
}
#if defined(_LP64)
else {
args->emulator = brandlib32;
- linker = brandlinker32;
}
#endif /* _LP64 */
if ((err = lookupname(args->emulator, UIO_SYSSPACE, FOLLOW,
NULLVPP, &nvp)) != 0) {
--- 701,714 ----
*** 723,741 ****
bzero(&env, sizeof (env));
if (args->to_model == DATAMODEL_NATIVE) {
err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr,
&voffset, exec_file, &interp, &env.ex_bssbase,
! &env.ex_brkbase, &env.ex_brksize, NULL);
}
#if defined(_LP64)
else {
Elf32_Ehdr ehdr32;
Elf32_Addr uphdr_vaddr32;
err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32,
&voffset, exec_file, &interp, &env.ex_bssbase,
! &env.ex_brkbase, &env.ex_brksize, NULL);
Ehdr32to64(&ehdr32, &ehdr);
if (uphdr_vaddr32 == (Elf32_Addr)-1)
uphdr_vaddr = (Addr)-1;
else
--- 788,806 ----
bzero(&env, sizeof (env));
if (args->to_model == DATAMODEL_NATIVE) {
err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr,
&voffset, exec_file, &interp, &env.ex_bssbase,
! &env.ex_brkbase, &env.ex_brksize, NULL, NULL);
}
#if defined(_LP64)
else {
Elf32_Ehdr ehdr32;
Elf32_Addr uphdr_vaddr32;
err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32,
&voffset, exec_file, &interp, &env.ex_bssbase,
! &env.ex_brkbase, &env.ex_brksize, NULL, NULL);
Ehdr32to64(&ehdr32, &ehdr);
if (uphdr_vaddr32 == (Elf32_Addr)-1)
uphdr_vaddr = (Addr)-1;
else
*** 742,751 ****
--- 807,820 ----
uphdr_vaddr = uphdr_vaddr32;
}
#endif /* _LP64 */
if (err != 0) {
restoreexecenv(&origenv, &orig_sigaltstack);
+
+ if (interp != NULL)
+ kmem_free(interp, MAXPATHLEN);
+
return (err);
}
/*
* Save off the important properties of the executable. The
*** 759,769 ****
sedp->sed_phdr = voffset + uphdr_vaddr;
sedp->sed_entry = voffset + ehdr.e_entry;
sedp->sed_phent = ehdr.e_phentsize;
sedp->sed_phnum = ehdr.e_phnum;
! if (interp) {
if (ehdr.e_type == ET_DYN) {
/*
* This is a shared object executable, so we
* need to pick a reasonable place to put the
* heap. Just don't use the first page.
--- 828,838 ----
sedp->sed_phdr = voffset + uphdr_vaddr;
sedp->sed_entry = voffset + ehdr.e_entry;
sedp->sed_phent = ehdr.e_phentsize;
sedp->sed_phnum = ehdr.e_phnum;
! if (interp != NULL) {
if (ehdr.e_type == ET_DYN) {
/*
* This is a shared object executable, so we
* need to pick a reasonable place to put the
* heap. Just don't use the first page.
*** 775,802 ****
/*
* If the program needs an interpreter (most do), map
* it in and store relevant information about it in the
* aux vector, where the brand library can find it.
*/
! if ((err = lookupname(linker, UIO_SYSSPACE,
FOLLOW, NULLVPP, &nvp)) != 0) {
! uprintf("%s: not found.", brandlinker);
restoreexecenv(&origenv, &orig_sigaltstack);
return (err);
}
if (args->to_model == DATAMODEL_NATIVE) {
err = mapexec_brand(nvp, args, &ehdr,
&uphdr_vaddr, &voffset, exec_file, &interp,
! NULL, NULL, NULL, &lddata);
}
#if defined(_LP64)
else {
Elf32_Ehdr ehdr32;
Elf32_Addr uphdr_vaddr32;
err = mapexec32_brand(nvp, args, &ehdr32,
&uphdr_vaddr32, &voffset, exec_file, &interp,
! NULL, NULL, NULL, &lddata);
Ehdr32to64(&ehdr32, &ehdr);
if (uphdr_vaddr32 == (Elf32_Addr)-1)
uphdr_vaddr = (Addr)-1;
else
--- 844,875 ----
/*
* If the program needs an interpreter (most do), map
* it in and store relevant information about it in the
* aux vector, where the brand library can find it.
*/
! if ((err = lookupname(interp, UIO_SYSSPACE,
FOLLOW, NULLVPP, &nvp)) != 0) {
! uprintf("%s: not found.", interp);
restoreexecenv(&origenv, &orig_sigaltstack);
+ kmem_free(interp, MAXPATHLEN);
return (err);
}
+
+ kmem_free(interp, MAXPATHLEN);
+
if (args->to_model == DATAMODEL_NATIVE) {
err = mapexec_brand(nvp, args, &ehdr,
&uphdr_vaddr, &voffset, exec_file, &interp,
! NULL, NULL, NULL, &lddata, NULL);
}
#if defined(_LP64)
else {
Elf32_Ehdr ehdr32;
Elf32_Addr uphdr_vaddr32;
err = mapexec32_brand(nvp, args, &ehdr32,
&uphdr_vaddr32, &voffset, exec_file, &interp,
! NULL, NULL, NULL, &lddata, NULL);
Ehdr32to64(&ehdr32, &ehdr);
if (uphdr_vaddr32 == (Elf32_Addr)-1)
uphdr_vaddr = (Addr)-1;
else
*** 932,944 ****
}
#endif /* _LP64 */
/*
* Third, the /proc aux vectors set up by elfexec() point to
! * brand emulation library and it's linker. Copy these to the
* /proc brand specific aux vector, and update the regular
! * /proc aux vectors to point to the executable (and it's
* linker). This will enable debuggers to access the
* executable via the usual /proc or elf notes aux vectors.
*
* The brand emulation library's linker will get it's aux
* vectors off the stack, and then update the stack with the
--- 1005,1017 ----
}
#endif /* _LP64 */
/*
* Third, the /proc aux vectors set up by elfexec() point to
! * brand emulation library and its linker. Copy these to the
* /proc brand specific aux vector, and update the regular
! * /proc aux vectors to point to the executable (and its
* linker). This will enable debuggers to access the
* executable via the usual /proc or elf notes aux vectors.
*
* The brand emulation library's linker will get it's aux
* vectors off the stack, and then update the stack with the
*** 1076,1134 ****
ASSERT(l->lwp_brand != NULL);
l->lwp_brand = NULL;
}
/*ARGSUSED*/
! int
brand_solaris_initlwp(klwp_t *l, struct brand *pbrand)
{
ASSERT(l->lwp_procp->p_brand == pbrand);
ASSERT(l->lwp_procp->p_brand_data != NULL);
ASSERT(l->lwp_brand == NULL);
l->lwp_brand = (void *)-1;
- return (0);
}
/*ARGSUSED*/
void
brand_solaris_lwpexit(klwp_t *l, struct brand *pbrand)
{
- proc_t *p = l->lwp_procp;
-
ASSERT(l->lwp_procp->p_brand == pbrand);
ASSERT(l->lwp_procp->p_brand_data != NULL);
ASSERT(l->lwp_brand != NULL);
-
- /*
- * We should never be called for the last thread in a process.
- * (That case is handled by brand_solaris_proc_exit().)
- * Therefore this lwp must be exiting from a multi-threaded
- * process.
- */
- ASSERT(p->p_tlist != p->p_tlist->t_forw);
-
- l->lwp_brand = NULL;
}
/*ARGSUSED*/
void
! brand_solaris_proc_exit(struct proc *p, klwp_t *l, struct brand *pbrand)
{
ASSERT(p->p_brand == pbrand);
ASSERT(p->p_brand_data != NULL);
- /*
- * When called from proc_exit(), we know that process is
- * single-threaded and free our lwp brand data.
- * otherwise just free p_brand_data and return.
- */
- if (l != NULL) {
- ASSERT(p->p_tlist == p->p_tlist->t_forw);
- ASSERT(p->p_tlist->t_lwp == l);
- (void) brand_solaris_freelwp(l, pbrand);
- }
-
/* upon exit, free our proc brand data */
kmem_free(p->p_brand_data, sizeof (brand_proc_data_t));
p->p_brand_data = NULL;
}
--- 1149,1183 ----
ASSERT(l->lwp_brand != NULL);
l->lwp_brand = NULL;
}
/*ARGSUSED*/
! void
brand_solaris_initlwp(klwp_t *l, struct brand *pbrand)
{
ASSERT(l->lwp_procp->p_brand == pbrand);
ASSERT(l->lwp_procp->p_brand_data != NULL);
ASSERT(l->lwp_brand == NULL);
l->lwp_brand = (void *)-1;
}
/*ARGSUSED*/
void
brand_solaris_lwpexit(klwp_t *l, struct brand *pbrand)
{
ASSERT(l->lwp_procp->p_brand == pbrand);
ASSERT(l->lwp_procp->p_brand_data != NULL);
ASSERT(l->lwp_brand != NULL);
}
/*ARGSUSED*/
void
! brand_solaris_proc_exit(struct proc *p, struct brand *pbrand)
{
ASSERT(p->p_brand == pbrand);
ASSERT(p->p_brand_data != NULL);
/* upon exit, free our proc brand data */
kmem_free(p->p_brand_data, sizeof (brand_proc_data_t));
p->p_brand_data = NULL;
}
*** 1143,1149 ****
* is single-threaded.
*/
ASSERT(p->p_tlist == p->p_tlist->t_forw);
p->p_brand_data = kmem_zalloc(sizeof (brand_proc_data_t), KM_SLEEP);
- (void) brand_solaris_initlwp(p->p_tlist->t_lwp, pbrand);
}
--- 1192,1197 ----