diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2003-05-08 16:30:53 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2003-05-08 16:30:53 +0000 |
commit | 4c9e8a8f53881a9a4c55bc44c342ae3e39186074 (patch) | |
tree | 9f0d5c09c519988574383ab107d6528dd167ee9f /libexec/ld.so/sod.c | |
parent | 005f055d6703a25a26e4f35aac777dfdac0c2b0f (diff) |
Previously, ld.so would use a single page for mapping the hints file
and then, if that was not big enough, map the rest of it contiguously.
However, there is no guarantee that the address space after the
first mmap has not already been used by something else.
Instead, just fstat the file and map up to st_size. Also reorganized
the code a tad and added some sanity checks for st_size.
Problem tracked down by dhartmei@ and mickey@; drahn@ OK.
Diffstat (limited to 'libexec/ld.so/sod.c')
-rw-r--r-- | libexec/ld.so/sod.c | 67 |
1 files changed, 28 insertions, 39 deletions
diff --git a/libexec/ld.so/sod.c b/libexec/ld.so/sod.c index f8589611ddf..eb42997162b 100644 --- a/libexec/ld.so/sod.c +++ b/libexec/ld.so/sod.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sod.c,v 1.16 2003/02/02 16:57:58 deraadt Exp $ */ +/* $OpenBSD: sod.c,v 1.17 2003/05/08 16:30:52 millert Exp $ */ /* * Copyright (c) 1993 Paul Kranenburg @@ -37,6 +37,7 @@ #include <fcntl.h> #include <nlist.h> #include <link.h> +#include <limits.h> #include <machine/exec.h> #include <sys/mman.h> #include <string.h> @@ -48,7 +49,6 @@ #include "util.h" #include "sod.h" -#define PAGSIZ __LDPGSZ int _dl_hinthash(char *cp, int vmajor, int vminor); /* @@ -129,8 +129,6 @@ backout: sodp->sod_name = (long)_dl_strdup(name); } -static int hfd; -static long hsize; static struct hints_header *hheader = NULL; static struct hints_bucket *hbuckets; static char *hstrtab; @@ -141,48 +139,30 @@ char *_dl_hint_search_path = NULL; void _dl_maphints(void) { - caddr_t addr; + struct stat sb; + caddr_t addr = MAP_FAILED; + long hsize = 0; + int hfd; - if ((hfd = _dl_open(_PATH_LD_HINTS, O_RDONLY)) < 0) { - hheader = (struct hints_header *)-1; - return; - } + if ((hfd = _dl_open(_PATH_LD_HINTS, O_RDONLY)) < 0) + goto bad_hints; - hsize = PAGSIZ; - addr = (void *) _dl_mmap(0, hsize, PROT_READ, MAP_PRIVATE, hfd, 0); + if (_dl_fstat(hfd, &sb) != 0 || !S_ISREG(sb.st_mode) || + sb.st_size < sizeof(struct hints_header) || sb.st_size > LONG_MAX) + goto bad_hints; - if (addr == MAP_FAILED) { - _dl_close(hfd); - hheader = (struct hints_header *)-1; - return; - } + hsize = (long)sb.st_size; + addr = (void *)_dl_mmap(0, hsize, PROT_READ, MAP_PRIVATE, hfd, 0); + if (addr == MAP_FAILED) + goto bad_hints; hheader = (struct hints_header *)addr; - if (HH_BADMAG(*hheader)) { - _dl_munmap(addr, hsize); - _dl_close(hfd); - hheader = (struct hints_header *)-1; - return; - } + if (HH_BADMAG(*hheader) || hheader->hh_ehints > hsize) + goto bad_hints; if (hheader->hh_version != LD_HINTS_VERSION_1 && - hheader->hh_version != LD_HINTS_VERSION_2) { - _dl_munmap(addr, hsize); - _dl_close(hfd); - hheader = (struct hints_header *)-1; - return; - } - - if (hheader->hh_ehints > hsize) { - if ((caddr_t)_dl_mmap(addr+hsize, hheader->hh_ehints - hsize, - PROT_READ, MAP_PRIVATE|MAP_FIXED, - hfd, hsize) != (caddr_t)(addr+hsize)) { - _dl_munmap((caddr_t)hheader, hsize); - _dl_close(hfd); - hheader = (struct hints_header *)-1; - return; - } - } + hheader->hh_version != LD_HINTS_VERSION_2) + goto bad_hints; hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab); hstrtab = (char *)(addr + hheader->hh_strtab); @@ -191,6 +171,15 @@ _dl_maphints(void) /* close the file descriptor, leaving the hints mapped */ _dl_close(hfd); + + return; + +bad_hints: + if (addr != MAP_FAILED) + _dl_munmap(addr, hsize); + if (hfd != -1) + _dl_close(hfd); + hheader = (struct hints_header *)-1; } char * |