diff options
Diffstat (limited to 'meta/recipes-core/glibc/glibc/0003-ld.so-Reject-overly-long-LD_AUDIT-path-elements.patch')
-rw-r--r-- | meta/recipes-core/glibc/glibc/0003-ld.so-Reject-overly-long-LD_AUDIT-path-elements.patch | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/meta/recipes-core/glibc/glibc/0003-ld.so-Reject-overly-long-LD_AUDIT-path-elements.patch b/meta/recipes-core/glibc/glibc/0003-ld.so-Reject-overly-long-LD_AUDIT-path-elements.patch new file mode 100644 index 0000000000..b52b8a1fa7 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0003-ld.so-Reject-overly-long-LD_AUDIT-path-elements.patch | |||
@@ -0,0 +1,231 @@ | |||
1 | From c0b25407def32718147530da72959a034cd1318d Mon Sep 17 00:00:00 2001 | ||
2 | From: Florian Weimer <fweimer@redhat.com> | ||
3 | Date: Mon, 19 Jun 2017 22:32:12 +0200 | ||
4 | Subject: [PATCH] ld.so: Reject overly long LD_AUDIT path elements | ||
5 | |||
6 | Also only process the last LD_AUDIT entry. | ||
7 | |||
8 | (cherry picked from commit 81b82fb966ffbd94353f793ad17116c6088dedd9) | ||
9 | |||
10 | Upstream-Status: Backport | ||
11 | https://sourceware.org/git/?p=glibc.git;a=commit;h=2febff860b31df3666bef5ade0d0744c93f76a74 | ||
12 | https://anonscm.debian.org/cgit/pkg-glibc/glibc.git/commit/?h=stretch&id=2755c57269f24e9d59c22c49788f92515346c1bb | ||
13 | |||
14 | CVE: CVE-2017-1000366 | ||
15 | |||
16 | Signed-off-by: George McCollister <george.mccollister@gmail.com> | ||
17 | --- | ||
18 | ChangeLog | 11 +++++++ | ||
19 | elf/rtld.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- | ||
20 | 2 files changed, 106 insertions(+), 15 deletions(-) | ||
21 | |||
22 | diff --git a/ChangeLog b/ChangeLog | ||
23 | index ea5ecd4a1e..638cb632b1 100644 | ||
24 | --- a/ChangeLog | ||
25 | +++ b/ChangeLog | ||
26 | @@ -1,3 +1,14 @@ | ||
27 | +2017-06-19 Florian Weimer <fweimer@redhat.com> | ||
28 | + | ||
29 | + * elf/rtld.c (audit_list_string): New variable. | ||
30 | + (audit_list): Update comment. | ||
31 | + (struct audit_list_iter): Define. | ||
32 | + (audit_list_iter_init, audit_list_iter_next): New function. | ||
33 | + (dl_main): Use struct audit_list_iter to process audit modules. | ||
34 | + (process_dl_audit): Call dso_name_valid_for_suid. | ||
35 | + (process_envvars): Set audit_list_string instead of calling | ||
36 | + process_dl_audit. | ||
37 | + | ||
38 | 2017-06-19 Florian Weimer <fweimer@redhat.com> | ||
39 | |||
40 | * elf/rtld.c (SECURE_NAME_LIMIT, SECURE_PATH_LIMIT): Define. | ||
41 | diff --git a/elf/rtld.c b/elf/rtld.c | ||
42 | index 1d8eab9fe2..302bb63620 100644 | ||
43 | --- a/elf/rtld.c | ||
44 | +++ b/elf/rtld.c | ||
45 | @@ -129,13 +129,91 @@ dso_name_valid_for_suid (const char *p) | ||
46 | return *p != '\0'; | ||
47 | } | ||
48 | |||
49 | -/* List of auditing DSOs. */ | ||
50 | +/* LD_AUDIT variable contents. Must be processed before the | ||
51 | + audit_list below. */ | ||
52 | +const char *audit_list_string; | ||
53 | + | ||
54 | +/* Cyclic list of auditing DSOs. audit_list->next is the first | ||
55 | + element. */ | ||
56 | static struct audit_list | ||
57 | { | ||
58 | const char *name; | ||
59 | struct audit_list *next; | ||
60 | } *audit_list; | ||
61 | |||
62 | +/* Iterator for audit_list_string followed by audit_list. */ | ||
63 | +struct audit_list_iter | ||
64 | +{ | ||
65 | + /* Tail of audit_list_string still needing processing, or NULL. */ | ||
66 | + const char *audit_list_tail; | ||
67 | + | ||
68 | + /* The list element returned in the previous iteration. NULL before | ||
69 | + the first element. */ | ||
70 | + struct audit_list *previous; | ||
71 | + | ||
72 | + /* Scratch buffer for returning a name which is part of | ||
73 | + audit_list_string. */ | ||
74 | + char fname[SECURE_NAME_LIMIT]; | ||
75 | +}; | ||
76 | + | ||
77 | +/* Initialize an audit list iterator. */ | ||
78 | +static void | ||
79 | +audit_list_iter_init (struct audit_list_iter *iter) | ||
80 | +{ | ||
81 | + iter->audit_list_tail = audit_list_string; | ||
82 | + iter->previous = NULL; | ||
83 | +} | ||
84 | + | ||
85 | +/* Iterate through both audit_list_string and audit_list. */ | ||
86 | +static const char * | ||
87 | +audit_list_iter_next (struct audit_list_iter *iter) | ||
88 | +{ | ||
89 | + if (iter->audit_list_tail != NULL) | ||
90 | + { | ||
91 | + /* First iterate over audit_list_string. */ | ||
92 | + while (*iter->audit_list_tail != '\0') | ||
93 | + { | ||
94 | + /* Split audit list at colon. */ | ||
95 | + size_t len = strcspn (iter->audit_list_tail, ":"); | ||
96 | + if (len > 0 && len < sizeof (iter->fname)) | ||
97 | + { | ||
98 | + memcpy (iter->fname, iter->audit_list_tail, len); | ||
99 | + iter->fname[len] = '\0'; | ||
100 | + } | ||
101 | + else | ||
102 | + /* Do not return this name to the caller. */ | ||
103 | + iter->fname[0] = '\0'; | ||
104 | + | ||
105 | + /* Skip over the substring and the following delimiter. */ | ||
106 | + iter->audit_list_tail += len; | ||
107 | + if (*iter->audit_list_tail == ':') | ||
108 | + ++iter->audit_list_tail; | ||
109 | + | ||
110 | + /* If the name is valid, return it. */ | ||
111 | + if (dso_name_valid_for_suid (iter->fname)) | ||
112 | + return iter->fname; | ||
113 | + /* Otherwise, wrap around and try the next name. */ | ||
114 | + } | ||
115 | + /* Fall through to the procesing of audit_list. */ | ||
116 | + } | ||
117 | + | ||
118 | + if (iter->previous == NULL) | ||
119 | + { | ||
120 | + if (audit_list == NULL) | ||
121 | + /* No pre-parsed audit list. */ | ||
122 | + return NULL; | ||
123 | + /* Start of audit list. The first list element is at | ||
124 | + audit_list->next (cyclic list). */ | ||
125 | + iter->previous = audit_list->next; | ||
126 | + return iter->previous->name; | ||
127 | + } | ||
128 | + if (iter->previous == audit_list) | ||
129 | + /* Cyclic list wrap-around. */ | ||
130 | + return NULL; | ||
131 | + iter->previous = iter->previous->next; | ||
132 | + return iter->previous->name; | ||
133 | +} | ||
134 | + | ||
135 | #ifndef HAVE_INLINED_SYSCALLS | ||
136 | /* Set nonzero during loading and initialization of executable and | ||
137 | libraries, cleared before the executable's entry point runs. This | ||
138 | @@ -1322,11 +1400,13 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
139 | GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); | ||
140 | |||
141 | /* If we have auditing DSOs to load, do it now. */ | ||
142 | - if (__glibc_unlikely (audit_list != NULL)) | ||
143 | + bool need_security_init = true; | ||
144 | + if (__glibc_unlikely (audit_list != NULL) | ||
145 | + || __glibc_unlikely (audit_list_string != NULL)) | ||
146 | { | ||
147 | - /* Iterate over all entries in the list. The order is important. */ | ||
148 | struct audit_ifaces *last_audit = NULL; | ||
149 | - struct audit_list *al = audit_list->next; | ||
150 | + struct audit_list_iter al_iter; | ||
151 | + audit_list_iter_init (&al_iter); | ||
152 | |||
153 | /* Since we start using the auditing DSOs right away we need to | ||
154 | initialize the data structures now. */ | ||
155 | @@ -1337,9 +1417,14 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
156 | use different values (especially the pointer guard) and will | ||
157 | fail later on. */ | ||
158 | security_init (); | ||
159 | + need_security_init = false; | ||
160 | |||
161 | - do | ||
162 | + while (true) | ||
163 | { | ||
164 | + const char *name = audit_list_iter_next (&al_iter); | ||
165 | + if (name == NULL) | ||
166 | + break; | ||
167 | + | ||
168 | int tls_idx = GL(dl_tls_max_dtv_idx); | ||
169 | |||
170 | /* Now it is time to determine the layout of the static TLS | ||
171 | @@ -1348,7 +1433,7 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
172 | no DF_STATIC_TLS bit is set. The reason is that we know | ||
173 | glibc will use the static model. */ | ||
174 | struct dlmopen_args dlmargs; | ||
175 | - dlmargs.fname = al->name; | ||
176 | + dlmargs.fname = name; | ||
177 | dlmargs.map = NULL; | ||
178 | |||
179 | const char *objname; | ||
180 | @@ -1361,7 +1446,7 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
181 | not_loaded: | ||
182 | _dl_error_printf ("\ | ||
183 | ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", | ||
184 | - al->name, err_str); | ||
185 | + name, err_str); | ||
186 | if (malloced) | ||
187 | free ((char *) err_str); | ||
188 | } | ||
189 | @@ -1465,10 +1550,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", | ||
190 | goto not_loaded; | ||
191 | } | ||
192 | } | ||
193 | - | ||
194 | - al = al->next; | ||
195 | } | ||
196 | - while (al != audit_list->next); | ||
197 | |||
198 | /* If we have any auditing modules, announce that we already | ||
199 | have two objects loaded. */ | ||
200 | @@ -1732,7 +1814,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", | ||
201 | if (tcbp == NULL) | ||
202 | tcbp = init_tls (); | ||
203 | |||
204 | - if (__glibc_likely (audit_list == NULL)) | ||
205 | + if (__glibc_likely (need_security_init)) | ||
206 | /* Initialize security features. But only if we have not done it | ||
207 | earlier. */ | ||
208 | security_init (); | ||
209 | @@ -2363,9 +2445,7 @@ process_dl_audit (char *str) | ||
210 | char *p; | ||
211 | |||
212 | while ((p = (strsep) (&str, ":")) != NULL) | ||
213 | - if (p[0] != '\0' | ||
214 | - && (__builtin_expect (! __libc_enable_secure, 1) | ||
215 | - || strchr (p, '/') == NULL)) | ||
216 | + if (dso_name_valid_for_suid (p)) | ||
217 | { | ||
218 | /* This is using the local malloc, not the system malloc. The | ||
219 | memory can never be freed. */ | ||
220 | @@ -2429,7 +2509,7 @@ process_envvars (enum mode *modep) | ||
221 | break; | ||
222 | } | ||
223 | if (memcmp (envline, "AUDIT", 5) == 0) | ||
224 | - process_dl_audit (&envline[6]); | ||
225 | + audit_list_string = &envline[6]; | ||
226 | break; | ||
227 | |||
228 | case 7: | ||
229 | -- | ||
230 | 2.15.0 | ||
231 | |||