Fix use-after-free in glob when expanding ~user (bug 25414)

The value of `end_name' points into the value of `dirname', thus don't
deallocate the latter before the last use of the former.

(cherry picked from commit ddc650e9b3)
This commit is contained in:
Andreas Schwab 2020-02-19 17:21:46 +01:00 committed by Tulio Magno Quites Machado Filho
parent 0478174d1e
commit 21344a3d62
2 changed files with 17 additions and 12 deletions

4
NEWS
View File

@ -73,6 +73,7 @@ The following bugs are resolved with this release:
[25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs [25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs
[25225] ld.so fails to link on x86 if GCC defaults to -fcf-protection [25225] ld.so fails to link on x86 if GCC defaults to -fcf-protection
[25232] No const correctness for strchr et al. for Clang++ [25232] No const correctness for strchr et al. for Clang++
[25414] 'glob' use-after-free bug (CVE-2020-1752)
[25423] Array overflow in backtrace on powerpc [25423] Array overflow in backtrace on powerpc
Security related changes: Security related changes:
@ -109,6 +110,9 @@ Security related changes:
addresses for loaded libraries and thus bypass ASLR for a setuid addresses for loaded libraries and thus bypass ASLR for a setuid
program. Reported by Marcin Kościelnicki. program. Reported by Marcin Kościelnicki.
CVE-2020-1752: A use-after-free vulnerability in the glob function when
expanding ~user has been fixed.
Version 2.28 Version 2.28

View File

@ -827,31 +827,32 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
{ {
size_t home_len = strlen (p->pw_dir); size_t home_len = strlen (p->pw_dir);
size_t rest_len = end_name == NULL ? 0 : strlen (end_name); size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
char *d; char *d, *newp;
bool use_alloca = glob_use_alloca (alloca_used,
home_len + rest_len + 1);
if (__glibc_unlikely (malloc_dirname)) if (use_alloca)
free (dirname); newp = alloca_account (home_len + rest_len + 1, alloca_used);
malloc_dirname = 0;
if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
dirname = alloca_account (home_len + rest_len + 1,
alloca_used);
else else
{ {
dirname = malloc (home_len + rest_len + 1); newp = malloc (home_len + rest_len + 1);
if (dirname == NULL) if (newp == NULL)
{ {
scratch_buffer_free (&pwtmpbuf); scratch_buffer_free (&pwtmpbuf);
retval = GLOB_NOSPACE; retval = GLOB_NOSPACE;
goto out; goto out;
} }
malloc_dirname = 1;
} }
d = mempcpy (dirname, p->pw_dir, home_len); d = mempcpy (newp, p->pw_dir, home_len);
if (end_name != NULL) if (end_name != NULL)
d = mempcpy (d, end_name, rest_len); d = mempcpy (d, end_name, rest_len);
*d = '\0'; *d = '\0';
if (__glibc_unlikely (malloc_dirname))
free (dirname);
dirname = newp;
malloc_dirname = !use_alloca;
dirlen = home_len + rest_len; dirlen = home_len + rest_len;
dirname_modified = 1; dirname_modified = 1;
} }