From 33a8b578dcd79d0dea0436874e54332233563d3c Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 20 Jan 2004 18:46:22 +0000 Subject: [PATCH] Resident executable support stage 2/4: userland bits. Augment rtld-elf to check additional environment variables to trigger registration and deregistration of a dynamically linked program as a resident binary. Add a new userland utility, 'resident'. --- libexec/rtld-elf/i386/rtld_start.S | 4 +- libexec/rtld-elf/rtld.c | 73 ++++++++-- usr.sbin/Makefile | 3 +- usr.sbin/resident/Makefile | 8 + usr.sbin/resident/resident.8 | 18 +++ usr.sbin/resident/resident.c | 226 +++++++++++++++++++++++++++++ 6 files changed, 316 insertions(+), 16 deletions(-) create mode 100644 usr.sbin/resident/Makefile create mode 100644 usr.sbin/resident/resident.8 create mode 100644 usr.sbin/resident/resident.c diff --git a/libexec/rtld-elf/i386/rtld_start.S b/libexec/rtld-elf/i386/rtld_start.S index 45ab4a813e..fd2f74c3f5 100644 --- a/libexec/rtld-elf/i386/rtld_start.S +++ b/libexec/rtld-elf/i386/rtld_start.S @@ -23,13 +23,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/i386/rtld_start.S,v 1.3 1999/08/28 00:10:15 peter Exp $ - * $DragonFly: src/libexec/rtld-elf/i386/rtld_start.S,v 1.2 2003/06/17 04:27:08 dillon Exp $ + * $DragonFly: src/libexec/rtld-elf/i386/rtld_start.S,v 1.3 2004/01/20 18:46:21 dillon Exp $ */ .text .align 4 + .globl resident_start .globl .rtld_start .type .rtld_start,@function +resident_start: .rtld_start: xorl %ebp,%ebp # Clear frame pointer for good form movl %esp,%eax # Save initial stack pointer diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 5888c33fb4..db0ce6d1cc 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.43.2.15 2003/02/20 20:42:46 kan Exp $ - * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.4 2003/12/01 23:50:20 drhodus Exp $ + * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.5 2004/01/20 18:46:20 dillon Exp $ */ /* @@ -145,6 +145,7 @@ static Obj_Entry **obj_tail; /* Link field of last object in list */ static Obj_Entry *obj_main; /* The main program shared object */ static Obj_Entry obj_rtld; /* The dynamic linker shared object */ static unsigned int obj_count; /* Number of objects in obj_list */ +static int ld_resident; /* Non-zero if resident */ static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ STAILQ_HEAD_INITIALIZER(list_global); @@ -271,21 +272,28 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) argv = (char **) sp; sp += argc + 1; /* Skip over arguments and NULL terminator */ env = (char **) sp; - while (*sp++ != 0) /* Skip over environment, and NULL terminator */ - ; - aux = (Elf_Auxinfo *) sp; - /* Digest the auxiliary vector. */ - for (i = 0; i < AT_COUNT; i++) - aux_info[i] = NULL; - for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { - if (auxp->a_type < AT_COUNT) - aux_info[auxp->a_type] = auxp; - } + /* + * If we aren't already resident we have to dig out some more info. + * Note that auxinfo does not exist when we are resident. + */ + if (ld_resident == 0) { + while (*sp++ != 0) /* Skip over environment, and NULL terminator */ + ; + aux = (Elf_Auxinfo *) sp; + + /* Digest the auxiliary vector. */ + for (i = 0; i < AT_COUNT; i++) + aux_info[i] = NULL; + for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { + if (auxp->a_type < AT_COUNT) + aux_info[auxp->a_type] = auxp; + } - /* Initialize and relocate ourselves. */ - assert(aux_info[AT_BASE] != NULL); - init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr); + /* Initialize and relocate ourselves. */ + assert(aux_info[AT_BASE] != NULL); + init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr); + } __progname = obj_rtld.path; argv0 = argv[0] != NULL ? argv[0] : "(null)"; @@ -318,6 +326,17 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) dbg("RTLD dynamic = %p", obj_rtld.dynamic); dbg("RTLD pltgot = %p", obj_rtld.pltgot); + /* + * If we are resident we can skip work that we have already done. + * Note that the stack is reset and there is no Elf_Auxinfo + * when running from a resident image, and the static globals setup + * between here and resident_skip will have already been setup. + */ + if (ld_resident) { /* XXX clean this up! */ + preload_tail = obj_tail; + goto resident_skip1; + } + /* * Load the main program, or process its program header if it is * already loaded. @@ -392,11 +411,16 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) for (obj = obj_list; obj != NULL; obj = obj->next) objlist_push_tail(&list_main, obj); +resident_skip1: + if (ld_tracing) { /* We're done */ trace_loaded_objects(obj_main); exit(0); } + if (ld_resident) /* XXX clean this up! */ + goto resident_skip2; + if (prebind_disable || prebind_load(&obj_rtld, obj_main)) { if (relocate_objects(obj_main, ld_bind_now != NULL && *ld_bind_now != '\0') == -1) @@ -407,9 +431,30 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) die(); } +resident_skip2: + if (ld_prebind != NULL && *ld_prebind != '\0') exit (prebind_save(&obj_rtld, obj_main)); + if (getenv("LD_RESIDENT_REGISTER_NOW")) { + extern void resident_start(void); + ld_resident = 1; + if (exec_sys_register(resident_start) < 0) { + dbg("exec_sys_register failed %d\n", errno); + exit(errno); + } + dbg("exec_sys_register success\n"); + exit(0); + } + if (getenv("LD_RESIDENT_UNREGISTER_NOW")) { + if (exec_sys_unregister(-1) < 0) { + dbg("exec_sys_unregister failed %d\n", errno); + exit(errno); + } + dbg("exec_sys_unregister success\n"); + exit(0); + } + dbg("initializing key program variables"); set_program_var("__progname", argv[0] != NULL ? basename(argv[0]) : ""); set_program_var("environ", env); diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index cffae18d9d..14c564e51e 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,6 +1,6 @@ # From: @(#)Makefile 5.20 (Berkeley) 6/12/93 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $ -# $DragonFly: src/usr.sbin/Makefile,v 1.4 2003/09/18 21:23:04 dillon Exp $ +# $DragonFly: src/usr.sbin/Makefile,v 1.5 2004/01/20 18:46:19 dillon Exp $ # XXX MISSING: mkproto SUBDIR= IPXrouted \ @@ -77,6 +77,7 @@ SUBDIR= IPXrouted \ rarpd \ raycontrol \ repquota \ + resident \ rip6query \ rmt \ route6d \ diff --git a/usr.sbin/resident/Makefile b/usr.sbin/resident/Makefile new file mode 100644 index 0000000000..8b746d9f20 --- /dev/null +++ b/usr.sbin/resident/Makefile @@ -0,0 +1,8 @@ +# $DragonFly: src/usr.sbin/resident/Makefile,v 1.1 2004/01/20 18:46:22 dillon Exp $ + +PROG= resident +SRCS= resident.c +WARNS?= 5 +MAN= resident.8 + +.include diff --git a/usr.sbin/resident/resident.8 b/usr.sbin/resident/resident.8 new file mode 100644 index 0000000000..cbc0249acd --- /dev/null +++ b/usr.sbin/resident/resident.8 @@ -0,0 +1,18 @@ +.\" $DragonFly: src/usr.sbin/resident/resident.8,v 1.1 2004/01/20 18:46:22 dillon Exp $ +.\" +.Dd May 21, 2003 +.Dt RESIDENT 1 +.Os +.Sh NAME +.Nm resident +.Nd Make a dynamic binary resident. +.Sh SYNOPSIS +.Nm +.Ar program ... +.Sh DESCRIPTION +.Sh SEE ALSO +.Xr ld 1 , +.Xr ldd 1 , +.Xr nm 1 , +.Xr rtld 1 +.Sh HISTORY diff --git a/usr.sbin/resident/resident.c b/usr.sbin/resident/resident.c new file mode 100644 index 0000000000..4d96f4b208 --- /dev/null +++ b/usr.sbin/resident/resident.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2003 Matthew Dillon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/usr.sbin/resident/resident.c,v 1.1 2004/01/20 18:46:22 dillon Exp $ + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +usage(void) +{ + fprintf(stderr, "usage: resident [-d] program ...\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int rval; + int c; + int doreg = 1; + int force = 0; + + while ((c = getopt(argc, argv, "dfx:")) != -1) { + switch (c) { + case 'f': + force = 1; + break; + case 'd': + doreg = 0; + break; + case 'x': + c = exec_sys_unregister(strtol(optarg, NULL, 0)); + if (c < 0) + printf("unregister: %s\n", strerror(errno)); + else + printf("unregister: success\n"); + exit(0); + default: + usage(); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + if (argc <= 0) { + usage(); + /*NOTREACHED*/ + } + + /* ld-elf.so magic */ + if (doreg) + setenv("LD_RESIDENT_REGISTER_NOW", "yes", 1); + else + setenv("LD_RESIDENT_UNREGISTER_NOW", "yes", 1); + + rval = 0; + for ( ; argc > 0; argc--, argv++) { + int fd; + union { + struct exec aout; + Elf_Ehdr elf; + } hdr; + int n; + int status; + int file_ok; + int is_shlib; + + if (force) + goto force_target; + + if ((fd = open(*argv, O_RDONLY, 0)) < 0) { + warn("%s", *argv); + rval |= 1; + continue; + } + if ((n = read(fd, &hdr, sizeof hdr)) == -1) { + warn("%s: can't read program header", *argv); + (void)close(fd); + rval |= 1; + continue; + } + + file_ok = 1; + is_shlib = 0; + if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) { + /* a.out file */ + if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC +#if 1 /* Compatibility */ + || hdr.aout.a_entry < __LDPGSZ +#endif + ) { + warnx("%s: not a dynamic executable", *argv); + file_ok = 0; + } + } else if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) { + Elf_Ehdr ehdr; + Elf_Phdr phdr; + int dynamic = 0, i; + + if (lseek(fd, 0, SEEK_SET) == -1 || + read(fd, &ehdr, sizeof ehdr) != sizeof ehdr || + lseek(fd, ehdr.e_phoff, SEEK_SET) == -1 + ) { + warnx("%s: can't read program header", *argv); + file_ok = 0; + } else { + for (i = 0; i < ehdr.e_phnum; i++) { + if (read(fd, &phdr, ehdr.e_phentsize) + != sizeof phdr) { + warnx("%s: can't read program header", + *argv); + file_ok = 0; + break; + } + if (phdr.p_type == PT_DYNAMIC) + dynamic = 1; + } + } + if (!dynamic) { + warnx("%s: not a dynamic executable", *argv); + file_ok = 0; + } else if (hdr.elf.e_type == ET_DYN) { + if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { + is_shlib = 1; + } else { + warnx("%s: not a FreeBSD ELF shared " + "object", *argv); + file_ok = 0; + } + } + } else { + warnx("%s: not a dynamic executable", *argv); + file_ok = 0; + } + (void)close(fd); + if (!file_ok) { + rval |= 1; + continue; + } + + if (is_shlib) { + rval |= 1; + warnx("%s: prebinding not supported on shared libraries.", *argv); + continue; + } + +force_target: + fflush(stdout); + + switch (fork()) { + case -1: + err(1, "fork"); + break; + default: + if (wait(&status) <= 0) { + warn("wait"); + rval |= 1; + } else if (WIFSIGNALED(status)) { + fprintf(stderr, "%s: signal %d\n", + *argv, WTERMSIG(status)); + rval |= 1; + } else if (WIFEXITED(status) && WEXITSTATUS(status)) { + switch(WEXITSTATUS(status)) { + case ENOENT: + fprintf(stderr, "%s: entry not found\n", + *argv); + break; + case EEXIST: + fprintf(stderr, "%s: binary already resident\n", + *argv); + break; + default: + fprintf(stderr, "%s: exit status %s\n", + *argv, strerror(WEXITSTATUS(status))); + } + rval |= 1; + } else { + } + break; + case 0: + execl(*argv, *argv, (char *)NULL); + warn("%s", *argv); + _exit(1); + } + } + + return rval; +} -- 2.32.0