Resident executable support stage 2/4: userland bits. Augment rtld-elf
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 20 Jan 2004 18:46:22 +0000 (18:46 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 20 Jan 2004 18:46:22 +0000 (18:46 +0000)
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
libexec/rtld-elf/rtld.c
usr.sbin/Makefile
usr.sbin/resident/Makefile [new file with mode: 0644]
usr.sbin/resident/resident.8 [new file with mode: 0644]
usr.sbin/resident/resident.c [new file with mode: 0644]

index 45ab4a8..fd2f74c 100644 (file)
  * 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
index 5888c33..db0ce6d 100644 (file)
@@ -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);
index cffae18..14c564e 100644 (file)
@@ -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 (file)
index 0000000..8b746d9
--- /dev/null
@@ -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 <bsd.prog.mk>
diff --git a/usr.sbin/resident/resident.8 b/usr.sbin/resident/resident.8
new file mode 100644 (file)
index 0000000..cbc0249
--- /dev/null
@@ -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 (file)
index 0000000..4d96f4b
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
+ * 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 <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/wait.h>
+
+#include <machine/elf.h>
+#include <a.out.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+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;
+}