diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -2080,8 +2080,10 @@ /* Keep from trying again in case the hints file is bad. */ hints = ""; - if ((fd = open(ld_elf_hints_path, O_RDONLY | O_CLOEXEC)) == -1) + if ((fd = open(ld_elf_hints_path, O_RDONLY | O_CLOEXEC)) == -1) { + dbg("failed to open hints file \"%s\"", ld_elf_hints_path); return (NULL); + } /* * Check of hdr.dirlistlen value against type limit @@ -2089,29 +2091,57 @@ * 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.dirlistlen > UINT_MAX / 2 || - fstat(fd, &hint_stat) == -1) { + if (read(fd, &hdr, sizeof hdr) != sizeof hdr) { + dbg("failed to read %lu bytes from hints file \"%s\"", + (u_long)sizeof hdr, ld_elf_hints_path); cleanup1: close(fd); - hdr.dirlistlen = 0; return (NULL); } + if (hdr.magic != ELFHINTS_MAGIC) { + dbg("invalid magic number %08x (expected: %08x)", + hdr.magic, ELFHINTS_MAGIC); + goto cleanup1; + } + if (hdr.version != 1) { + dbg("hints file version %d (expected: 1)", hdr.version); + goto cleanup1; + } + if (hdr.dirlistlen > UINT_MAX / 2) { + dbg("directory list to long: %d > %d", + hdr.dirlistlen, UINT_MAX / 2); + goto cleanup1; + } + if (fstat(fd, &hint_stat) == -1) { + dbg("failed to find length of hints file \"%s\"", + ld_elf_hints_path); + goto cleanup1; + } dl = hdr.strtab; - if (dl + hdr.dirlist < dl) + if (dl + hdr.dirlist < dl) { + dbg("invalid string table position %d", dl); + goto cleanup1; + } goto cleanup1; dl += hdr.dirlist; - if (dl + hdr.dirlistlen < dl) + if (dl + hdr.dirlistlen < dl) { + dbg("invalid directory list offset %d", hdr.dirlist); + goto cleanup1; + } goto cleanup1; dl += hdr.dirlistlen; - if (dl > hint_stat.st_size) + if (dl > hint_stat.st_size) { + dbg("hints file \"%s\" is truncated (%d vs. %lld bytes)", + ld_elf_hints_path, dl, (unsigned long long)hint_stat.st_size); goto cleanup1; + } p = xmalloc(hdr.dirlistlen + 1); if (pread(fd, p, hdr.dirlistlen + 1, hdr.strtab + hdr.dirlist) != (ssize_t)hdr.dirlistlen + 1 || p[hdr.dirlistlen] != '\0') { free(p); + dbg("failed to read %d bytes starting at %d from hints file \"%s\"", + hdr.dirlistlen + 1, hdr.strtab + hdr.dirlist, ld_elf_hints_path); goto cleanup1; } hints = p;