From mboxrd@z Thu Jan 1 00:00:00 1970 Reply-To: kernel-hardening@lists.openwall.com Sender: Ingo Molnar Date: Tue, 10 Jan 2017 11:27:33 +0100 From: Ingo Molnar Message-ID: <20170110102733.GA5638@gmail.com> References: <20170106064900.GC28091@gmail.com> <20170107073553.GA13565@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: Subject: [kernel-hardening] Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location To: Thomas Garnier Cc: Andy Lutomirski , Arjan van de Ven , Thomas Gleixner , Ingo Molnar , "H . Peter Anvin" , Kees Cook , Borislav Petkov , Dave Hansen , Chen Yucong , Paul Gortmaker , Andrew Morton , Masahiro Yamada , Sebastian Andrzej Siewior , Anna-Maria Gleixner , Boris Ostrovsky , Rasmus Villemoes , Michael Ellerman , Juergen Gross , Richard Weinberger , X86 ML , "linux-kernel@vger.kernel.org" , "kernel-hardening@lists.openwall.com" List-ID: * Thomas Garnier wrote: > Coming back on that after a bit more testing. The LTR instruction > check if the busy bit is already set, if already set then it will just > issue a #GP given a bad selector: > > [ 0.000000] general protection fault: 0040 [#1] SMP > ... > [ 0.000000] RIP: 0010:native_load_tr_desc+0x9/0x10 > ... > [ 0.000000] Call Trace: > [ 0.000000] cpu_init+0x2d0/0x3c0 > [ 0.000000] trap_init+0x2a2/0x312 > [ 0.000000] start_kernel+0x1fb/0x43b > [ 0.000000] ? set_init_arg+0x55/0x55 > [ 0.000000] ? early_idt_handler_array+0x120/0x120 > [ 0.000000] x86_64_start_reservations+0x2a/0x2c > [ 0.000000] x86_64_start_kernel+0x13d/0x14c > [ 0.000000] start_cpu+0x14/0x14 > > I assume that's in this part of the pseudo-code: > > if(!IsWithinDescriptorTableLimit(Source.Offset) || Source.Type != > TypeGlobal) Exception(GP(SegmentSelector)); > SegmentDescriptor = ReadSegmentDescriptor(); > if(!IsForAnAvailableTSS(SegmentDescriptor)) > Exception(GP(SegmentSelector)); <---- That's where I got the GP > TSSSegmentDescriptor.Busy = 1; > <------------------------------------------------------------------ > That's the pagefault I get otherwise > //Locked read-modify-write operation on the entire descriptor when > setting busy flag > TaskRegister.SegmentSelector = Source; > TaskRegister.SegmentDescriptor.TSSSegmentDescriptor; > > I assume the best option would be to make the remap read-write for the > LTR instruction. What do you think? So if LTR does not modify the GDT if the busy bit is already set, why don't we set the busy bit in the descriptor (via the linear mapping rw alias). Then the remapped GDT can stay read-only all the time and LTR won't fault. Am I missing something here? Thanks, Ingo From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1765467AbdAJK1l (ORCPT ); Tue, 10 Jan 2017 05:27:41 -0500 Received: from mail-wj0-f196.google.com ([209.85.210.196]:36591 "EHLO mail-wj0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753570AbdAJK1i (ORCPT ); Tue, 10 Jan 2017 05:27:38 -0500 Date: Tue, 10 Jan 2017 11:27:33 +0100 From: Ingo Molnar To: Thomas Garnier Cc: Andy Lutomirski , Arjan van de Ven , Thomas Gleixner , Ingo Molnar , "H . Peter Anvin" , Kees Cook , Borislav Petkov , Dave Hansen , Chen Yucong , Paul Gortmaker , Andrew Morton , Masahiro Yamada , Sebastian Andrzej Siewior , Anna-Maria Gleixner , Boris Ostrovsky , Rasmus Villemoes , Michael Ellerman , Juergen Gross , Richard Weinberger , X86 ML , "linux-kernel@vger.kernel.org" , "kernel-hardening@lists.openwall.com" Subject: Re: [RFC] x86/mm/KASLR: Remap GDTs at fixed location Message-ID: <20170110102733.GA5638@gmail.com> References: <20170106064900.GC28091@gmail.com> <20170107073553.GA13565@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org * Thomas Garnier wrote: > Coming back on that after a bit more testing. The LTR instruction > check if the busy bit is already set, if already set then it will just > issue a #GP given a bad selector: > > [ 0.000000] general protection fault: 0040 [#1] SMP > ... > [ 0.000000] RIP: 0010:native_load_tr_desc+0x9/0x10 > ... > [ 0.000000] Call Trace: > [ 0.000000] cpu_init+0x2d0/0x3c0 > [ 0.000000] trap_init+0x2a2/0x312 > [ 0.000000] start_kernel+0x1fb/0x43b > [ 0.000000] ? set_init_arg+0x55/0x55 > [ 0.000000] ? early_idt_handler_array+0x120/0x120 > [ 0.000000] x86_64_start_reservations+0x2a/0x2c > [ 0.000000] x86_64_start_kernel+0x13d/0x14c > [ 0.000000] start_cpu+0x14/0x14 > > I assume that's in this part of the pseudo-code: > > if(!IsWithinDescriptorTableLimit(Source.Offset) || Source.Type != > TypeGlobal) Exception(GP(SegmentSelector)); > SegmentDescriptor = ReadSegmentDescriptor(); > if(!IsForAnAvailableTSS(SegmentDescriptor)) > Exception(GP(SegmentSelector)); <---- That's where I got the GP > TSSSegmentDescriptor.Busy = 1; > <------------------------------------------------------------------ > That's the pagefault I get otherwise > //Locked read-modify-write operation on the entire descriptor when > setting busy flag > TaskRegister.SegmentSelector = Source; > TaskRegister.SegmentDescriptor.TSSSegmentDescriptor; > > I assume the best option would be to make the remap read-write for the > LTR instruction. What do you think? So if LTR does not modify the GDT if the busy bit is already set, why don't we set the busy bit in the descriptor (via the linear mapping rw alias). Then the remapped GDT can stay read-only all the time and LTR won't fault. Am I missing something here? Thanks, Ingo