On 12/23/22 06:32, Ilya Leoshkevich wrote:
+    mmap_lock();
+    p = pageflags_find(address, address);
+    mmap_unlock();

How does the code ensure that p is not freed here?

+    return p ? p->flags : 0;

Yep, need to use g_free_rcu.

+    while (true) {
+        PageFlagsNode *p = pageflags_find(start, last);

We can end up here without mmap_lock if we come from the syscall code.
Do we need a retry like in page_get_flags()?

Yep, need to retry.


Speaking of which: does lock_user() actually guarantee that it's safe
to access the respective pages until unlock_user()? If yes, doesn't
this mean that mmap_lock must be held between the two? And if no, and
the SEGV handler is already supposed to gracefully handle SEGVs in
syscall.c, do we need to call access_ok_untagged() there at all?

No, it doesn't, really guarantee anything. We can't hold a lock across a blocking syscall, so lock_user() can't really lock. We do need to page_unprotect writable pages, which is the main thing accomplished by the access_ok check.

+        if (qemu_host_page_size <= TARGET_PAGE_SIZE) {
+            start = address & TARGET_PAGE_MASK;
+            len = TARGET_PAGE_SIZE;
+            prot = p->flags | PAGE_WRITE;
+            pageflags_set_clear(start, start + len - 1, PAGE_WRITE, 0);
+            current_tb_invalidated = tb_invalidate_phys_page_unwind(start, pc);

When we come from page_check_range(), pc == 0 and the assertion in
tb_invalidate_phys_page_unwind() fires.

Yep, the assertion is wrong.


Should we pass
current_cpu->cc->get_pc() to page_unprotect() instead of 0, so that
current_tb is resolved to the TB that invoked the syscall?

It's not a guest pc, but the host unwind pc, so, no.


r~

Reply via email to