Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/syscall/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -4540,6 +4540,11 @@ int64_t sys_mprotect(guest_t *g, uint64_t addr, uint64_t length, int prot)
return -LINUX_ENOMEM;
}
guest_region_set_prot(g, addr, mprot_end, prot);
if (prot & LINUX_PROT_EXEC) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The icache flush is added only in the high-VA branch (addr >= g->guest_size), but ordinary guest memory (text/heap/mmap below guest_size, which is the 64 GiB to 1 TiB primary window where ART JIT buffers live) is handled by the second mprot_off branch below, which never calls __builtin___clear_cache. For any mprotect(PROT_EXEC) at a normal guest VA, sys_mprotect returns without invalidating the instruction cache, so the stale-instruction bug the PR targets remains unfixed in the common case.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/syscall/mem.c, line 4543:

<comment>The icache flush is added only in the high-VA branch (`addr >= g->guest_size`), but ordinary guest memory (text/heap/mmap below `guest_size`, which is the 64 GiB to 1 TiB primary window where ART JIT buffers live) is handled by the second `mprot_off` branch below, which never calls `__builtin___clear_cache`. For any mprotect(PROT_EXEC) at a normal guest VA, `sys_mprotect` returns without invalidating the instruction cache, so the stale-instruction bug the PR targets remains unfixed in the common case.</comment>

<file context>
@@ -4540,6 +4540,11 @@ int64_t sys_mprotect(guest_t *g, uint64_t addr, uint64_t length, int prot)
                     return -LINUX_ENOMEM;
             }
             guest_region_set_prot(g, addr, mprot_end, prot);
+            if (prot & LINUX_PROT_EXEC) {
+                char *host_start = (char *) g->host_base + addr;
+                char *host_end = (char *) g->host_base + mprot_end;
</file context>

char *host_start = (char *) g->host_base + addr;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: In the high-VA branch the range passed to __builtin___clear_cache is computed as g->host_base + addr, but pages with addr >= guest_size are not backed at host_base + addr. Per the comment at mem.c:1439-1441 and host_ptr_for_gpa (mem.c:796), high-VA pages live in named-mapping/overflow-segment host buffers, so this flushes the wrong (primary-window) memory and leaves the actual instruction cache untouched. Resolve the host range with host_ptr_for_gpa(g, addr) / host_ptr_for_gpa(g, mprot_end) instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/syscall/mem.c, line 4544:

<comment>In the high-VA branch the range passed to `__builtin___clear_cache` is computed as `g->host_base + addr`, but pages with `addr >= guest_size` are not backed at `host_base + addr`. Per the comment at mem.c:1439-1441 and `host_ptr_for_gpa` (mem.c:796), high-VA pages live in named-mapping/overflow-segment host buffers, so this flushes the wrong (primary-window) memory and leaves the actual instruction cache untouched. Resolve the host range with `host_ptr_for_gpa(g, addr)` / `host_ptr_for_gpa(g, mprot_end)` instead.</comment>

<file context>
@@ -4540,6 +4540,11 @@ int64_t sys_mprotect(guest_t *g, uint64_t addr, uint64_t length, int prot)
             }
             guest_region_set_prot(g, addr, mprot_end, prot);
+            if (prot & LINUX_PROT_EXEC) {
+                char *host_start = (char *) g->host_base + addr;
+                char *host_end = (char *) g->host_base + mprot_end;
+                __builtin___clear_cache(host_start, host_end);
</file context>

char *host_end = (char *) g->host_base + mprot_end;
__builtin___clear_cache(host_start, host_end);
}
return 0;
}
uint64_t mprot_off = addr - g->ipa_base;
Expand Down
Loading