···1+From ba67ba3275d47e0080f0e5f09d9f5102c000c97e Mon Sep 17 00:00:00 2001
2+Message-Id: <ba67ba3275d47e0080f0e5f09d9f5102c000c97e.1495998948.git.fweimer@redhat.com>
3+In-Reply-To: <cover.1495998948.git.fweimer@redhat.com>
4+References: <cover.1495998948.git.fweimer@redhat.com>
5+From: Florian Weimer <fweimer@redhat.com>
6+Date: Sun, 28 May 2017 20:44:52 +0200
7+Subject: [PATCH 3/3] rtld: Reject overly long LD_AUDIT path elements
8+To: libc-alpha@sourceware.org
9+10+Also only process the last LD_AUDIT entry.
11+---
12+ elf/rtld.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------
13+ 1 file changed, 95 insertions(+), 15 deletions(-)
14+15+diff --git a/elf/rtld.c b/elf/rtld.c
16+index 30f0cae..89d8573 100644
17+--- a/elf/rtld.c
18++++ b/elf/rtld.c
19+@@ -116,13 +116,95 @@ dso_name_valid_for_suid (const char *p)
20+ return *p != '\0';
21+ }
22+23+-/* List of auditing DSOs. */
24++/* LD_AUDIT variable contents. Must be processed before the
25++ audit_list below. */
26++const char *audit_list_string;
27++
28++/* Cyclic list of auditing DSOs. audit_list->next is the first
29++ element. */
30+ static struct audit_list
31+ {
32+ const char *name;
33+ struct audit_list *next;
34+ } *audit_list;
35+36++/* Iterator for audit_list_string followed by audit_list. */
37++struct audit_list_iter
38++{
39++ /* Tail of audit_list_string still needing processing, or NULL. */
40++ const char *audit_list_tail;
41++
42++ /* The list element returned in the previous iteration. NULL before
43++ the first element. */
44++ struct audit_list *previous;
45++
46++ /* Scratch buffer for returning a name which is part of
47++ audit_list_string. */
48++#ifdef PATH_MAX
49++ char fname[PATH_MAX];
50++#else
51++ char fname[4096];
52++#endif
53++};
54++
55++/* Initialize an audit list iterator. */
56++static void
57++audit_list_iter_init (struct audit_list_iter *iter)
58++{
59++ iter->audit_list_tail = audit_list_string;
60++ iter->previous = NULL;
61++}
62++
63++/* Iterate through both audit_list_string and audit_list. */
64++static const char *
65++audit_list_iter_next (struct audit_list_iter *iter)
66++{
67++ if (iter->audit_list_tail != NULL)
68++ {
69++ /* First iterate over audit_list_string. */
70++ while (*iter->audit_list_tail != '\0')
71++ {
72++ /* Split audit list at colon. */
73++ size_t len = strcspn (iter->audit_list_tail, ":");
74++ if (len > 0 && len < sizeof(iter->fname))
75++ {
76++ memcpy (iter->fname, iter->audit_list_tail, len);
77++ iter->fname[len] = '\0';
78++ }
79++ else
80++ /* Do not return this name to the caller. */
81++ iter->fname[0] = '\0';
82++
83++ /* Skip over the substring and the following delimiter. */
84++ iter->audit_list_tail += len;
85++ if (*iter->audit_list_tail == ':')
86++ ++iter->audit_list_tail;
87++
88++ /* If the name is valid, return it. */
89++ if (dso_name_valid_for_suid (iter->fname))
90++ return iter->fname;
91++ /* Otherwise, wrap around and try the next name. */
92++ }
93++ /* Fall through to the procesing of audit_list. */
94++ }
95++
96++ if (iter->previous == NULL)
97++ {
98++ if (audit_list == NULL)
99++ /* No pre-parsed audit list. */
100++ return NULL;
101++ /* Start of audit list. The first list element is at
102++ audit_list->next (cyclic list). */
103++ iter->previous = audit_list->next;
104++ return iter->previous->name;
105++ }
106++ if (iter->previous == audit_list)
107++ /* Cyclic list wrap-around. */
108++ return NULL;
109++ iter->previous = iter->previous->next;
110++ return iter->previous->name;
111++}
112++
113+ #ifndef HAVE_INLINED_SYSCALLS
114+ /* Set nonzero during loading and initialization of executable and
115+ libraries, cleared before the executable's entry point runs. This
116+@@ -1290,11 +1368,13 @@ of this helper program; chances are you did not intend to run this program.\n\
117+ GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
118+119+ /* If we have auditing DSOs to load, do it now. */
120+- if (__glibc_unlikely (audit_list != NULL))
121++ bool need_security_init = true;
122++ if (__glibc_unlikely (audit_list != NULL)
123++ || __glibc_unlikely (audit_list_string != NULL))
124+ {
125+- /* Iterate over all entries in the list. The order is important. */
126+ struct audit_ifaces *last_audit = NULL;
127+- struct audit_list *al = audit_list->next;
128++ struct audit_list_iter al_iter;
129++ audit_list_iter_init (&al_iter);
130+131+ /* Since we start using the auditing DSOs right away we need to
132+ initialize the data structures now. */
133+@@ -1305,9 +1385,14 @@ of this helper program; chances are you did not intend to run this program.\n\
134+ use different values (especially the pointer guard) and will
135+ fail later on. */
136+ security_init ();
137++ need_security_init = false;
138+139+- do
140++ while (true)
141+ {
142++ const char *name = audit_list_iter_next (&al_iter);
143++ if (name == NULL)
144++ break;
145++
146+ int tls_idx = GL(dl_tls_max_dtv_idx);
147+148+ /* Now it is time to determine the layout of the static TLS
149+@@ -1316,7 +1401,7 @@ of this helper program; chances are you did not intend to run this program.\n\
150+ no DF_STATIC_TLS bit is set. The reason is that we know
151+ glibc will use the static model. */
152+ struct dlmopen_args dlmargs;
153+- dlmargs.fname = al->name;
154++ dlmargs.fname = name;
155+ dlmargs.map = NULL;
156+157+ const char *objname;
158+@@ -1329,7 +1414,7 @@ of this helper program; chances are you did not intend to run this program.\n\
159+ not_loaded:
160+ _dl_error_printf ("\
161+ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
162+- al->name, err_str);
163++ name, err_str);
164+ if (malloced)
165+ free ((char *) err_str);
166+ }
167+@@ -1433,10 +1518,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
168+ goto not_loaded;
169+ }
170+ }
171+-
172+- al = al->next;
173+ }
174+- while (al != audit_list->next);
175+176+ /* If we have any auditing modules, announce that we already
177+ have two objects loaded. */
178+@@ -1700,7 +1782,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
179+ if (tcbp == NULL)
180+ tcbp = init_tls ();
181+182+- if (__glibc_likely (audit_list == NULL))
183++ if (__glibc_likely (need_security_init))
184+ /* Initialize security features. But only if we have not done it
185+ earlier. */
186+ security_init ();
187+@@ -2331,9 +2413,7 @@ process_dl_audit (char *str)
188+ char *p;
189+190+ while ((p = (strsep) (&str, ":")) != NULL)
191+- if (p[0] != '\0'
192+- && (__builtin_expect (! __libc_enable_secure, 1)
193+- || strchr (p, '/') == NULL))
194++ if (dso_name_valid_for_suid (p))
195+ {
196+ /* This is using the local malloc, not the system malloc. The
197+ memory can never be freed. */
198+@@ -2397,7 +2477,7 @@ process_envvars (enum mode *modep)
199+ break;
200+ }
201+ if (memcmp (envline, "AUDIT", 5) == 0)
202+- process_dl_audit (&envline[6]);
203++ audit_list_string = &envline[6];
204+ break;
205+206+ case 7:
207+--
208+2.9.4
209+
···1+From 65ff0b7a085b85271ec8fde99f542281b495e3bc Mon Sep 17 00:00:00 2001
2+Message-Id: <65ff0b7a085b85271ec8fde99f542281b495e3bc.1495998948.git.fweimer@redhat.com>
3+In-Reply-To: <cover.1495998948.git.fweimer@redhat.com>
4+References: <cover.1495998948.git.fweimer@redhat.com>
5+From: Florian Weimer <fweimer@redhat.com>
6+Date: Sun, 28 May 2017 20:57:40 +0200
7+Subject: [PATCH 2/3] rtld: Reject overly long LD_PRELOAD path elements
8+To: libc-alpha@sourceware.org
9+10+---
11+ elf/rtld.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++---------------
12+ 1 file changed, 53 insertions(+), 16 deletions(-)
13+14+diff --git a/elf/rtld.c b/elf/rtld.c
15+index 824b6cf..30f0cae 100644
16+--- a/elf/rtld.c
17++++ b/elf/rtld.c
18+@@ -99,6 +99,22 @@ uintptr_t __pointer_chk_guard_local
19+ strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
20+ #endif
21+22++/* Check that AT_SECURE=0, or that the passed name does not contain
23++ directories and is not overly long. Reject empty names
24++ unconditionally. */
25++static bool
26++dso_name_valid_for_suid (const char *p)
27++{
28++ if (__glibc_unlikely (__libc_enable_secure))
29++ {
30++ /* Ignore pathnames with directories for AT_SECURE=1
31++ programs, and also skip overlong names. */
32++ size_t len = strlen (p);
33++ if (len >= NAME_MAX || memchr (p, '/', len) != NULL)
34++ return false;
35++ }
36++ return *p != '\0';
37++}
38+39+ /* List of auditing DSOs. */
40+ static struct audit_list
41+@@ -716,6 +732,46 @@ static const char *preloadlist attribute_relro;
42+ /* Nonzero if information about versions has to be printed. */
43+ static int version_info attribute_relro;
44+45++/* The LD_PRELOAD environment variable gives list of libraries
46++ separated by white space or colons that are loaded before the
47++ executable's dependencies and prepended to the global scope list.
48++ (If the binary is running setuid all elements containing a '/' are
49++ ignored since it is insecure.) Return the number of preloads
50++ performed. */
51++unsigned int
52++handle_ld_preload (const char *preloadlist, struct link_map *main_map)
53++{
54++ unsigned int npreloads = 0;
55++ const char *p = preloadlist;
56++#ifdef PATH_MAX
57++ char fname[PATH_MAX];
58++#else
59++ char fname[4096];
60++#endif
61++
62++ while (*p != '\0')
63++ {
64++ /* Split preload list at space/colon. */
65++ size_t len = strcspn (p, " :");
66++ if (len > 0 && len < sizeof(fname))
67++ {
68++ memcpy (fname, p, len);
69++ fname[len] = '\0';
70++ }
71++ else
72++ fname[0] = '\0';
73++
74++ /* Skip over the substring and the following delimiter. */
75++ p += len;
76++ if (*p == ' ' || *p == ':')
77++ ++p;
78++
79++ if (dso_name_valid_for_suid (fname))
80++ npreloads += do_preload (fname, main_map, "LD_PRELOAD");
81++ }
82++ return npreloads;
83++}
84++
85+ static void
86+ dl_main (const ElfW(Phdr) *phdr,
87+ ElfW(Word) phnum,
88+@@ -1462,23 +1514,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
89+90+ if (__glibc_unlikely (preloadlist != NULL))
91+ {
92+- /* The LD_PRELOAD environment variable gives list of libraries
93+- separated by white space or colons that are loaded before the
94+- executable's dependencies and prepended to the global scope
95+- list. If the binary is running setuid all elements
96+- containing a '/' are ignored since it is insecure. */
97+- char *list = strdupa (preloadlist);
98+- char *p;
99+-
100+ HP_TIMING_NOW (start);
101+-
102+- /* Prevent optimizing strsep. Speed is not important here. */
103+- while ((p = (strsep) (&list, " :")) != NULL)
104+- if (p[0] != '\0'
105+- && (__builtin_expect (! __libc_enable_secure, 1)
106+- || strchr (p, '/') == NULL))
107+- npreloads += do_preload (p, main_map, "LD_PRELOAD");
108+-
109++ npreloads += handle_ld_preload (preloadlist, main_map);
110+ HP_TIMING_NOW (stop);
111+ HP_TIMING_DIFF (diff, start, stop);
112+ HP_TIMING_ACCUM_NT (load_time, diff);
113+--
114+2.9.4
115+
+5
pkgs/development/libraries/glibc/common.nix
···59 "/bin:/usr/bin", which is inappropriate on NixOS machines. This
60 patch extends the search path by "/run/current-system/sw/bin". */
61 ./fix_path_attribute_in_getconf.patch
0000062 ]
63 ++ lib.optional stdenv.isi686 ./fix-i686-memchr.patch;
64
···59 "/bin:/usr/bin", which is inappropriate on NixOS machines. This
60 patch extends the search path by "/run/current-system/sw/bin". */
61 ./fix_path_attribute_in_getconf.patch
62+63+ /* Stack Clash */
64+ ./CVE-2017-1000366-rtld-LD_LIBRARY_PATH.patch
65+ ./CVE-2017-1000366-rtld-LD_PRELOAD.patch
66+ ./CVE-2017-1000366-rtld-LD_AUDIT.patch
67 ]
68 ++ lib.optional stdenv.isi686 ./fix-i686-memchr.patch;
69