From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/11951 Path: news.gmane.org!.POSTED!not-for-mail From: Markus Wichmann Newsgroups: gmane.linux.lib.musl.general Subject: Re: preventable SIGSEGV when bad AT_SYSINFO_EHDR Date: Tue, 19 Sep 2017 19:21:29 +0200 Message-ID: <20170919172129.k5pjpuwtm5dhhf57@voyager> References: <439c3bd7-9eed-dd18-a025-bd6257373f11@bitwagon.com> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: blaine.gmane.org 1505841704 27295 195.159.176.226 (19 Sep 2017 17:21:44 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 19 Sep 2017 17:21:44 +0000 (UTC) User-Agent: NeoMutt/20170113 (1.7.2) To: musl@lists.openwall.com Original-X-From: musl-return-11964-gllmg-musl=m.gmane.org@lists.openwall.com Tue Sep 19 19:21:40 2017 Return-path: Envelope-to: gllmg-musl@m.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by blaine.gmane.org with smtp (Exim 4.84_2) (envelope-from ) id 1duMDM-0006rj-C1 for gllmg-musl@m.gmane.org; Tue, 19 Sep 2017 19:21:40 +0200 Original-Received: (qmail 17924 invoked by uid 550); 19 Sep 2017 17:21:45 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Original-Received: (qmail 17900 invoked from network); 19 Sep 2017 17:21:45 -0000 Content-Disposition: inline In-Reply-To: <439c3bd7-9eed-dd18-a025-bd6257373f11@bitwagon.com> X-Provags-ID: V03:K0:Kr5QnE73ExXO5QkN93FSuBS01CmMVgmchHFFXXN/xEShZmD3q4B ege5u7MqmzdzGwmvG7JxEQ8mAmOdjsY41/0phspkROP/k5A6yaXhP1drvaY60FUs/NLO1wp RCFWee4MhbyzIDcv0JZ3u3f9sXOa1lc2sOqe2XkoeJnaIELzjOPG9xXF6ImpaJK/3N/gpRw 1vygBo1LJG+4FckpWqR6Q== X-UI-Out-Filterresults: notjunk:1;V01:K0:Kzv8vHL00CE=:9QBxRb2RcmNJOof2nKTadK ARlC5I2z0RopmcNVszBhOhrnSjv1zSuBLAQ7/MExU0jsYfOiUM/md5QgahT6TRnrzS9ntiYBT uxXtwHjwhqCdJ2Ol/TSAh+u1kJogPovJ2/w2NhqulSx5QyJtH+nsPrwvzT5lDZ5pb4oMy8FKF wNiyYMrCkseNkDhlb51pKXbnxT/AMg4WqTelFyKTDxRfc8byoRlGpiZ1Y8f4tHHqzJUYyjxd4 9TsGQXnWzFv9lbzEA8bUV4gaG7x+XTw2UguGdI0WlWFkU+fhgp7yfwLzGdFfBHyKmTtyyn6bh 4YtIwyu62q79bovTSP6kRdVmjo1b9qNN9BzuEbSa4UFhTgEAo7AffbcLKuhWPe8vqcTdUI/SK /x7PpqAGz+E35Lh3JdbMviTV/xzcw7AkJtpnXq302AhOO72prydLhEZtA2duBqxvi6JPQHUpg 0XJN7WmSmjSFedvE9koi3M/wInFeuTgfAdyfaf/A1VFmeV200aliDF7eMyyJEZM7mYrq58V7j UmwaaUUoNaj4b/Fc13K+KeV0aUilcXOaIUd5tVqT3/qBjQ2HDKgVb7DKcmujJ2SAcMoOHjUob g/MHebCy0Sc2WaDr54yuvuDCVj4Mknyfz1Tgup5Y/dXZzC7JkPTVhU+Y0E9lQb5mDfwtM1UDn Q0P3iqh2XE2sUGp/lEsuCyl/H2YJPJbytAtvg0MbwR9VA1hk7/+fPnoxJ7pfr7ngH/o+bgKov j2GQAhMiKsEjfysIQbbc+JkJuvfSZRt2zJWwevCmmY9yVqexTwO3OsDaAjk/WXrae29atKTy Xref: news.gmane.org gmane.linux.lib.musl.general:11951 Archived-At: On Tue, Sep 19, 2017 at 09:46:19AM -0700, John Reiser wrote: > __dls3() and friends in musl/ldso/dynlink.c should check Elf headers more carefully. > I saw a SIGSEGV in decode_dyn() because vdso_base = ElfXX_auxv[{AT_SYSINFO_EHDR}].a_ptr > pointed to a region that was all zero, and thus vdso.dynv == 0. The operating system > kernel is the only one who can perform a fork() or clone(), but other software can > perform execve(). In my case that other software had a bug. However, the blame > for the SIGSEGV rests on __dls3() because it did not validate input data. [This is > the stuff of exploits.] Calling a_crash() is OK; but a preventable SIGSEGV must be > avoided, both directly and because it indicates a lack of secure implementation. > How esoteric. As far as I know, the aux headers come from the kernel and are implicitly trusted because of that. If you have some userspace program trying to do execve() without a kernel call, then that program needs to correctly implement the aux headers. Mistrusting aux headers is as sensible as mistrusting the kernel. For example, we fetch our user credentials out of the aux headers in __init_libc(). But if your program emulates execve(), then how does security come into play here? Security is only important if security domains are switched, which a userspace program can't do (discounting kernel bugs, of course). And so you're left with a program that might be able to exploit musl into running arbitrary code in its own security domain. Newsflash: You can already run arbitrary code in your own security domain. It's called program execution. And if a buggy program was running with elevated privileges and somehow could be tricked into running its execve() emulation with attacker controlled data, then the problem has already happened a long time ago, and you're merely asking us to fix the symptoms. In short, the quickest fix is to not emulate execve() but call the kernel instead, hoping it won't screw up the ABI (if it does, abandon ship, since all hope is lost). Another fix would be to just link your programs statically. That way, all the __dls*() functions don't run at all. > It is [mostly] reasonable that __dls3() should trust that a non-zero vdso_base points to > a region that is readable, is as big and as aligned as an ElfXX_Ehdr, and is const > (no other thread is writing it, neither is any other process via a shared memory mapping); > but after that ldso should check. > No, if the value is set then it is correct by definition! Just as much as AT_UID or AT_SECURE. > In particular, these should be checked: > 0 == memcmp(ELFMAG, &.e_ident[EI_MAG0], SELFMAG) > .e_machine matches the executing ldso > .e_ident[{EI_CLASS, EI_DATA}] match the executing ldso > .e_phnum != 0 > .e_phentsize >= sizeof(ElfXX_Phdr); and larger *IS ALLOWED*: derived classes, etc. How do classes come into play in a file format? To my knowledge, program headers have an explicitly defined layout, and a mismatching phentsize is indicative of the program header in the file not being what you thought it was. > .e_phnum * .e_phentsize is not too large [loops that increment a pointer by .e_phentsize] > .e_phoff >= sizeof(ElfXX_Ehdr); overlap of Ehdr and Phdr is a logical error > (.e_phoff + .e_phnum * .e_phentsize) < .st_size; no access beyond EOF > And where does that EOF check come from? We only know the start of the kernel vDSO, but not its length. We can't stat() it, as it doesn't really exist, it is merely injected into every process. Ciao, Markus