Short description: Work ld.so --verify crash on debuginfo files. Author(s): Fedora glibc team Origin: PATCH Bug-RHEL: #741105, #767146 Upstream status: not-needed This change is designed to work around running ld.so on a debuginfo file. This is the wrong fix for this problem and should be dropped. The correct solution is to mark debuginfo files as new types of ELF files. diff --git a/elf/dl-load.c b/elf/dl-load.c index 646c5dca40efcc9b..1f44ea3744f139f3 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -952,6 +952,18 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, in this information for the executable in case of an explicit loader invocation. */ struct r_file_id id; + struct stat64 st; + + if (__glibc_unlikely (!_dl_get_file_id (fd, &id, &st))) + { + errstring = N_("cannot stat shared object"); + call_lose_errno: + errval = errno; + call_lose: + lose (errval, fd, name, realname, l, errstring, + make_consistent ? r : NULL, nsid); + } + if (mode & __RTLD_OPENEXEC) { assert (nsid == LM_ID_BASE); @@ -959,16 +971,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, } else { - if (__glibc_unlikely (!_dl_get_file_id (fd, &id))) - { - errstring = N_("cannot stat shared object"); - call_lose_errno: - errval = errno; - call_lose: - lose (errval, fd, name, realname, l, errstring, - make_consistent ? r : NULL, nsid); - } - /* Look again to see if the real name matched another already loaded. */ for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) @@ -1147,6 +1149,16 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, = N_("ELF load command address/offset not properly aligned"); goto call_lose; } + if (__glibc_unlikely (ph->p_offset + ph->p_filesz > st.st_size)) + { + /* If the segment requires zeroing of part of its last + page, we'll crash when accessing the unmapped page. + There's still a possibility of a race, if the shared + object is truncated between the fxstat above and the + memset below. */ + errstring = N_("ELF load command past end of file"); + goto call_lose; + } struct loadcmd *c = &loadcmds[nloadcmds++]; c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize)); diff --git a/sysdeps/generic/dl-fileid.h b/sysdeps/generic/dl-fileid.h index 459328d28c62c8e1..5070580b1b0cc629 100644 --- a/sysdeps/generic/dl-fileid.h +++ b/sysdeps/generic/dl-fileid.h @@ -29,7 +29,8 @@ struct r_file_id On error, returns false, with errno set. */ static inline bool _dl_get_file_id (int fd __attribute__ ((unused)), - struct r_file_id *id __attribute__ ((unused))) + struct r_file_id *id __attribute__ ((unused)), + struct stat64_t *st __attribute__((unused))) { return true; } diff --git a/sysdeps/posix/dl-fileid.h b/sysdeps/posix/dl-fileid.h index b3c8166701650b8b..cd862f511e6e3e94 100644 --- a/sysdeps/posix/dl-fileid.h +++ b/sysdeps/posix/dl-fileid.h @@ -27,18 +27,16 @@ struct r_file_id ino64_t ino; }; -/* Sample FD to fill in *ID. Returns true on success. +/* Sample FD to fill in *ID and *ST. Returns true on success. On error, returns false, with errno set. */ static inline bool -_dl_get_file_id (int fd, struct r_file_id *id) +_dl_get_file_id (int fd, struct r_file_id *id, struct stat64 *st) { - struct stat64 st; - - if (__glibc_unlikely (__fstat64 (fd, &st) < 0)) + if (__glibc_unlikely (__fstat64 (fd, st) < 0)) return false; - id->dev = st.st_dev; - id->ino = st.st_ino; + id->dev = st->st_dev; + id->ino = st->st_ino; return true; }