blob: 7b2073201efd058424421ad0f5ae4091b4b8f2f3 [file] [log] [blame]
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001From 951bdaad7a18cc0dc1036bba86b18b90874d39ff Mon Sep 17 00:00:00 2001
2From: Chet Ramey <chet.ramey@case.edu>
3Date: Mon, 1 Jul 2019 09:03:53 -0400
4Subject: [PATCH] commit bash-20190628 snapshot
5
6An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11.
7By default, if Bash is run with its effective UID not equal to its real UID,
8it will drop privileges by setting its effective UID to its real UID.
9However, it does so incorrectly. On Linux and other systems that support "saved UID" functionality,
10the saved UID is not dropped. An attacker with command execution in the shell can use "enable -f" for
11runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore
12regains privileges. However, binaries running with an effective UID of 0 are unaffected.
13
14Get the patch from [1] to fix the issue.
15
16Upstream-Status: Inappropriate [the upstream thinks it doesn't increase the credibility of CVEs in general]
17CVE: CVE-2019-18276
18
19[1] https://git.savannah.gnu.org/cgit/bash.git/commit/?h=devel&id=951bdaa
20
21Signed-off-by: De Huo <De.Huo@windriver.com>
22Signed-off-by: Kai Kang <kai.kang@windriver.com>
23Signed-off-by: Mingli Yu <mingli.yu@windriver.com>
24---
25 MANIFEST | 2 ++
26 bashline.c | 50 +-------------------------------------------------
27 builtins/help.def | 2 +-
28 config.h.in | 10 +++++++++-
29 configure.ac | 1 +
30 doc/bash.1 | 3 ++-
31 doc/bashref.texi | 3 ++-
32 lib/glob/glob.c | 5 ++++-
33 pathexp.c | 16 ++++++++++++++--
34 shell.c | 8 ++++++++
35 tests/glob.tests | 2 ++
36 tests/glob6.sub | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
37 tests/glob7.sub | 11 +++++++++++
38 14 files changed, 122 insertions(+), 56 deletions(-)
39 create mode 100644 tests/glob6.sub
40 create mode 100644 tests/glob7.sub
41
42diff --git a/MANIFEST b/MANIFEST
43index 03de221..f9ccad7 100644
44--- a/MANIFEST
45+++ b/MANIFEST
46@@ -1037,6 +1037,8 @@ tests/extglob3.tests f
47 tests/extglob3.right f
48 tests/extglob4.sub f
49 tests/extglob5.sub f
50+tests/glob6.sub f
51+tests/glob7.sub f
52 tests/func.tests f
53 tests/func.right f
54 tests/func1.sub f
55diff --git a/bashline.c b/bashline.c
56index 824ea9d..d86b47d 100644
57--- a/bashline.c
58+++ b/bashline.c
59@@ -3718,55 +3718,7 @@ static int
60 completion_glob_pattern (string)
61 char *string;
62 {
63- register int c;
64- char *send;
65- int open;
66-
67- DECLARE_MBSTATE;
68-
69- open = 0;
70- send = string + strlen (string);
71-
72- while (c = *string++)
73- {
74- switch (c)
75- {
76- case '?':
77- case '*':
78- return (1);
79-
80- case '[':
81- open++;
82- continue;
83-
84- case ']':
85- if (open)
86- return (1);
87- continue;
88-
89- case '+':
90- case '@':
91- case '!':
92- if (*string == '(') /*)*/
93- return (1);
94- continue;
95-
96- case '\\':
97- if (*string++ == 0)
98- return (0);
99- }
100-
101- /* Advance one fewer byte than an entire multibyte character to
102- account for the auto-increment in the loop above. */
103-#ifdef HANDLE_MULTIBYTE
104- string--;
105- ADVANCE_CHAR_P (string, send - string);
106- string++;
107-#else
108- ADVANCE_CHAR_P (string, send - string);
109-#endif
110- }
111- return (0);
112+ return (glob_pattern_p (string) == 1);
113 }
114
115 static char *globtext;
116diff --git a/builtins/help.def b/builtins/help.def
117index 006c4b5..92f9b38 100644
118--- a/builtins/help.def
119+++ b/builtins/help.def
120@@ -128,7 +128,7 @@ help_builtin (list)
121
122 /* We should consider making `help bash' do something. */
123
124- if (glob_pattern_p (list->word->word))
125+ if (glob_pattern_p (list->word->word) == 1)
126 {
127 printf ("%s", ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
128 print_word_list (list, ", ");
129diff --git a/config.h.in b/config.h.in
130index 8554aec..ad4b1e8 100644
131--- a/config.h.in
132+++ b/config.h.in
133@@ -1,6 +1,6 @@
134 /* config.h -- Configuration file for bash. */
135
136-/* Copyright (C) 1987-2009,2011-2012 Free Software Foundation, Inc.
137+/* Copyright (C) 1987-2009,2011-2012,2013-2019 Free Software Foundation, Inc.
138
139 This file is part of GNU Bash, the Bourne Again SHell.
140
141@@ -807,6 +807,14 @@
142 #undef HAVE_SETREGID
143 #undef HAVE_DECL_SETREGID
144
145+/* Define if you have the setregid function. */
146+#undef HAVE_SETRESGID
147+#undef HAVE_DECL_SETRESGID
148+
149+/* Define if you have the setresuid function. */
150+#undef HAVE_SETRESUID
151+#undef HAVE_DECL_SETRESUID
152+
153 /* Define if you have the setvbuf function. */
154 #undef HAVE_SETVBUF
155
156diff --git a/configure.ac b/configure.ac
157index 52b4cdb..549adef 100644
158--- a/configure.ac
159+++ b/configure.ac
160@@ -810,6 +810,7 @@ AC_CHECK_DECLS([confstr])
161 AC_CHECK_DECLS([printf])
162 AC_CHECK_DECLS([sbrk])
163 AC_CHECK_DECLS([setregid])
164+AC_CHECK_DECLS[(setresuid, setresgid])
165 AC_CHECK_DECLS([strcpy])
166 AC_CHECK_DECLS([strsignal])
167
168diff --git a/doc/bash.1 b/doc/bash.1
169index e6cd08d..9e58a0b 100644
170--- a/doc/bash.1
171+++ b/doc/bash.1
172@@ -4681,7 +4681,8 @@ above).
173 .PD
174 .SH "SIMPLE COMMAND EXPANSION"
175 When a simple command is executed, the shell performs the following
176-expansions, assignments, and redirections, from left to right.
177+expansions, assignments, and redirections, from left to right, in
178+the following order.
179 .IP 1.
180 The words that the parser has marked as variable assignments (those
181 preceding the command name) and redirections are saved for later
182diff --git a/doc/bashref.texi b/doc/bashref.texi
183index d33cd57..3065126 100644
184--- a/doc/bashref.texi
185+++ b/doc/bashref.texi
186@@ -2964,7 +2964,8 @@ is not specified. If the file does not exist, it is created.
187 @cindex command expansion
188
189 When a simple command is executed, the shell performs the following
190-expansions, assignments, and redirections, from left to right.
191+expansions, assignments, and redirections, from left to right, in
192+the following order.
193
194 @enumerate
195 @item
196diff --git a/lib/glob/glob.c b/lib/glob/glob.c
197index 398253b..2eaa33e 100644
198--- a/lib/glob/glob.c
199+++ b/lib/glob/glob.c
200@@ -607,6 +607,7 @@ glob_vector (pat, dir, flags)
201 register unsigned int i;
202 int mflags; /* Flags passed to strmatch (). */
203 int pflags; /* flags passed to sh_makepath () */
204+ int hasglob; /* return value from glob_pattern_p */
205 int nalloca;
206 struct globval *firstmalloc, *tmplink;
207 char *convfn;
208@@ -648,10 +649,12 @@ glob_vector (pat, dir, flags)
209 patlen = (pat && *pat) ? strlen (pat) : 0;
210
211 /* If the filename pattern (PAT) does not contain any globbing characters,
212+ or contains a pattern with only backslash escapes (hasglob == 2),
213 we can dispense with reading the directory, and just see if there is
214 a filename `DIR/PAT'. If there is, and we can access it, just make the
215 vector to return and bail immediately. */
216- if (skip == 0 && glob_pattern_p (pat) == 0)
217+ hasglob = 0;
218+ if (skip == 0 && (hasglob = glob_pattern_p (pat)) == 0 || hasglob == 2)
219 {
220 int dirlen;
221 struct stat finfo;
222diff --git a/pathexp.c b/pathexp.c
223index c1bf2d8..e6c5392 100644
224--- a/pathexp.c
225+++ b/pathexp.c
226@@ -58,7 +58,10 @@ int extended_glob = EXTGLOB_DEFAULT;
227 /* Control enabling special handling of `**' */
228 int glob_star = 0;
229
230-/* Return nonzero if STRING has any unquoted special globbing chars in it. */
231+/* Return nonzero if STRING has any unquoted special globbing chars in it.
232+ This is supposed to be called when pathname expansion is performed, so
233+ it implements the rules in Posix 2.13.3, specifically that an unquoted
234+ slash cannot appear in a bracket expression. */
235 int
236 unquoted_glob_pattern_p (string)
237 register char *string;
238@@ -85,10 +88,14 @@ unquoted_glob_pattern_p (string)
239 continue;
240
241 case ']':
242- if (open)
243+ if (open) /* XXX - if --open == 0? */
244 return (1);
245 continue;
246
247+ case '/':
248+ if (open)
249+ open = 0;
250+
251 case '+':
252 case '@':
253 case '!':
254@@ -106,6 +113,11 @@ unquoted_glob_pattern_p (string)
255 string++;
256 continue;
257 }
258+ else if (open && *string == '/')
259+ {
260+ string++; /* quoted slashes in bracket expressions are ok */
261+ continue;
262+ }
263 else if (*string == 0)
264 return (0);
265
266diff --git a/shell.c b/shell.c
267index a2b2a55..6adabc8 100644
268--- a/shell.c
269+++ b/shell.c
270@@ -1293,7 +1293,11 @@ disable_priv_mode ()
271 {
272 int e;
273
274+#if HAVE_DECL_SETRESUID
275+ if (setresuid (current_user.uid, current_user.uid, current_user.uid) < 0)
276+#else
277 if (setuid (current_user.uid) < 0)
278+#endif
279 {
280 e = errno;
281 sys_error (_("cannot set uid to %d: effective uid %d"), current_user.uid, current_user.euid);
282@@ -1302,7 +1306,11 @@ disable_priv_mode ()
283 exit (e);
284 #endif
285 }
286+#if HAVE_DECL_SETRESGID
287+ if (setresgid (current_user.gid, current_user.gid, current_user.gid) < 0)
288+#else
289 if (setgid (current_user.gid) < 0)
290+#endif
291 sys_error (_("cannot set gid to %d: effective gid %d"), current_user.gid, current_user.egid);
292
293 current_user.euid = current_user.uid;
294diff --git a/tests/glob.tests b/tests/glob.tests
295index 01913bb..fb012f7 100644
296--- a/tests/glob.tests
297+++ b/tests/glob.tests
298@@ -12,6 +12,8 @@ ${THIS_SH} ./glob1.sub
299 ${THIS_SH} ./glob2.sub
300 ${THIS_SH} ./glob3.sub
301 ${THIS_SH} ./glob4.sub
302+${THIS_SH} ./glob6.sub
303+${THIS_SH} ./glob7.sub
304
305 MYDIR=$PWD # save where we are
306
307diff --git a/tests/glob6.sub b/tests/glob6.sub
308new file mode 100644
309index 0000000..b099811
310--- /dev/null
311+++ b/tests/glob6.sub
312@@ -0,0 +1,54 @@
313+# tests of the backslash-in-glob-patterns discussion on the austin-group ML
314+
315+: ${TMPDIR:=/var/tmp}
316+
317+ORIG=$PWD
318+GLOBDIR=$TMPDIR/bash-glob-$$
319+mkdir $GLOBDIR && cd $GLOBDIR
320+
321+# does the pattern matcher allow backslashes as escape characters and remove
322+# them as part of matching?
323+touch abcdefg
324+pat='ab\cd*'
325+printf '<%s>\n' $pat
326+pat='\.'
327+printf '<%s>\n' $pat
328+rm abcdefg
329+
330+# how about when escaping pattern characters?
331+touch '*abc.c'
332+a='\**.c'
333+printf '%s\n' $a
334+rm -f '*abc.c'
335+
336+# how about when making the distinction between readable and searchable path
337+# components?
338+mkdir -m a=x searchable
339+mkdir -m a=r readable
340+
341+p='searchable/\.'
342+printf "%s\n" $p
343+
344+p='searchable/\./.'
345+printf "%s\n" $p
346+
347+p='readable/\.'
348+printf "%s\n" $p
349+
350+p='readable/\./.'
351+printf "%s\n" $p
352+
353+printf "%s\n" 'searchable/\.'
354+printf "%s\n" 'readable/\.'
355+
356+echo */.
357+
358+p='*/\.'
359+echo $p
360+
361+echo */'.'
362+
363+rmdir searchable readable
364+
365+cd $ORIG
366+rmdir $GLOBDIR
367diff --git a/tests/glob7.sub b/tests/glob7.sub
368new file mode 100644
369index 0000000..0212b8e
370--- /dev/null
371+++ b/tests/glob7.sub
372@@ -0,0 +1,11 @@
373+# according to Posix 2.13.3, a slash in a bracket expression renders that
374+# bracket expression invalid
375+shopt -s nullglob
376+
377+echo 1: [qwe/qwe]
378+echo 2: [qwe/
379+echo 3: [qwe/]
380+
381+echo 4: [qwe\/qwe]
382+echo 5: [qwe\/
383+echo 6: [qwe\/]
384--
3851.9.1
386