diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2006-05-11 22:03:23 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2006-05-11 22:03:23 +0000 |
commit | f03f7d1bdcb4d37382d1eb9d2e02897f7768cea9 (patch) | |
tree | a22060248e171e7d6323b4063a9a0f2c1d724b4c | |
parent | 0a6e9ba40277f106bbc392648093762682567e0c (diff) |
move prebind_strip(8) into ldconfig as the -D option; ok drahn
-rw-r--r-- | libexec/ld.so/Makefile | 4 | ||||
-rw-r--r-- | libexec/ld.so/ldconfig/Makefile | 4 | ||||
-rw-r--r-- | libexec/ld.so/ldconfig/ldconfig.8 | 22 | ||||
-rw-r--r-- | libexec/ld.so/ldconfig/ldconfig.c | 41 | ||||
-rw-r--r-- | libexec/ld.so/ldconfig/prebind_delete.c | 217 | ||||
-rw-r--r-- | libexec/ld.so/prebind_strip/Makefile | 13 | ||||
-rw-r--r-- | libexec/ld.so/prebind_strip/prebind_strip.8 | 48 | ||||
-rw-r--r-- | libexec/ld.so/prebind_strip/prebind_strip.c | 227 |
8 files changed, 272 insertions, 304 deletions
diff --git a/libexec/ld.so/Makefile b/libexec/ld.so/Makefile index 171457c1bf7..8d0b50d0df3 100644 --- a/libexec/ld.so/Makefile +++ b/libexec/ld.so/Makefile @@ -1,7 +1,7 @@ -# $OpenBSD: Makefile,v 1.33 2006/05/04 01:52:16 drahn Exp $ +# $OpenBSD: Makefile,v 1.34 2006/05/11 22:03:22 deraadt Exp $ SUBDIR=ldconfig ldd -#SUBDIR+=prebind prebind_strip +#SUBDIR+=prebind VPATH=${.CURDIR}/../../lib/libc/string SRCS= ldasm.S loader.c resolve.c dlfcn.c dl_printf.c rtld_machine.c diff --git a/libexec/ld.so/ldconfig/Makefile b/libexec/ld.so/ldconfig/Makefile index 663ef189494..4f0e1109827 100644 --- a/libexec/ld.so/ldconfig/Makefile +++ b/libexec/ld.so/ldconfig/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.4 2004/11/10 22:03:18 drahn Exp $ +# $OpenBSD: Makefile,v 1.5 2006/05/11 22:03:22 deraadt Exp $ # $NetBSD: Makefile,v 1.10 1995/03/06 04:24:41 cgd Exp $ PROG= ldconfig -SRCS= ldconfig.c shlib.c etc.c +SRCS= ldconfig.c shlib.c etc.c prebind_delete.c LDDIR?= $(.CURDIR)/.. #CFLAGS+=-Werror #CFLAGS+=-I$(.CURDIR) -I$(LDDIR)/$(MACHINE_ARCH) diff --git a/libexec/ld.so/ldconfig/ldconfig.8 b/libexec/ld.so/ldconfig/ldconfig.8 index 49042da5987..71ce8285479 100644 --- a/libexec/ld.so/ldconfig/ldconfig.8 +++ b/libexec/ld.so/ldconfig/ldconfig.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ldconfig.8,v 1.17 2005/12/31 15:08:22 jmc Exp $ +.\" $OpenBSD: ldconfig.8,v 1.18 2006/05/11 22:03:22 deraadt Exp $ .\" .\" Copyright (c) 1993,1995 Paul Kranenburg .\" All rights reserved. @@ -37,8 +37,8 @@ .Nd configure the shared library cache .Sh SYNOPSIS .Nm ldconfig -.Op Fl mRrsUv -.Op Ar directory Ar ... +.Op Fl DmRrsUv +.Op Ar path Ar ... .Sh DESCRIPTION .Nm is used to prepare a set of @@ -91,6 +91,8 @@ for further information. The following options are recognized by .Nm ldconfig : .Bl -tag -width indent +.It Fl D +Remove any prebind information in the specified binary or shared library. .It Fl m Merge the result of the scan of the directories given as arguments into the existing hints file. @@ -118,7 +120,19 @@ This option cannot be used with .It Fl v Switch on verbose mode. .El -.Sh Security +.Sh PREBINDING +Prebinding is loosely based on an earlier concept called Prelinking, which +also accelerated +.Xr ld.so 1 +performance but simultaneously impaired address space randomization. +When prebinding information is added to libraries and programs using +.Fl P , +program startup can be significantly improved because +.Xr ld.so 1 +can initialize the shared library environment much faster. +Prebinding information adds a small amount of data to the end of each +specified library and program. +.Sh SECURITY Special care must be taken when loading shared libraries into the address space of .Ev set-user-Id diff --git a/libexec/ld.so/ldconfig/ldconfig.c b/libexec/ld.so/ldconfig/ldconfig.c index 2cda859a3c0..cab2ee9ba03 100644 --- a/libexec/ld.so/ldconfig/ldconfig.c +++ b/libexec/ld.so/ldconfig/ldconfig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldconfig.c,v 1.18 2006/04/11 15:21:40 ray Exp $ */ +/* $OpenBSD: ldconfig.c,v 1.19 2006/05/11 22:03:22 deraadt Exp $ */ /* * Copyright (c) 1993,1995 Paul Kranenburg @@ -59,6 +59,8 @@ extern char *__progname; static int verbose; +static int delete; +static int doprebind; static int nostd; static int justread; static int merge; @@ -85,13 +87,21 @@ static int buildhints(void); static int readhints(void); static void listhints(void); +void +usage(void) +{ + fprintf(stderr, + "usage: %s [-DmRrsUv] [path ...]\n", __progname); + exit(1); +} + int main(int argc, char *argv[]) { int i, c; int rval = 0; - while ((c = getopt(argc, argv, "RUmrsv")) != -1) { + while ((c = getopt(argc, argv, "DRmrsUv")) != -1) { switch (c) { case 'R': rescan = 1; @@ -111,10 +121,14 @@ main(int argc, char *argv[]) case 'v': verbose = 1; break; + case 'D': + delete = 1; + break; +// case 'P': +// doprebind = 1; + break; default: - fprintf(stderr, - "usage: %s [-mRrsUv] [dir ...]\n", __progname); - exit(1); + usage(); break; } } @@ -125,6 +139,12 @@ main(int argc, char *argv[]) dir_list = xmalloc(1); *dir_list = '\0'; + if (delete) { + if (rescan || unconfig || merge || justread || nostd || doprebind) + errx(1, "cannot mix -U -R -r -s -P options with -D"); + exit (prebind_delete(&argv[optind], verbose)); + } + if (justread || merge || rescan) { if ((rval = readhints()) != 0) return rval; @@ -135,9 +155,14 @@ main(int argc, char *argv[]) add_search_path(dir_list); dir_list = xrealloc(dir_list, 1); *dir_list = '\0'; - } else - if (!nostd) - std_search_path(); + } else if (!nostd) + std_search_path(); + +// if (doprebind) { +// if (rescan || unconfig || justread || nostd) +// errx(1, "cannot mix other options with -P"); +// exit (prebind(&argv[optind], verbose, merge)); +// } if (unconfig) { if (optind < argc) diff --git a/libexec/ld.so/ldconfig/prebind_delete.c b/libexec/ld.so/ldconfig/prebind_delete.c new file mode 100644 index 00000000000..6933f11acc9 --- /dev/null +++ b/libexec/ld.so/ldconfig/prebind_delete.c @@ -0,0 +1,217 @@ +/* $OpenBSD: prebind_delete.c,v 1.1 2006/05/11 22:03:22 deraadt Exp $ */ + +/* + * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/exec_elf.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include "../prebind.h" + +#define BUFSZ (256 * 1024) + +int strip_prebind(char *file, int verbose); +int prebind_remove_load_section(int fd, char *name, int verbose); +int prebind_newfile(int fd, char *name, struct stat *st, + struct prebind_footer *footer, int verbose); + +int +prebind_delete(char **argv, int verbose) +{ + extern char *__progname; + + while (*argv) { + if (strip_prebind(*argv, verbose) == -1) + return (1); + argv++; + } + return (0); +} + +int +strip_prebind(char *file, int verbose) +{ + struct prebind_footer footer; + extern char *__progname; + int fd, rdonly = 0; + struct stat st; + ssize_t bytes; + + fd = open(file, O_RDWR); + if (fd == -1 && errno == ETXTBSY) { + fd = open(file, O_RDONLY); + rdonly = 1; + } + if (fd == -1) { + warn("%s", file); + return (-1); + } + + if (fstat(fd, &st) == -1) + return (-1); + + lseek(fd, -((off_t)sizeof(struct prebind_footer)), SEEK_END); + bytes = read(fd, &footer, sizeof(struct prebind_footer)); + if (bytes != sizeof(struct prebind_footer)) + goto done; + + if (footer.bind_id[0] != BIND_ID0 || footer.bind_id[1] != BIND_ID1 || + footer.bind_id[2] != BIND_ID2 || footer.bind_id[3] != BIND_ID3) { + if (verbose) + fprintf(stderr, "%s: no prebind header\n", file); + goto done; + } + + if (rdonly) { + fd = prebind_newfile(fd, file, &st, &footer, verbose); + } else { + prebind_remove_load_section(fd, file, verbose); + ftruncate(fd, footer.orig_size); + } + + if (verbose) + fprintf(stderr, "%s: stripped %lld bytes from %s\n", + __progname, st.st_size - footer.orig_size, file); + +done: + if (fd != -1) + close(fd); + return (0); +} + +int +prebind_remove_load_section(int fd, char *name, int verbose) +{ + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + int loadsection; + char *buf; + + buf = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_FILE | MAP_SHARED, + fd, 0); + if (buf == MAP_FAILED) { + if (verbose) + warn("%s: cannot mmap for for write", name); + return (-1); + } + + ehdr = (Elf_Ehdr *)buf; + phdr = (Elf_Phdr *)(buf + ehdr->e_phoff); + loadsection = ehdr->e_phnum - 1; + + if (ehdr->e_type != ET_EXEC || + (phdr[loadsection].p_flags & 0x08000000) == 0) + goto done; + + if (phdr[loadsection].p_type != PT_LOAD || + ((phdr[loadsection].p_flags & 0x08000000) == 0)) { + /* doesn't look like ours */ + if (verbose) + fprintf(stderr, "mapped, %s id doesn't match %lx\n", name, + (long)(phdr[loadsection].p_vaddr)); + goto done; + } + + bzero(&phdr[loadsection], sizeof(Elf_Phdr)); + ehdr->e_phnum--; +done: + munmap(buf, 8192); + return (0); +} + +int +prebind_newfile(int infd, char *name, struct stat *st, + struct prebind_footer *footer, int verbose) +{ + struct timeval tv[2]; + char *newname, *buf; + ssize_t len, wlen; + int outfd; + + if (asprintf(&newname, "%s.XXXXXXXXXX", name) == -1) { + if (verbose) + warn("asprintf"); + return (-1); + } + outfd = open(newname, O_CREAT|O_RDWR|O_TRUNC, 0600); + if (outfd == -1) { + warn("%s", newname); + free(newname); + return (-1); + } + + buf = malloc(BUFSZ); + if (buf == NULL) { + if (verbose) + warn("malloc"); + goto fail; + } + + /* copy old file to new file */ + lseek(infd, (off_t)0, SEEK_SET); + while (1) { + len = read(infd, buf, BUFSIZ); + if (len == -1) { + if (verbose) + warn("read"); + free(buf); + goto fail; + } + if (len == 0) + break; + wlen = write(outfd, buf, len); + if (wlen != len) { + free(buf); + goto fail; + } + } + free(buf); + + /* now back track, and delete the header */ + if (prebind_remove_load_section(outfd, newname, verbose) == -1) + goto fail; + if (ftruncate(outfd, footer->orig_size) == -1) + goto fail; + + /* move new file into place */ + TIMESPEC_TO_TIMEVAL(&tv[0], &st->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tv[1], &st->st_mtimespec); + if (futimes(outfd, tv) == -1) + goto fail; + if (fchown(outfd, st->st_uid, st->st_gid) == -1) + goto fail; + if (fchmod(outfd, st->st_mode) == -1) + goto fail; + if (fchflags(outfd, st->st_flags) == -1) + goto fail; + if (rename(newname, name) == -1) + goto fail; + + return (outfd); + +fail: + free(newname); + unlink(newname); + close(outfd); + return (-1); +} diff --git a/libexec/ld.so/prebind_strip/Makefile b/libexec/ld.so/prebind_strip/Makefile deleted file mode 100644 index 6b0fa03bbd9..00000000000 --- a/libexec/ld.so/prebind_strip/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# $OpenBSD: Makefile,v 1.1 2006/05/03 16:10:52 drahn Exp $ - -SRCS= prebind_strip.c - -PROG= prebind_strip -MAN= prebind_strip.8 - -BINDIR=/usr/sbin - -CFLAGS += -Wall -ggdb -CFLAGS += -I${.CURDIR}/.. - -.include <bsd.prog.mk> diff --git a/libexec/ld.so/prebind_strip/prebind_strip.8 b/libexec/ld.so/prebind_strip/prebind_strip.8 deleted file mode 100644 index 112baa1e254..00000000000 --- a/libexec/ld.so/prebind_strip/prebind_strip.8 +++ /dev/null @@ -1,48 +0,0 @@ -.\" $OpenBSD: prebind_strip.8,v 1.3 2006/05/05 13:52:42 jmc Exp $ -.\" -.\" Copyright (c) 2006 Dale Rahn <drahn@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd May 1, 2006 -.Dt PREBIND_STRIP 8 -.Os -.Sh NAME -.Nm prebind_strip -.Nd remove prebind info from binaries and libraries -.Sh SYNOPSIS -.Nm prebind_strip -.Op Ar -.Sh DESCRIPTION -.Nm -removes any prebind information from a binary or shared library. -After this is run, the library length and md5 should match the original value. -.Sh SEE ALSO -.Xr ld.so 1 , -.Xr prebind 8 -.Sh STANDARDS -None -.Sh HISTORY -The -.Nm -utility first appeared in -.Ox 4.0 . -.Nm -is based loosely on Prelinking, however prelink removes the security -feature of libraries appearing in random order on each invocation, thus -it was incompatible with -.Ox Ns 's -goals. -.Nm -was written as an attempt to improve the speed of dynamic linking -without the penalty of loss of security features. diff --git a/libexec/ld.so/prebind_strip/prebind_strip.c b/libexec/ld.so/prebind_strip/prebind_strip.c deleted file mode 100644 index a7b433af230..00000000000 --- a/libexec/ld.so/prebind_strip/prebind_strip.c +++ /dev/null @@ -1,227 +0,0 @@ -/* $OpenBSD: prebind_strip.c,v 1.4 2006/05/08 20:37:01 deraadt Exp $ */ -/* - * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/exec_elf.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include "prebind.h" - -void strip_prebind(char *file, char *output); -void prebind_remove_load_section(int fd, char *name); -int prebind_cat(int fd, struct prebind_footer *footer, char *name); - -extern char *__progname; - -void __dead -usage(void) -{ - fprintf(stderr, "Usage:%s [-o <outfile>] <filelist>\n", __progname); - exit(1); -} - - -int -main(int argc, char **argv) -{ - char *outputfile = NULL; - int i; - int ch; - while ((ch = getopt(argc, argv, "o:")) != -1) { - switch (ch) { - case 'o': - outputfile = optarg; - break; - default: - usage(); - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (outputfile != NULL && argc > 1) { - fprintf(stderr, "%s:-o will not work with multiple files\n", - __progname); - usage(); - } - for (i = 0; i < argc; i++) { - strip_prebind(argv[i], outputfile); - } - - return 0; -} - -void -strip_prebind(char *file, char *outfile) -{ - struct prebind_footer footer; - int fd; - ssize_t bytes; - int mode; - - if (outfile == NULL) - mode = O_RDWR; - else - mode = O_RDONLY; - - fd = open(file, mode); - if (fd == -1) { - perror(file); - return; - } - lseek(fd, -((off_t)sizeof(struct prebind_footer)), SEEK_END); - bytes = read(fd, &footer, sizeof(struct prebind_footer)); - if (bytes != sizeof(struct prebind_footer)) { - perror("short read\n"); - goto done; - } - - if (footer.bind_id[0] == BIND_ID0 && - footer.bind_id[1] == BIND_ID1 && - footer.bind_id[2] == BIND_ID2 && - footer.bind_id[3] == BIND_ID3) { - - } else { - fprintf(stderr, "%s: no prebind header\n", file); - goto done; - } - - if (outfile == NULL) { - prebind_remove_load_section(fd, file); - - ftruncate(fd, footer.orig_size); - } else { - prebind_cat(fd, &footer, outfile); - } -done: - close(fd); -} - -void -prebind_remove_load_section(int fd, char *name) -{ - void *buf; - Elf_Ehdr *ehdr; - Elf_Phdr *phdr; - int loadsection; - - buf = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_FILE | MAP_SHARED, - fd, 0); - if (buf == MAP_FAILED) { - perror(name); - fprintf(stderr, "%s: cannot mmap for write\n", name); - return; - } - - ehdr = (Elf_Ehdr *) buf; - phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff); - - loadsection = ehdr->e_phnum - 1; - - if (ehdr->e_type != ET_EXEC || - (phdr[loadsection].p_flags & 0x08000000) == 0) { - goto done; - } - - if ((phdr[loadsection].p_type != PT_LOAD) || - ((phdr[loadsection].p_flags & 0x08000000) == 0)) { - /* doesn't look like ours */ - fprintf(stderr, "mapped, %s id doesn't match %lx\n", name, - (long)(phdr[loadsection].p_vaddr)); - goto done; - } - - bzero(&phdr[loadsection], sizeof(Elf_Phdr)); - - ehdr->e_phnum--; -done: - munmap(buf, 8192); -} - -int -prebind_cat(int fd, struct prebind_footer *footer, char *name) -{ - int outfd; - void *buf; - Elf_Ehdr *ehdr; - Elf_Phdr *phdr; - size_t len, wlen, rlen, remlen; - int header_done = 0; - int err = 0; - int loadsection; - - if (strcmp(name, "-") == 0) - outfd = 1; - else - outfd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0644); - - if (outfd == -1) { - fprintf(stderr, "unable to open file %s\n", name); - return 1; - } -#define BUFSZ (256 * 1024) - buf = malloc(BUFSZ); - - if (buf == NULL) { - fprintf(stderr, "failed to allocate copy buffer\n"); - return 1; - } - - lseek(fd, 0, SEEK_SET); - remlen = footer->orig_size; - while (remlen > 0) { - if (remlen > BUFSZ) - rlen = BUFSZ; - else - rlen = remlen; - len = read(fd, buf, rlen); - if (len <= 0) { - break; /* read failure */ - err=1; - } - remlen -= len; - if (header_done == 0) { - header_done = 1; - ehdr = (Elf_Ehdr *) buf; - phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff); - - loadsection = ehdr->e_phnum - 1; - - if ((len >= ehdr->e_phoff + - sizeof(Elf_Phdr) * ehdr->e_phnum) && - ehdr->e_type == ET_EXEC && - (phdr[loadsection].p_flags & 0x08000000) != 0 && - (phdr[loadsection].p_type == PT_LOAD)) { - bzero(&phdr[loadsection], sizeof(Elf_Phdr)); - ehdr->e_phnum--; - } - } - wlen = write(outfd, buf, len); - if (wlen != len) { - /* write failed */ - err=1; - break; - } - } - - return err; -} |