diff options
Diffstat (limited to 'elf/dl-load.c')
-rw-r--r-- | elf/dl-load.c | 143 |
1 files changed, 76 insertions, 67 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c index 46f0b67567..6e8b977195 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -31,8 +31,7 @@ #include "dynamic-link.h" #include <stdio-common/_itoa.h> -#include <dl-origin.h> - +#include <dl-dst.h> /* On some systems, no flag bits are given to specify file mapping. */ #ifndef MAP_FILE @@ -146,129 +145,139 @@ local_strdup (const char *s) return (char *) memcpy (new, s, len); } -/* Return copy of argument with all recognized dynamic string tokens - ($ORIGIN and $PLATFORM for now) replaced. On some platforms it - might not be possible to determine the path from which the object - belonging to the map is loaded. In this case the path element - containing $ORIGIN is left out. */ -static char * -expand_dynamic_string_token (struct link_map *l, const char *s) + +size_t +_dl_dst_count (const char *name, int is_path) { - /* We make two runs over the string. First we determine how large the - resulting string is and then we copy it over. Since this is now - frequently executed operation we are looking here not for performance - but rather for code size. */ - const char *sf; size_t cnt = 0; - size_t origin_len; - size_t total; - char *result, *last_elem, *wp; - sf = strchr (s, '$'); - while (sf != NULL) + do { size_t len = 1; /* $ORIGIN is not expanded for SUID/GUID programs. */ if ((((!__libc_enable_secure - && strncmp (&sf[1], "ORIGIN", 6) == 0 && (len = 7) != 0) - || (strncmp (&sf[1], "PLATFORM", 8) == 0 && (len = 9) != 0)) - && (s[len] == '\0' || s[len] == '/' || s[len] == ':')) - || (s[1] == '{' + && strncmp (&name[1], "ORIGIN", 6) == 0 && (len = 7) != 0) + || (strncmp (&name[1], "PLATFORM", 8) == 0 && (len = 9) != 0)) + && (name[len] == '\0' || name[len] == '/' + || (is_path && name[len] == ':'))) + || (name[1] == '{' && ((!__libc_enable_secure - && strncmp (&sf[2], "ORIGIN}", 7) == 0 && (len = 9) != 0) - || (strncmp (&sf[2], "PLATFORM}", 9) == 0 + && strncmp (&name[2], "ORIGIN}", 7) == 0 && (len = 9) != 0) + || (strncmp (&name[2], "PLATFORM}", 9) == 0 && (len = 11) != 0)))) ++cnt; - sf = strchr (sf + len, '$'); + name = strchr (name + len, '$'); } + while (name != NULL); - /* If we do not have to replace anything simply copy the string. */ - if (cnt == 0) - return local_strdup (s); - - /* Now we make a guess how many extra characters on top of the length - of S we need to represent the result. We know that we have CNT - replacements. Each at most can use - MAX (strlen (ORIGIN), strlen (_dl_platform)) - minus 7 (which is the length of "$ORIGIN"). + return cnt; +} - First get the origin string if it is not available yet. This can - only happen for the map of the executable. */ - if (l->l_origin == NULL) - { - assert (l->l_name[0] == '\0'); - l->l_origin = get_origin (); - origin_len = (l->l_origin && l->l_origin != (char *) -1 - ? strlen (l->l_origin) : 0); - } - else - origin_len = l->l_origin == (char *) -1 ? 0 : strlen (l->l_origin); - total = strlen (s) + cnt * (MAX (origin_len, _dl_platformlen) - 7); - result = (char *) malloc (total + 1); - if (result == NULL) - return NULL; +char * +_dl_dst_substitute (struct link_map *l, const char *name, char *result, + int is_path) +{ + char *last_elem, *wp; /* Now fill the result path. While copying over the string we keep track of the start of the last path element. When we come accross a DST we copy over the value or (if the value is not available) leave the entire path element out. */ last_elem = wp = result; + do { - if (*s == '$') + if (*name == '$') { const char *repl; size_t len; - if ((((strncmp (&s[1], "ORIGIN", 6) == 0 && (len = 7) != 0) - || (strncmp (&s[1], "PLATFORM", 8) == 0 && (len = 9) != 0)) - && (s[len] == '\0' || s[len] == '/' || s[len] == ':')) - || (s[1] == '{' - && ((strncmp (&s[2], "ORIGIN}", 7) == 0 && (len = 9) != 0) - || (strncmp (&s[2], "PLATFORM}", 9) == 0 + if ((((strncmp (&name[1], "ORIGIN", 6) == 0 && (len = 7) != 0) + || (strncmp (&name[1], "PLATFORM", 8) == 0 && (len = 9) != 0)) + && (name[len] == '\0' || name[len] == '/' + || (is_path && name[len] == ':'))) + || (name[1] == '{' + && ((strncmp (&name[2], "ORIGIN}", 7) == 0 && (len = 9) != 0) + || (strncmp (&name[2], "PLATFORM}", 9) == 0 && (len = 11) != 0)))) { - repl = ((len == 7 || s[2] == 'O') + repl = ((len == 7 || name[2] == 'O') ? (__libc_enable_secure ? NULL : l->l_origin) : _dl_platform); if (repl != NULL && repl != (const char *) -1) { wp = __stpcpy (wp, repl); - s += len; + name += len; } else { /* We cannot use this path element, the value of the replacement is unknown. */ wp = last_elem; - s += len; - while (*s != '\0' && *s != ':') - ++s; + name += len; + while (*name != '\0' && (!is_path || *name != ':')) + ++name; } } else /* No DST we recognize. */ - *wp++ = *s++; + *wp++ = *name++; } - else if (*s == ':') + else if (is_path && *name == ':') { - *wp++ = *s++; + *wp++ = *name++; last_elem = wp; } else - *wp++ = *s++; + *wp++ = *name++; } - while (*s != '\0'); + while (*name != '\0'); *wp = '\0'; return result; } + +/* Return copy of argument with all recognized dynamic string tokens + ($ORIGIN and $PLATFORM for now) replaced. On some platforms it + might not be possible to determine the path from which the object + belonging to the map is loaded. In this case the path element + containing $ORIGIN is left out. */ +static char * +expand_dynamic_string_token (struct link_map *l, const char *s) +{ + /* We make two runs over the string. First we determine how large the + resulting string is and then we copy it over. Since this is now + frequently executed operation we are looking here not for performance + but rather for code size. */ + size_t cnt; + size_t total; + char *result; + + /* Determine the nubmer of DST elements. */ + cnt = DL_DST_COUNT (s, 1); + + /* If we do not have to replace anything simply copy the string. */ + if (cnt == 0) + return local_strdup (s); + + /* Determine the length of the substituted string. */ + total = DL_DST_REQUIRED (l, s, strlen (s), cnt); + + /* Allocate the necessary memory. */ + result = (char *) malloc (total + 1); + if (result == NULL) + return NULL; + + return DL_DST_SUBSTITUTE (l, s, result, 1); +} + + /* Add `name' to the list of names for a particular shared object. `name' is expected to have been allocated with malloc and will be freed if the shared object already has this name. |