summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2016-05-25 18:10:44 +0000
committerkib <kib@FreeBSD.org>2016-05-25 18:10:44 +0000
commit95a437124baf399b7a62c426eb61f60401c0f4c0 (patch)
tree81a138b0de207a016c47cb44944f4335bfbe51c5 /libexec
parent03a8f3fe54fa20421ce5ada0b4e1aa0ec891fe10 (diff)
downloadFreeBSD-src-95a437124baf399b7a62c426eb61f60401c0f4c0.zip
FreeBSD-src-95a437124baf399b7a62c426eb61f60401c0f4c0.tar.gz
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
Diffstat (limited to 'libexec')
-rw-r--r--libexec/rtld-elf/rtld.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index b7811cb..1869194 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
OpenPOWER on IntegriCloud