diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2016-05-25 18:10:44 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2016-05-25 18:10:44 +0000 |
| commit | 360ba6bc13d1d194f1b3a345d4afc150aba0c6ae (patch) | |
| tree | 81a138b0de207a016c47cb44944f4335bfbe51c5 /libexec/rtld-elf/rtld.c | |
| parent | 7813f8309c545f0e2a7e6e57484fc9eae1616852 (diff) | |
Notes
Diffstat (limited to 'libexec/rtld-elf/rtld.c')
| -rw-r--r-- | libexec/rtld-elf/rtld.c | 35 |
1 files changed, 28 insertions, 7 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index b7811cb3139a..1869194150ed 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1667,14 +1667,16 @@ static const char * gethints(bool nostdlib) { static char *hints, *filtered_path; - struct elfhints_hdr hdr; + static struct elfhints_hdr hdr; struct fill_search_info_args sargs, hargs; struct dl_serinfo smeta, hmeta, *SLPinfo, *hintinfo; struct dl_serpath *SLPpath, *hintpath; char *p; + struct stat hint_stat; unsigned int SLPndx, hintndx, fndx, fcount; int fd; size_t flen; + uint32_t dl; bool skip; /* First call, read the hints file */ @@ -1684,19 +1686,38 @@ gethints(bool nostdlib) if ((fd = open(ld_elf_hints_path, O_RDONLY | O_CLOEXEC)) == -1) return (NULL); + + /* + * Check of hdr.dirlistlen value against type limit + * intends to pacify static analyzers. Further + * paranoia leads to checks that dirlist is fully + * contained in the file range. + */ if (read(fd, &hdr, sizeof hdr) != sizeof hdr || hdr.magic != ELFHINTS_MAGIC || - hdr.version != 1) { + hdr.version != 1 || hdr.dirlistlen > UINT_MAX / 2 || + fstat(fd, &hint_stat) == -1) { +cleanup1: close(fd); + hdr.dirlistlen = 0; return (NULL); } + dl = hdr.strtab; + if (dl + hdr.dirlist < dl) + goto cleanup1; + dl += hdr.dirlist; + if (dl + hdr.dirlistlen < dl) + goto cleanup1; + dl += hdr.dirlistlen; + if (dl > hint_stat.st_size) + goto cleanup1; p = xmalloc(hdr.dirlistlen + 1); + if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 || read(fd, p, hdr.dirlistlen + 1) != - (ssize_t)hdr.dirlistlen + 1) { + (ssize_t)hdr.dirlistlen + 1 || p[hdr.dirlistlen] != '\0') { free(p); - close(fd); - return (NULL); + goto cleanup1; } hints = p; close(fd); @@ -1729,7 +1750,7 @@ gethints(bool nostdlib) hargs.serinfo = &hmeta; path_enumerate(ld_standard_library_path, fill_search_info, &sargs); - path_enumerate(p, fill_search_info, &hargs); + path_enumerate(hints, fill_search_info, &hargs); SLPinfo = xmalloc(smeta.dls_size); hintinfo = xmalloc(hmeta.dls_size); @@ -1748,7 +1769,7 @@ gethints(bool nostdlib) hargs.strspace = (char *)&hintinfo->dls_serpath[hmeta.dls_cnt]; path_enumerate(ld_standard_library_path, fill_search_info, &sargs); - path_enumerate(p, fill_search_info, &hargs); + path_enumerate(hints, fill_search_info, &hargs); /* * Now calculate the difference between two sets, by excluding |
