📄 dl-load.c
字号:
maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); if (ehdr->e_phoff + maplength <= fbp->len) phdr = (void *) (fbp->buf + ehdr->e_phoff); else { phdr = alloca (maplength); lseek (fd, SEEK_SET, ehdr->e_phoff); if (__libc_read (fd, (void *) phdr, maplength) != maplength) { read_error: errval = errno; errstring = N_("cannot read file data"); goto call_lose; } } /* Check .note.ABI-tag if present. */ for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph) if (ph->p_type == PT_NOTE && ph->p_filesz == 32 && ph->p_align >= 4) { if (ph->p_offset + 32 <= fbp->len) abi_note = (void *) (fbp->buf + ph->p_offset); else { lseek (fd, SEEK_SET, ph->p_offset); if (__libc_read (fd, (void *) abi_note_buf, 32) != 32) goto read_error; abi_note = abi_note_buf; } if (memcmp (abi_note, &expected_note, sizeof (expected_note))) continue; osversion = (abi_note[5] & 0xff) * 65536 + (abi_note[6] & 0xff) * 256 + (abi_note[7] & 0xff); if (abi_note[4] != __ABI_TAG_OS || (_dl_osversion && _dl_osversion < osversion)) { close_and_out: close (fd); __set_errno (ENOENT); fd = -1; } break; } } return fd;}/* Try to open NAME in one of the directories in *DIRSP. Return the fd, or -1. If successful, fill in *REALNAME with the malloc'd full directory name. If it turns out that none of the directories in *DIRSP exists, *DIRSP is replaced with (void *) -1, and the old value is free()d if MAY_FREE_DIRS is true. */static intopen_path (const char *name, size_t namelen, int preloaded, struct r_search_path_struct *sps, char **realname, struct filebuf *fbp){ struct r_search_path_elem **dirs = sps->dirs; char *buf; int fd = -1; const char *current_what = NULL; int any = 0; buf = alloca (max_dirnamelen + max_capstrlen + namelen); do { struct r_search_path_elem *this_dir = *dirs; size_t buflen = 0; size_t cnt; char *edp; int here_any = 0; int err; /* If we are debugging the search for libraries print the path now if it hasn't happened now. */ if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0) && current_what != this_dir->what) { current_what = this_dir->what; print_search_path (dirs, current_what, this_dir->where); } edp = (char *) (memcpy (buf, this_dir->dirname, this_dir->dirnamelen) + this_dir->dirnamelen); for (cnt = 0; fd == -1 && cnt < ncapstr; ++cnt) { char *tmp; /* Skip this directory if we know it does not exist. */ if (this_dir->status[cnt] == nonexisting) continue; tmp = memcpy (edp, capstr[cnt].str, capstr[cnt].len); tmp += capstr[cnt].len; tmp = memcpy (tmp, name, namelen); tmp += namelen; buflen = ((char *) (tmp - buf)); /* Print name we try if this is wanted. */ if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) _dl_debug_printf (" trying file=%s\n", buf); fd = open_verify (buf, fbp); if (this_dir->status[cnt] == unknown) { if (fd != -1) this_dir->status[cnt] = existing; else { /* We failed to open machine dependent library. Let's test whether there is any directory at all. */ struct stat64 st; buf[buflen - namelen - 1] = '\0'; if (stat64 (buf, &st) != 0 || ! S_ISDIR (st.st_mode)) /* The directory does not exist or it is no directory. */ this_dir->status[cnt] = nonexisting; else this_dir->status[cnt] = existing; } } /* Remember whether we found any existing directory. */ here_any |= this_dir->status[cnt] == existing; if (fd != -1 && __builtin_expect (preloaded, 0) && 0) { /* This is an extra security effort to make sure nobody can preload broken shared objects which are in the trusted directories and so exploit the bugs. */ struct stat64 st; if (fstat64 (fd, &st) != 0 || (st.st_mode & S_ISUID) == 0) { /* The shared object cannot be tested for being SUID or this bit is not set. In this case we must not use this object. */ close (fd); fd = -1; /* We simply ignore the file, signal this by setting the error value which would have been set by `open'. */ errno = ENOENT; } } } if (fd != -1) { *realname = (char *) malloc (buflen); if (*realname != NULL) { memcpy (*realname, buf, buflen); return fd; } else { /* No memory for the name, we certainly won't be able to load and link it. */ close (fd); return -1; } } if (here_any && (err = errno) != ENOENT && err != EACCES) /* The file exists and is readable, but something went wrong. */ return -1; /* Remember whether we found anything. */ any |= here_any; } while (*++dirs != NULL); /* Remove the whole path if none of the directories exists. */ if (__builtin_expect (! any, 0)) { /* Paths which were allocated using the minimal malloc() in ld.so must not be freed using the general free() in libc. */ if (sps->malloced) free (sps->dirs); sps->dirs = (void *) -1; } return -1;}/* Map in the shared object file NAME. */struct link_map *internal_function_dl_map_object (struct link_map *loader, const char *name, int preloaded, int type, int trace_mode, int mode){ int fd; char *realname; char *name_copy; struct link_map *l; struct filebuf fb; /* Look for this name among those already loaded. */ for (l = _dl_loaded; l; l = l->l_next) { /* If the requested name matches the soname of a loaded object, use that object. Elide this check for names that have not yet been opened. */ if (__builtin_expect (l->l_faked, 0) != 0) continue; if (!_dl_name_match_p (name, l)) { const char *soname; if (__builtin_expect (l->l_soname_added, 1) || l->l_info[DT_SONAME] == NULL) continue; soname = ((const char *) D_PTR (l, l_info[DT_STRTAB]) + l->l_info[DT_SONAME]->d_un.d_val); if (strcmp (name, soname) != 0) continue; /* We have a match on a new name -- cache it. */ add_name_to_object (l, soname); l->l_soname_added = 1; } /* We have a match. */ return l; } /* Display information if we are debugging. */ if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0) && loader != NULL) _dl_debug_printf ("\nfile=%s; needed by %s\n", name, loader->l_name[0] ? loader->l_name : _dl_argv[0]); if (strchr (name, '/') == NULL) { /* Search for NAME in several places. */ size_t namelen = strlen (name) + 1; if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) _dl_debug_printf ("find library=%s; searching\n", name); fd = -1; /* When the object has the RUNPATH information we don't use any RPATHs. */ if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL) { /* First try the DT_RPATH of the dependent object that caused NAME to be loaded. Then that object's dependent, and on up. */ for (l = loader; fd == -1 && l; l = l->l_loader) { if (l->l_rpath_dirs.dirs == NULL) { if (l->l_info[DT_RPATH] == NULL) { /* There is no path. */ l->l_rpath_dirs.dirs = (void *) -1; continue; } else { /* Make sure the cache information is available. */ size_t ptrval = (D_PTR (l, l_info[DT_STRTAB]) + l->l_info[DT_RPATH]->d_un.d_val); decompose_rpath (&l->l_rpath_dirs, (const char *) ptrval, l, "RPATH"); } } if (l->l_rpath_dirs.dirs != (void *) -1) fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, &realname, &fb); } /* If dynamically linked, try the DT_RPATH of the executable itself. */ l = _dl_loaded; if (fd == -1 && l && l->l_type != lt_loaded && l != loader && l->l_rpath_dirs.dirs != (void *) -1) fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, &realname, &fb); } /* Try the LD_LIBRARY_PATH environment variable. */ if (fd == -1 && env_path_list.dirs != (void *) -1) fd = open_path (name, namelen, preloaded, &env_path_list, &realname, &fb); /* Look at the RUNPATH information for this binary. Note that this is no real loop. 'while' is used only to enable us to use 'break' instead of a 'goto' to jump to the end. The loop is always left after the first round. */ while (fd == -1 && loader != NULL && loader->l_runpath_dirs.dirs != (void *) -1) { if (loader->l_runpath_dirs.dirs == NULL) { if (loader->l_info[DT_RUNPATH] == NULL) { /* No RUNPATH. */ loader->l_runpath_dirs.dirs = (void *) -1; break; } else { /* Make sure the cache information is available. */ size_t ptrval = (D_PTR (loader, l_info[DT_STRTAB]) + loader->l_info[DT_RUNPATH]->d_un.d_val); decompose_rpath (&loader->l_runpath_dirs, (const char *) ptrval, loader, "RUNPATH"); } } if (loader->l_runpath_dirs.dirs != (void *) -1) fd = open_path (name, namelen, preloaded, &loader->l_runpath_dirs, &realname, &fb); break; } if (fd == -1 && (__builtin_expect (! preloaded, 1) || ! 0)) { /* Check the list of libraries in the file /etc/ld.so.cache, for compatibility with Linux's ldconfig program. */ const char *cached = _dl_load_cache_lookup (name); if (cached != NULL) {#ifdef SHARED l = loader ?: _dl_loaded;#else l = loader;#endif /* If the loader has the DF_1_NODEFLIB flag set we must not use a cache entry from any of these directories. */ if (#ifndef SHARED /* 'l' is always != NULL for dynamically linked objects. */ l != NULL &&#endif __builtin_expect (l->l_flags_1 & DF_1_NODEFLIB, 0)) { const char *dirp = system_dirs; unsigned int cnt = 0; do { if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0) { /* The prefix matches. Don't use the entry. */ cached = NULL; break; } dirp += system_dirs_len[cnt] + 1; ++cnt; } while (cnt < nsystem_dirs_len); } if (cached != NULL) { fd = open_verify (cached, &fb); if (__builtin_expect (fd != -1, 1)) { realname = local_strdup (cached); if (realname == NULL) { close (fd); fd = -1; } } } } } /* Finally, try the default path. */ if (fd == -1 && ((l = loader ?: _dl_loaded) /* 'l' is always != NULL for dynamically linked objects. */#ifdef SHARED ,#else == NULL ||#endif __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1)) && rtld_search_dirs.dirs != (void *) -1) fd = open_path (name, namelen, preloaded, &rtld_search_dirs, &realname, &fb); /* Add another newline when we a tracing the library loading. */ if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) _dl_debug_printf ("\n"); } else { /* The path may contain dynamic string tokens. */ realname = (loader ? expand_dynamic_string_token (loader, name) : local_strdup (name)); if (realname == NULL) fd = -1; else { fd = open_verify (realname, &fb); if (__builtin_expect (fd, 0) == -1) free (realname); } } if (__builtin_expect (fd, 0) == -1) { if (trace_mode) { /* We haven't found an appropriate library. But since we are only interested in the list of libraries this isn't so severe. Fake an entry with all the information we have. */ static const Elf_Symndx dummy_bucket = STN_UNDEF; /* Enter the new object in the list of loaded objects. */ if ((name_copy = local_strdup (name)) == NULL || (l = _dl_new_object (name_copy, name, type, loader)) == NULL) _dl_signal_error (ENOMEM, name, NULL, N_("cannot create shared object descriptor")); /* Signal that this is a faked entry. */ l->l_faked = 1; /* Since the descriptor is initialized with zero we do not have do this here. l->l_reserved = 0; */ l->l_buckets = &dummy_bucket; l->l_nbuckets = 1; l->l_relocated = 1; return l; } else _dl_signal_error (errno, name, NULL, N_("cannot open shared object file")); } return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -