From: James Hogan <james.hogan@imgtec.com> To: "Maciej W. Rozycki" <macro@imgtec.com> Cc: Marcin Nowakowski <marcin.nowakowski@imgtec.com>, Ralf Baechle <ralf@linux-mips.org>, <linux-mips@linux-mips.org> Subject: Re: [PATCH v2 1/2] MIPS: ptrace: disallow setting watchpoints in kernel address space Date: Tue, 24 Jan 2017 22:05:54 +0000 [thread overview] Message-ID: <20170124220554.GM29015@jhogan-linux.le.imgtec.org> (raw) In-Reply-To: <alpine.DEB.2.00.1701241909540.13564@tp.orcam.me.uk> [-- Attachment #1: Type: text/plain, Size: 5026 bytes --] On Tue, Jan 24, 2017 at 08:52:22PM +0000, Maciej W. Rozycki wrote: > On Tue, 24 Jan 2017, James Hogan wrote: > > > > Can't for example the low-level exception handling entry/exit code be > > > moved out of the way of the EVA overlap range and then all watchpoints > > > masked for the duration of kernel mode execution? This would be quite > > > expensive, however it could only be executed if a task flag indicates > > > watchpoints are being used. > > > > That doesn't cover data watches. RAM would still need accessing, e.g. to > > save/restore the watch state from the thread context, or even to read > > the task flag, and stack accesses in C code. > > All the critical data structures would have to be outside the EVA > overlap. This in itself is awkward. If a SoC supports multiple RAM sizes, e.g. up to 2GB, you might want a single EVA kernel that could support both. Normally you could just go with a 2GB compatible layout (for the sake of argument, lets say RAM cached @ kernel VA 0x40000000 .. 0xBFFFFFFF, ignoring BEV overlays for now), but if less than 1GB is fitted then none of that RAM is outside of the user overlap range. > > > The only safe way for it to work would be to somehow disable or inhibit > > watchpoints before clearing EXL, and re-enable them after setting EXL, > > though you'd still get a loop of deferred watchpoints if it hit on the > > way out to user mode unless cleared at the last moment before ERET. > > Ah, I forgot about CP0.Cause.WP -- is it not enough to clear the bit to > have any pending exception cancelled? If so (and the architecture manual > is actually clear that it is) then it looks like we have a solution and we > don't have to place any code or data specially, although it'll have to be > carefully coded. > > > > Alternatively perhaps we could clobber > > > CP0.EntryHi.ASID, at least temporarily; that would be cheaper. > > > > Kernel mode still needs to access the user address space. > > Sure, that's why it would have to be temporary. Low-level exception > entry/exit code is not supposed to have a need to access user memory. Ah I see, really temporary. > > So we can put aside a certain ASID value, say 0 (for easy pasting with > INS from $0), and never use it for a real context. Then it can be cleared > right away at the general exception entry point if EVA is in use, say: > > <d>mfc0 $k0, $10 > <d>ins $k0, $zero, 0, 10 > <d>mtc0 $k0, $10 > > (there'll be a hazard here, but we can clear it later on if needed). > There is no neeed to save the old ASID as we can retrieve the original > from our data structures. > > Then we can proceed with the usual switch to the kernel mode, switching > stacks, saving registers, etc. We can then check CP0.Cause.WP and stash > it away for further processing if needed (though discarding it would I > think be the usual if not only choice) and clear, with a hazard barrier, > right before CP0.Status.EXL is cleared. > > Now that we're in the regular kernel mode, with ASID still set to 0, we > can check if process tracing has been enabled and if so, then iterate over > the watchpoints registers masking them all. At this point we can restore > the correct ASID in CP0.EntryHi and proceed with the exception handler. > > And then we'd do the reverse in the exception epilogue, only restoring > the ASID as the last instruction before final ERET. > > > Alternatively we could set WatchHi.ASID to a reserved one, and only > > clear/set the WatchHi.G bit (to bypass the ASID match) at the first/last > > moment while EXL=1. It still wouldn't protect against code watches > > around there exposing the kernel address of that code by the resulting > > hang though, so would need to move the ebase out of the overlap range > > too (which would have to be platform specific). > > You'd still have to iterate over all WatchHi registers, a variable number > up to 8 architecturally, which I think would be too expensive for the > common exception path. > > Poking at ASID as I described above is just a couple of instructions at > entry and exit, and the rest would only be done if tracing is active. > Plus you don't actually have to move anything away, except from the final > ERET, though likely not even that, owing to the delayed nature of an ASID > update. Probably, so long as you ignore QEMU. > > So can you find a flaw in my proposal so far? not a functional one. > We'll have to think about > the TLB refill handler yet though. A deferred watch from refill handler (e.g. page tables) would I think trigger an immediate watch exception on eret, and get cleared / ignored. It would probably make enough of a timing difference for userland to reliably detect (in order to probe where the process' page tables are in kernel virtual memory, to be able to mount a more successful attack given some other vulnerability). Cheers James [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 801 bytes --]
WARNING: multiple messages have this Message-ID (diff)
From: James Hogan <james.hogan@imgtec.com> To: "Maciej W. Rozycki" <macro@imgtec.com> Cc: Marcin Nowakowski <marcin.nowakowski@imgtec.com>, Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org Subject: Re: [PATCH v2 1/2] MIPS: ptrace: disallow setting watchpoints in kernel address space Date: Tue, 24 Jan 2017 22:05:54 +0000 [thread overview] Message-ID: <20170124220554.GM29015@jhogan-linux.le.imgtec.org> (raw) Message-ID: <20170124220554.a34plq9gol9dPA9R6jvkDPOxdp-hhBdhFBj5PeJJ94c@z> (raw) In-Reply-To: <alpine.DEB.2.00.1701241909540.13564@tp.orcam.me.uk> [-- Attachment #1: Type: text/plain, Size: 5026 bytes --] On Tue, Jan 24, 2017 at 08:52:22PM +0000, Maciej W. Rozycki wrote: > On Tue, 24 Jan 2017, James Hogan wrote: > > > > Can't for example the low-level exception handling entry/exit code be > > > moved out of the way of the EVA overlap range and then all watchpoints > > > masked for the duration of kernel mode execution? This would be quite > > > expensive, however it could only be executed if a task flag indicates > > > watchpoints are being used. > > > > That doesn't cover data watches. RAM would still need accessing, e.g. to > > save/restore the watch state from the thread context, or even to read > > the task flag, and stack accesses in C code. > > All the critical data structures would have to be outside the EVA > overlap. This in itself is awkward. If a SoC supports multiple RAM sizes, e.g. up to 2GB, you might want a single EVA kernel that could support both. Normally you could just go with a 2GB compatible layout (for the sake of argument, lets say RAM cached @ kernel VA 0x40000000 .. 0xBFFFFFFF, ignoring BEV overlays for now), but if less than 1GB is fitted then none of that RAM is outside of the user overlap range. > > > The only safe way for it to work would be to somehow disable or inhibit > > watchpoints before clearing EXL, and re-enable them after setting EXL, > > though you'd still get a loop of deferred watchpoints if it hit on the > > way out to user mode unless cleared at the last moment before ERET. > > Ah, I forgot about CP0.Cause.WP -- is it not enough to clear the bit to > have any pending exception cancelled? If so (and the architecture manual > is actually clear that it is) then it looks like we have a solution and we > don't have to place any code or data specially, although it'll have to be > carefully coded. > > > > Alternatively perhaps we could clobber > > > CP0.EntryHi.ASID, at least temporarily; that would be cheaper. > > > > Kernel mode still needs to access the user address space. > > Sure, that's why it would have to be temporary. Low-level exception > entry/exit code is not supposed to have a need to access user memory. Ah I see, really temporary. > > So we can put aside a certain ASID value, say 0 (for easy pasting with > INS from $0), and never use it for a real context. Then it can be cleared > right away at the general exception entry point if EVA is in use, say: > > <d>mfc0 $k0, $10 > <d>ins $k0, $zero, 0, 10 > <d>mtc0 $k0, $10 > > (there'll be a hazard here, but we can clear it later on if needed). > There is no neeed to save the old ASID as we can retrieve the original > from our data structures. > > Then we can proceed with the usual switch to the kernel mode, switching > stacks, saving registers, etc. We can then check CP0.Cause.WP and stash > it away for further processing if needed (though discarding it would I > think be the usual if not only choice) and clear, with a hazard barrier, > right before CP0.Status.EXL is cleared. > > Now that we're in the regular kernel mode, with ASID still set to 0, we > can check if process tracing has been enabled and if so, then iterate over > the watchpoints registers masking them all. At this point we can restore > the correct ASID in CP0.EntryHi and proceed with the exception handler. > > And then we'd do the reverse in the exception epilogue, only restoring > the ASID as the last instruction before final ERET. > > > Alternatively we could set WatchHi.ASID to a reserved one, and only > > clear/set the WatchHi.G bit (to bypass the ASID match) at the first/last > > moment while EXL=1. It still wouldn't protect against code watches > > around there exposing the kernel address of that code by the resulting > > hang though, so would need to move the ebase out of the overlap range > > too (which would have to be platform specific). > > You'd still have to iterate over all WatchHi registers, a variable number > up to 8 architecturally, which I think would be too expensive for the > common exception path. > > Poking at ASID as I described above is just a couple of instructions at > entry and exit, and the rest would only be done if tracing is active. > Plus you don't actually have to move anything away, except from the final > ERET, though likely not even that, owing to the delayed nature of an ASID > update. Probably, so long as you ignore QEMU. > > So can you find a flaw in my proposal so far? not a functional one. > We'll have to think about > the TLB refill handler yet though. A deferred watch from refill handler (e.g. page tables) would I think trigger an immediate watch exception on eret, and get cleared / ignored. It would probably make enough of a timing difference for userland to reliably detect (in order to probe where the process' page tables are in kernel virtual memory, to be able to mount a more successful attack given some other vulnerability). Cheers James [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 801 bytes --]
next prev parent reply other threads:[~2017-01-24 22:06 UTC|newest] Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top 2017-01-23 9:18 [PATCH v2 1/2] MIPS: ptrace: disallow setting watchpoints in kernel address space Marcin Nowakowski 2017-01-23 9:18 ` Marcin Nowakowski 2017-01-23 9:18 ` [PATCH v2 2/2] MIPS: ptrace: disable watchpoints if hit in kernel mode Marcin Nowakowski 2017-01-23 9:18 ` Marcin Nowakowski 2017-01-24 17:09 ` [PATCH v2 1/2] MIPS: ptrace: disallow setting watchpoints in kernel address space Maciej W. Rozycki 2017-01-24 17:09 ` Maciej W. Rozycki 2017-01-24 18:54 ` James Hogan 2017-01-24 18:54 ` James Hogan 2017-01-24 20:52 ` Maciej W. Rozycki 2017-01-24 20:52 ` Maciej W. Rozycki 2017-01-24 22:05 ` James Hogan [this message] 2017-01-24 22:05 ` James Hogan 2017-01-24 23:07 ` Maciej W. Rozycki 2017-01-24 23:07 ` Maciej W. Rozycki 2017-01-25 14:39 ` Maciej W. Rozycki 2017-01-25 14:39 ` Maciej W. Rozycki
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20170124220554.GM29015@jhogan-linux.le.imgtec.org \ --to=james.hogan@imgtec.com \ --cc=linux-mips@linux-mips.org \ --cc=macro@imgtec.com \ --cc=marcin.nowakowski@imgtec.com \ --cc=ralf@linux-mips.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).