Date: Wed, 25 May 2016 18:10:44 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r300691 - head/libexec/rtld-elf Message-ID: <201605251810.u4PIAiFp023680@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Wed May 25 18:10:44 2016 New Revision: 300691 URL: https://svnweb.freebsd.org/changeset/base/300691 Log: Fix issues found by Coverity in the rtld-elf.c:gethints(). Check that the dirlist path string specification does not cause overflow and is fully contained in the hints file. Check that the dirlist string is nul-terminated. Make 'hdr' static variable, so that hdr.dirlistlen is available when hints cached value is used on next function calls. Reset hdr.dirlistlen to zero if error was detected, so that allocations use reasonable size. Use 'hints', and not 'p' in the body, since p is only initialized on the first call. Reported and reviewed by: truckman (previous version) Sponsored by: The FreeBSD Foundation CIDs: 1006503, 1006504, 1006676, 1008488, 1007263 MFC after: 2 weeks Modified: head/libexec/rtld-elf/rtld.c Modified: head/libexec/rtld-elf/rtld.c ============================================================================== --- head/libexec/rtld-elf/rtld.c Wed May 25 17:10:10 2016 (r300690) +++ head/libexec/rtld-elf/rtld.c Wed May 25 18:10:44 2016 (r300691) @@ -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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201605251810.u4PIAiFp023680>