* [Qemu-devel] [PATCH] translate-all: Bugfix for user-mode self-modifying code in 2 page long TB
@ 2016-07-05 10:45 Stanislav Shmarov
2016-07-05 19:31 ` Sergey Fedorov
0 siblings, 1 reply; 3+ messages in thread
From: Stanislav Shmarov @ 2016-07-05 10:45 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Peter Crosthwaite, Richard Henderson,
Stanislav Shmarov
In user-mode emulation Translation Block can consist of 2 guest pages.
In that case QEMU also mprotects 2 host pages that are dedicated for
guest memory, containing instructions. QEMU detects self-modifying code
with SEGFAULT signal processing.
In case if instruction in 1st page is modifying memory of 2nd
page (or vice versa) QEMU will mark 2nd page with PAGE_WRITE,
invalidate TB, generate new TB contatining 1 guest instruction and
exit to CPU loop. QEMU won't call mprotect, and new TB will cause
same SEGFAULT. Page will have both PAGE_WRITE_ORG and PAGE_WRITE
flags, so QEMU will handle the signal as guest binary problem,
and exit with guest SEGFAULT.
Solution is retranslate TB before marking pages as PAGE_WRITE,
and remove protection with mprotect on second SEGFAULT.
Signed-off-by: Stanislav Shmarov <snarpix@gmail.com>
---
translate-all.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/translate-all.c b/translate-all.c
index eaa95e4..1e2ac84 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -2022,11 +2022,7 @@ int page_unprotect(target_ulong address, uintptr_t pc)
prot = 0;
for (addr = host_start ; addr < host_end ; addr += TARGET_PAGE_SIZE) {
- p = page_find(addr >> TARGET_PAGE_BITS);
- p->flags |= PAGE_WRITE;
- prot |= p->flags;
-
- /* and since the content will be modified, we must invalidate
+ /* Since the content will be modified, we must invalidate
the corresponding translated code. */
if (tb_invalidate_phys_page(addr, pc)) {
mmap_unlock();
@@ -2035,6 +2031,10 @@ int page_unprotect(target_ulong address, uintptr_t pc)
#ifdef DEBUG_TB_CHECK
tb_invalidate_check(addr);
#endif
+
+ p = page_find(addr >> TARGET_PAGE_BITS);
+ p->flags |= PAGE_WRITE;
+ prot |= p->flags;
}
mprotect((void *)g2h(host_start), qemu_host_page_size,
prot & PAGE_BITS);
--
1.9.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] [PATCH] translate-all: Bugfix for user-mode self-modifying code in 2 page long TB
2016-07-05 10:45 [Qemu-devel] [PATCH] translate-all: Bugfix for user-mode self-modifying code in 2 page long TB Stanislav Shmarov
@ 2016-07-05 19:31 ` Sergey Fedorov
2016-07-06 7:58 ` Стас Шмаров
0 siblings, 1 reply; 3+ messages in thread
From: Sergey Fedorov @ 2016-07-05 19:31 UTC (permalink / raw)
To: Stanislav Shmarov, qemu-devel
Cc: Paolo Bonzini, Richard Henderson, Peter Crosthwaite
On 05/07/16 13:45, Stanislav Shmarov wrote:
> In user-mode emulation Translation Block can consist of 2 guest pages.
> In that case QEMU also mprotects 2 host pages that are dedicated for
> guest memory, containing instructions. QEMU detects self-modifying code
> with SEGFAULT signal processing.
>
> In case if instruction in 1st page is modifying memory of 2nd
> page (or vice versa) QEMU will mark 2nd page with PAGE_WRITE,
> invalidate TB, generate new TB contatining 1 guest instruction and
> exit to CPU loop. QEMU won't call mprotect, and new TB will cause
> same SEGFAULT. Page will have both PAGE_WRITE_ORG and PAGE_WRITE
> flags, so QEMU will handle the signal as guest binary problem,
> and exit with guest SEGFAULT.
>
> Solution is retranslate TB before marking pages as PAGE_WRITE,
> and remove protection with mprotect on second SEGFAULT.
>
> Signed-off-by: Stanislav Shmarov <snarpix@gmail.com>
> ---
> translate-all.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/translate-all.c b/translate-all.c
> index eaa95e4..1e2ac84 100644
> --- a/translate-all.c
> +++ b/translate-all.c
> @@ -2022,11 +2022,7 @@ int page_unprotect(target_ulong address, uintptr_t pc)
>
> prot = 0;
> for (addr = host_start ; addr < host_end ; addr += TARGET_PAGE_SIZE) {
> - p = page_find(addr >> TARGET_PAGE_BITS);
> - p->flags |= PAGE_WRITE;
> - prot |= p->flags;
> -
> - /* and since the content will be modified, we must invalidate
> + /* Since the content will be modified, we must invalidate
> the corresponding translated code. */
> if (tb_invalidate_phys_page(addr, pc)) {
> mmap_unlock();
> @@ -2035,6 +2031,10 @@ int page_unprotect(target_ulong address, uintptr_t pc)
> #ifdef DEBUG_TB_CHECK
> tb_invalidate_check(addr);
> #endif
> +
> + p = page_find(addr >> TARGET_PAGE_BITS);
> + p->flags |= PAGE_WRITE;
> + prot |= p->flags;
I'm afraid you need to do this even later, out of the loop for guest
pages, to ensure that mprotect() will be eventually called. That will
require a separate loop through all the guest pages which make up the
host page.
Kind regards,
Sergey
> }
> mprotect((void *)g2h(host_start), qemu_host_page_size,
> prot & PAGE_BITS);
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] [PATCH] translate-all: Bugfix for user-mode self-modifying code in 2 page long TB
2016-07-05 19:31 ` Sergey Fedorov
@ 2016-07-06 7:58 ` Стас Шмаров
0 siblings, 0 replies; 3+ messages in thread
From: Стас Шмаров @ 2016-07-06 7:58 UTC (permalink / raw)
To: Sergey Fedorov
Cc: qemu-devel, Paolo Bonzini, Richard Henderson, Peter Crosthwaite
Yes, you are right. If host page contains several guest pages, and
instruction in TB from second page writes to first(not associated with that
TB), that will cause the same problem. I updated the patch.
2016-07-05 22:31 GMT+03:00 Sergey Fedorov <serge.fdrv@gmail.com>:
> On 05/07/16 13:45, Stanislav Shmarov wrote:
> > In user-mode emulation Translation Block can consist of 2 guest pages.
> > In that case QEMU also mprotects 2 host pages that are dedicated for
> > guest memory, containing instructions. QEMU detects self-modifying code
> > with SEGFAULT signal processing.
> >
> > In case if instruction in 1st page is modifying memory of 2nd
> > page (or vice versa) QEMU will mark 2nd page with PAGE_WRITE,
> > invalidate TB, generate new TB contatining 1 guest instruction and
> > exit to CPU loop. QEMU won't call mprotect, and new TB will cause
> > same SEGFAULT. Page will have both PAGE_WRITE_ORG and PAGE_WRITE
> > flags, so QEMU will handle the signal as guest binary problem,
> > and exit with guest SEGFAULT.
> >
> > Solution is retranslate TB before marking pages as PAGE_WRITE,
> > and remove protection with mprotect on second SEGFAULT.
> >
> > Signed-off-by: Stanislav Shmarov <snarpix@gmail.com>
> > ---
> > translate-all.c | 10 +++++-----
> > 1 file changed, 5 insertions(+), 5 deletions(-)
> >
> > diff --git a/translate-all.c b/translate-all.c
> > index eaa95e4..1e2ac84 100644
> > --- a/translate-all.c
> > +++ b/translate-all.c
> > @@ -2022,11 +2022,7 @@ int page_unprotect(target_ulong address,
> uintptr_t pc)
> >
> > prot = 0;
> > for (addr = host_start ; addr < host_end ; addr +=
> TARGET_PAGE_SIZE) {
> > - p = page_find(addr >> TARGET_PAGE_BITS);
> > - p->flags |= PAGE_WRITE;
> > - prot |= p->flags;
> > -
> > - /* and since the content will be modified, we must
> invalidate
> > + /* Since the content will be modified, we must invalidate
> > the corresponding translated code. */
> > if (tb_invalidate_phys_page(addr, pc)) {
> > mmap_unlock();
> > @@ -2035,6 +2031,10 @@ int page_unprotect(target_ulong address,
> uintptr_t pc)
> > #ifdef DEBUG_TB_CHECK
> > tb_invalidate_check(addr);
> > #endif
> > +
> > + p = page_find(addr >> TARGET_PAGE_BITS);
> > + p->flags |= PAGE_WRITE;
> > + prot |= p->flags;
>
> I'm afraid you need to do this even later, out of the loop for guest
> pages, to ensure that mprotect() will be eventually called. That will
> require a separate loop through all the guest pages which make up the
> host page.
>
> Kind regards,
> Sergey
>
> > }
> > mprotect((void *)g2h(host_start), qemu_host_page_size,
> > prot & PAGE_BITS);
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2016-07-06 7:58 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-05 10:45 [Qemu-devel] [PATCH] translate-all: Bugfix for user-mode self-modifying code in 2 page long TB Stanislav Shmarov
2016-07-05 19:31 ` Sergey Fedorov
2016-07-06 7:58 ` Стас Шмаров
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).