HEX_SYS_OPEN copied guest bytes into a fixed-size buffer until it found a
NUL. A missing terminator could overrun that buffer. Use lock_user() with
the ABI filename length and validate its terminating NUL before opening it.

Fixes: 7711fdba88b ("target/hexagon: add main arch-specific semihosting 
operations")
Link: 
https://lore.kernel.org/all/cafeaca9mos6vfhf2uhz8z4cdvab+7dy6hjb2emyz2alse-t...@mail.gmail.com/
Suggested-by: Peter Maydell <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 target/hexagon/hexswi.c | 29 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index bc809594335..cc48c9ba9f1 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -469,35 +469,29 @@ static void sim_handle_trap0(CPUHexagonState *env)
 
     case HEX_SYS_OPEN:
     {
-        char filename[BUFSIZ];
+        char *filename;
         target_ulong physical_filename_addr;
         unsigned int filemode;
-        uint32_t length;
+        uint32_t filename_len;
+        size_t filename_size;
         int real_openmode;
         int ret, err = 0;
-        int i = 0;
 
         if (get_user_u32(physical_filename_addr, swi_info) ||
             get_user_u32(filemode, swi_info + 4) ||
-            get_user_u32(length, swi_info + 8)) {
+            get_user_u32(filename_len, swi_info + 8)) {
             goto do_fault;
         }
 
-        if (length >= BUFSIZ) {
-            qemu_log_mask(LOG_GUEST_ERROR,
-                          "%s: filename too large (%" PRIu32 ")\n",
-                          __func__, length);
-            semi_cb(cs, -1, ENAMETOOLONG);
-            break;
+        /* The ABI length excludes the filename's terminating NUL. */
+        filename_size = (size_t)filename_len + 1;
+        filename = lock_user(VERIFY_READ, physical_filename_addr,
+                             filename_size, true);
+        if (!filename || filename[filename_len] != '\0') {
+            unlock_user(filename, physical_filename_addr, 0);
+            goto do_fault;
         }
 
-        do {
-            if (get_user_u8(filename[i], physical_filename_addr + i)) {
-                goto do_fault;
-            }
-            i++;
-        } while (filename[i - 1]);
-
         /* convert ARM ANGEL filemode into host filemode */
         if (filemode < ARRAY_SIZE(angel_to_host_filemode_table)) {
             real_openmode = angel_to_host_filemode_table[filemode];
@@ -505,6 +499,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
             qemu_log_mask(LOG_GUEST_ERROR,
                           "%s: invalid OPEN mode: %u\n",
                           __func__, filemode);
+            unlock_user(filename, physical_filename_addr, 0);
             semi_cb(cs, -1, EINVAL);
             break;
         }
-- 
2.34.1

Reply via email to