/* This function's behavior must exactly match that * in uClibc/ldso/util/ldd.c */ static struct elf_resolve * search_for_named_library(const char *name, unsigned int rflags, const char *path_list, struct dyn_elf **rpnt, const char* origin) { char *mylibname; struct elf_resolve *tpnt; const char *p, *pn; int plen; if (path_list==NULL) return NULL; /* another bit of local storage */ mylibname = alloca(2050); /* Unlike ldd.c, don't bother to eliminate double //s */ /* Replace colons with zeros in path_list */ /* : at the beginning or end of path maps to CWD */ /* :: anywhere maps CWD */ /* "" maps to CWD */ for (p = path_list; p != NULL; p = pn) { pn = _dl_strchr(p + 1, ':'); if (pn != NULL) { plen = pn - p; pn++; } else plen = _dl_strlen(p); if (plen >= 7 && _dl_memcmp(p, "$ORIGIN", 7) == 0) { int olen; /* $ORIGIN is not expanded for SUID/GUID programs (except if it is $ORIGIN alone) */ if ((rflags & __RTLD_SECURE) && plen != 7) continue; if (origin == NULL) continue; for (olen = _dl_strlen(origin) - 1; olen >= 0 && origin[olen] != '/'; olen--) ; if (olen <= 0) continue; _dl_memcpy(&mylibname[0], origin, olen); _dl_memcpy(&mylibname[olen], p + 7, plen - 7); mylibname[olen + plen - 7] = 0; } else if (plen != 0) { _dl_memcpy(mylibname, p, plen); mylibname[plen] = 0; } else { _dl_strcpy(mylibname, "."); } _dl_strcat(mylibname, "/"); _dl_strcat(mylibname, name); #ifdef __LDSO_SAFE_RUNPATH__ if (*mylibname == '/') #endif if ((tpnt = _dl_load_elf_shared_library(rflags, rpnt, mylibname)) != NULL) return tpnt; } return NULL; }
/* * Extract a trace specification field, and setup the tracespec struct * accordingly. */ const char * _dl_trace_parse_spec(const char *var, struct tracespec *spec) { const char *start, *end; if (*var == '!') { spec->inverse = 1; var++; } start = var; end = _dl_strchr(start, ':'); if (end == NULL) end = start + _dl_strlen(start); if (end != start) { spec->spec = _dl_malloc(1 + end - start); if (spec->spec == NULL) _dl_exit(8); _dl_bcopy(start, spec->spec, end - start); spec->spec[end - start] = '\0'; } if (*end == ':') end++; return end; }
/* * Check if a given name matches a trace specification list. */ static int _dl_trace_match(const char *name, struct tracespec *spec, int allow_so) { const char *list, *end, *next; size_t span; int match; /* no spec means trace everything */ if (spec->spec == NULL) return 1; match = 0; list = spec->spec; end = list + _dl_strlen(list); while (*list != '\0') { next = _dl_strchr(list, ','); if (next == NULL) next = end; span = next - list; if (span != 0 && *(next - 1) == '*') span--; if (span != 0 && _dl_strncmp(name, list, span) == 0) { /* * If the object name matches the specification * fragment so far, it's a match if: * + the specification ends in a star (wildcard * match) * + there are no remaining chars in both the * object name and the specification (exact * match) * + the specification ends (no star) and the * object name continues with ".so" (radix * match) and `allow_so' is nonzero. */ if (list[span] == '*' || name[span] == '\0' || (allow_so && _dl_strncmp(name + span, ".so", 3) == 0)) { match = 1; break; } } while (*next == ',') next++; list = next; } return spec->inverse ? !match : match; }
void _dl_trace_object_setup(elf_object_t *object) { const char *basename, *slash; object->traced = 0; if (_dl_traceplt) { basename = object->load_name; while (*basename == '/') { basename++; slash = _dl_strchr(basename, '/'); if (slash == NULL) break; basename = slash; } if (_dl_trace_match(basename, &_dl_tracelib, 1)) object->traced = 1; } }
/* * char *dl_realpath(const char *path, char resolved[PATH_MAX]); * * Find the real name of path, by removing all ".", ".." and symlink * components. Returns (resolved) on success, or (NULL) on failure, * in which case the path which caused trouble is left in (resolved). */ char * _dl_realpath(const char *path, char *resolved) { struct stat sb; const char *p, *s; char *q; size_t left_len, resolved_len; unsigned symlinks; int slen, mem_allocated, ret; char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; if (path[0] == '\0') { return (NULL); } if (resolved == NULL) { resolved = _dl_malloc(PATH_MAX); if (resolved == NULL) return (NULL); mem_allocated = 1; } else mem_allocated = 0; symlinks = 0; if (path[0] == '/') { resolved[0] = '/'; resolved[1] = '\0'; if (path[1] == '\0') return (resolved); resolved_len = 1; left_len = _dl_strlcpy(left, path + 1, sizeof(left)); } else { if (_dl_getcwd(resolved, PATH_MAX) <= 0) { if (mem_allocated) _dl_free(resolved); else _dl_strlcpy(resolved, ".", PATH_MAX); return (NULL); } resolved_len = _dl_strlen(resolved); left_len = _dl_strlcpy(left, path, sizeof(left)); } if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { goto err; } /* * Iterate over path components in `left'. */ while (left_len != 0) { /* * Extract the next path component and adjust `left' * and its length. */ p = _dl_strchr(left, '/'); s = p ? p : left + left_len; if (s - left >= sizeof(next_token)) { goto err; } _dl_bcopy(left, next_token, s - left); next_token[s - left] = '\0'; left_len -= s - left; if (p != NULL) _dl_bcopy(s + 1, left, left_len + 1); if (resolved[resolved_len - 1] != '/') { if (resolved_len + 1 >= PATH_MAX) { goto err; } resolved[resolved_len++] = '/'; resolved[resolved_len] = '\0'; } if (next_token[0] == '\0') continue; else if (_dl_strcmp(next_token, ".") == 0) continue; else if (_dl_strcmp(next_token, "..") == 0) { /* * Strip the last path component except when we have * single "/" */ if (resolved_len > 1) { resolved[resolved_len - 1] = '\0'; q = _dl_strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } continue; } /* * Append the next path component and lstat() it. If * lstat() fails we still can return successfully if * there are no more path components left. */ resolved_len = _dl_strlcat(resolved, next_token, PATH_MAX); if (resolved_len >= PATH_MAX) { goto err; } if ((ret = _dl_lstat(resolved, &sb)) != 0) { if (ret == ENOENT && p == NULL) { return (resolved); } goto err; } if (S_ISLNK(sb.st_mode)) { if (symlinks++ > SYMLOOP_MAX) { goto err; } slen = _dl_readlink(resolved, symlink, sizeof(symlink) - 1); if (slen < 0) goto err; symlink[slen] = '\0'; if (symlink[0] == '/') { resolved[1] = 0; resolved_len = 1; } else if (resolved_len > 1) { /* Strip the last path component. */ resolved[resolved_len - 1] = '\0'; q = _dl_strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } /* * If there are any path components left, then * append them to symlink. The result is placed * in `left'. */ if (p != NULL) { if (symlink[slen - 1] != '/') { if (slen + 1 >= sizeof(symlink)) { goto err; } symlink[slen] = '/'; symlink[slen + 1] = 0; } left_len = _dl_strlcat(symlink, left, sizeof(symlink)); if (left_len >= sizeof(left)) { goto err; } } left_len = _dl_strlcpy(left, symlink, sizeof(left)); } } /* * Remove trailing slash except when the resolved pathname * is a single "/". */ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') resolved[resolved_len - 1] = '\0'; return (resolved); err: if (mem_allocated) _dl_free(resolved); return (NULL); }