svn commit: r300691 - head/libexec/rtld-elf

Konstantin Belousov kib at FreeBSD.org
Wed May 25 18:10:45 UTC 2016


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


More information about the svn-src-all mailing list