You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
3.2 KiB
103 lines
3.2 KiB
commit TBD |
|
Author: Florian Weimer <fweimer@redhat.com> |
|
Date: Fri May 19 17:46:47 2017 +0200 |
|
|
|
rtld: Reject overly long LD_PRELOAD path elements |
|
|
|
Index: b/elf/rtld.c |
|
=================================================================== |
|
--- a/elf/rtld.c |
|
+++ b/elf/rtld.c |
|
@@ -99,6 +99,22 @@ uintptr_t __pointer_chk_guard_local |
|
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) |
|
#endif |
|
|
|
+/* Check that AT_SECURE=0, or that the passed name does not contain |
|
+ directories and is not overly long. Reject empty names |
|
+ unconditionally. */ |
|
+static bool |
|
+dso_name_valid_for_suid (const char *p) |
|
+{ |
|
+ if (__builtin_expect (INTUSE(__libc_enable_secure), 0)) |
|
+ { |
|
+ /* Ignore pathnames with directories for AT_SECURE=1 |
|
+ programs, and also skip overlong names. */ |
|
+ size_t len = strlen (p); |
|
+ if (len >= NAME_MAX || memchr (p, '/', len) != NULL) |
|
+ return false; |
|
+ } |
|
+ return *p != '\0'; |
|
+} |
|
|
|
/* List of auditing DSOs. */ |
|
static struct audit_list |
|
@@ -880,6 +896,44 @@ static const char *preloadlist attribute |
|
/* Nonzero if information about versions has to be printed. */ |
|
static int version_info attribute_relro; |
|
|
|
+/* The LD_PRELOAD environment variable gives list of libraries |
|
+ separated by white space or colons that are loaded before the |
|
+ executable's dependencies and prepended to the global scope list. |
|
+ (If the binary is running setuid all elements containing a '/' are |
|
+ ignored since it is insecure.) Return the number of preloads |
|
+ performed. */ |
|
+unsigned int |
|
+handle_ld_preload (const char *preloadlist, struct link_map *main_map) |
|
+{ |
|
+ unsigned int npreloads = 0; |
|
+ const char *p = preloadlist; |
|
+ char fname[PATH_MAX]; |
|
+ |
|
+ while (*p != '\0') |
|
+ { |
|
+ /* Split preload list at space/colon. */ |
|
+ size_t len = strcspn (p, " :"); |
|
+ if (len > 0 && len < PATH_MAX) |
|
+ { |
|
+ memcpy (fname, p, len); |
|
+ fname[len] = '\0'; |
|
+ } |
|
+ else |
|
+ fname[0] = '\0'; |
|
+ |
|
+ /* Skip over the substring and the following delimiter. */ |
|
+ p += len; |
|
+ if (*p == ' ' || *p == ':') |
|
+ ++p; |
|
+ |
|
+ if (dso_name_valid_for_suid (fname)) |
|
+ npreloads += do_preload (fname, main_map, "LD_PRELOAD"); |
|
+ } |
|
+ return npreloads; |
|
+} |
|
+ |
|
+ |
|
+ |
|
static void |
|
dl_main (const ElfW(Phdr) *phdr, |
|
ElfW(Word) phnum, |
|
@@ -1611,23 +1665,8 @@ ERROR: ld.so: object '%s' cannot be load |
|
|
|
if (__builtin_expect (preloadlist != NULL, 0)) |
|
{ |
|
- /* The LD_PRELOAD environment variable gives list of libraries |
|
- separated by white space or colons that are loaded before the |
|
- executable's dependencies and prepended to the global scope |
|
- list. If the binary is running setuid all elements |
|
- containing a '/' are ignored since it is insecure. */ |
|
- char *list = strdupa (preloadlist); |
|
- char *p; |
|
- |
|
HP_TIMING_NOW (start); |
|
- |
|
- /* Prevent optimizing strsep. Speed is not important here. */ |
|
- while ((p = (strsep) (&list, " :")) != NULL) |
|
- if (p[0] != '\0' |
|
- && (__builtin_expect (! INTUSE(__libc_enable_secure), 1) |
|
- || strchr (p, '/') == NULL)) |
|
- npreloads += do_preload (p, main_map, "LD_PRELOAD"); |
|
- |
|
+ npreloads += handle_ld_preload (preloadlist, main_map); |
|
HP_TIMING_NOW (stop); |
|
HP_TIMING_DIFF (diff, start, stop); |
|
HP_TIMING_ACCUM_NT (load_time, diff);
|
|
|