summaryrefslogtreecommitdiff
path: root/libexec/ld.so/sod.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-05-08 16:30:53 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-05-08 16:30:53 +0000
commit4c9e8a8f53881a9a4c55bc44c342ae3e39186074 (patch)
tree9f0d5c09c519988574383ab107d6528dd167ee9f /libexec/ld.so/sod.c
parent005f055d6703a25a26e4f35aac777dfdac0c2b0f (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.c67
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 *