2017-06-26 02:58:17 +02:00
|
|
|
From 6d0ba622891bed9d8394eef1935add53003b12e8 Mon Sep 17 00:00:00 2001
|
2017-06-19 22:13:53 +02:00
|
|
|
From: Florian Weimer <fweimer@redhat.com>
|
2017-06-26 02:58:17 +02:00
|
|
|
Date: Mon, 19 Jun 2017 22:31:04 +0200
|
|
|
|
Subject: [PATCH] ld.so: Reject overly long LD_PRELOAD path elements
|
2017-06-19 22:13:53 +02:00
|
|
|
|
|
|
|
patch from:
|
2017-06-26 02:58:17 +02:00
|
|
|
https://sourceware.org/git/?p=glibc.git;a=patch;h=6d0ba622891bed9d8394eef1935add53003b12e8
|
2017-06-19 22:13:53 +02:00
|
|
|
|
|
|
|
---
|
2017-06-26 02:58:17 +02:00
|
|
|
ChangeLog | 7 ++++++
|
|
|
|
elf/rtld.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++------------
|
|
|
|
2 files changed, 73 insertions(+), 16 deletions(-)
|
2017-06-19 22:13:53 +02:00
|
|
|
|
|
|
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
2017-06-26 02:58:17 +02:00
|
|
|
index 2269dbe..86ae20c 100644
|
2017-06-19 22:13:53 +02:00
|
|
|
--- a/elf/rtld.c
|
|
|
|
+++ b/elf/rtld.c
|
2017-06-26 02:58:17 +02:00
|
|
|
@@ -99,6 +99,35 @@ uintptr_t __pointer_chk_guard_local
|
|
|
|
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
|
|
|
|
#endif
|
2017-06-19 22:13:53 +02:00
|
|
|
|
2017-06-26 02:58:17 +02:00
|
|
|
+/* Length limits for names and paths, to protect the dynamic linker,
|
|
|
|
+ particularly when __libc_enable_secure is active. */
|
|
|
|
+#ifdef NAME_MAX
|
|
|
|
+# define SECURE_NAME_LIMIT NAME_MAX
|
|
|
|
+#else
|
|
|
|
+# define SECURE_NAME_LIMIT 255
|
|
|
|
+#endif
|
|
|
|
+#ifdef PATH_MAX
|
|
|
|
+# define SECURE_PATH_LIMIT PATH_MAX
|
|
|
|
+#else
|
|
|
|
+# define SECURE_PATH_LIMIT 1024
|
|
|
|
+#endif
|
2017-06-19 22:13:53 +02:00
|
|
|
+
|
2017-06-26 02:58:17 +02:00
|
|
|
+/* 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 (__glibc_unlikely (__libc_enable_secure))
|
|
|
|
+ {
|
|
|
|
+ /* Ignore pathnames with directories for AT_SECURE=1
|
|
|
|
+ programs, and also skip overlong names. */
|
|
|
|
+ size_t len = strlen (p);
|
|
|
|
+ if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL)
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return *p != '\0';
|
|
|
|
+}
|
|
|
|
|
|
|
|
/* List of auditing DSOs. */
|
2017-06-19 22:13:53 +02:00
|
|
|
static struct audit_list
|
2017-06-26 02:58:17 +02:00
|
|
|
@@ -718,6 +747,42 @@ static const char *preloadlist attribute_relro;
|
|
|
|
/* Nonzero if information about versions has to be printed. */
|
|
|
|
static int version_info attribute_relro;
|
2017-06-19 22:13:53 +02:00
|
|
|
|
2017-06-26 02:58:17 +02:00
|
|
|
+/* 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)
|
2017-06-19 22:13:53 +02:00
|
|
|
+{
|
2017-06-26 02:58:17 +02:00
|
|
|
+ unsigned int npreloads = 0;
|
|
|
|
+ const char *p = preloadlist;
|
|
|
|
+ char fname[SECURE_PATH_LIMIT];
|
2017-06-19 22:13:53 +02:00
|
|
|
+
|
2017-06-26 02:58:17 +02:00
|
|
|
+ while (*p != '\0')
|
2017-06-19 22:13:53 +02:00
|
|
|
+ {
|
2017-06-26 02:58:17 +02:00
|
|
|
+ /* Split preload list at space/colon. */
|
|
|
|
+ size_t len = strcspn (p, " :");
|
|
|
|
+ if (len > 0 && len < sizeof (fname))
|
2017-06-19 22:13:53 +02:00
|
|
|
+ {
|
2017-06-26 02:58:17 +02:00
|
|
|
+ memcpy (fname, p, len);
|
|
|
|
+ fname[len] = '\0';
|
2017-06-19 22:13:53 +02:00
|
|
|
+ }
|
2017-06-26 02:58:17 +02:00
|
|
|
+ else
|
|
|
|
+ fname[0] = '\0';
|
2017-06-19 22:13:53 +02:00
|
|
|
+
|
2017-06-26 02:58:17 +02:00
|
|
|
+ /* Skip over the substring and the following delimiter. */
|
|
|
|
+ p += len;
|
|
|
|
+ if (*p != '\0')
|
|
|
|
+ ++p;
|
|
|
|
+
|
|
|
|
+ if (dso_name_valid_for_suid (fname))
|
|
|
|
+ npreloads += do_preload (fname, main_map, "LD_PRELOAD");
|
2017-06-19 22:13:53 +02:00
|
|
|
+ }
|
2017-06-26 02:58:17 +02:00
|
|
|
+ return npreloads;
|
2017-06-19 22:13:53 +02:00
|
|
|
+}
|
|
|
|
+
|
2017-06-26 02:58:17 +02:00
|
|
|
static void
|
|
|
|
dl_main (const ElfW(Phdr) *phdr,
|
|
|
|
ElfW(Word) phnum,
|
|
|
|
@@ -1464,23 +1529,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
2017-06-19 22:13:53 +02:00
|
|
|
|
2017-06-26 02:58:17 +02:00
|
|
|
if (__glibc_unlikely (preloadlist != NULL))
|
2017-06-19 22:13:53 +02:00
|
|
|
{
|
2017-06-26 02:58:17 +02:00
|
|
|
- /* 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;
|
2017-06-19 22:13:53 +02:00
|
|
|
-
|
2017-06-26 02:58:17 +02:00
|
|
|
HP_TIMING_NOW (start);
|
|
|
|
-
|
|
|
|
- /* Prevent optimizing strsep. Speed is not important here. */
|
|
|
|
- while ((p = (strsep) (&list, " :")) != NULL)
|
|
|
|
- if (p[0] != '\0'
|
|
|
|
- && (__builtin_expect (! __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);
|
2017-06-19 22:13:53 +02:00
|
|
|
--
|
|
|
|
2.9.3
|
|
|
|
|