qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

uaccess.c (2748B)


      1 /* User memory access */
      2 #include "qemu/osdep.h"
      3 #include "qemu/cutils.h"
      4 
      5 #include "qemu.h"
      6 #include "user-internals.h"
      7 
      8 void *lock_user(int type, abi_ulong guest_addr, ssize_t len, bool copy)
      9 {
     10     void *host_addr;
     11 
     12     guest_addr = cpu_untagged_addr(thread_cpu, guest_addr);
     13     if (!access_ok_untagged(type, guest_addr, len)) {
     14         return NULL;
     15     }
     16     host_addr = g2h_untagged(guest_addr);
     17 #ifdef DEBUG_REMAP
     18     if (copy) {
     19         host_addr = g_memdup(host_addr, len);
     20     } else {
     21         host_addr = g_malloc0(len);
     22     }
     23 #endif
     24     return host_addr;
     25 }
     26 
     27 #ifdef DEBUG_REMAP
     28 void unlock_user(void *host_ptr, abi_ulong guest_addr, ssize_t len)
     29 {
     30     void *host_ptr_conv;
     31 
     32     if (!host_ptr) {
     33         return;
     34     }
     35     host_ptr_conv = g2h(thread_cpu, guest_addr);
     36     if (host_ptr == host_ptr_conv) {
     37         return;
     38     }
     39     if (len > 0) {
     40         memcpy(host_ptr_conv, host_ptr, len);
     41     }
     42     g_free(host_ptr);
     43 }
     44 #endif
     45 
     46 void *lock_user_string(abi_ulong guest_addr)
     47 {
     48     ssize_t len = target_strlen(guest_addr);
     49     if (len < 0) {
     50         return NULL;
     51     }
     52     return lock_user(VERIFY_READ, guest_addr, len + 1, 1);
     53 }
     54 
     55 /* copy_from_user() and copy_to_user() are usually used to copy data
     56  * buffers between the target and host.  These internally perform
     57  * locking/unlocking of the memory.
     58  */
     59 int copy_from_user(void *hptr, abi_ulong gaddr, ssize_t len)
     60 {
     61     int ret = 0;
     62     void *ghptr = lock_user(VERIFY_READ, gaddr, len, 1);
     63 
     64     if (ghptr) {
     65         memcpy(hptr, ghptr, len);
     66         unlock_user(ghptr, gaddr, 0);
     67     } else {
     68         ret = -TARGET_EFAULT;
     69     }
     70     return ret;
     71 }
     72 
     73 int copy_to_user(abi_ulong gaddr, void *hptr, ssize_t len)
     74 {
     75     int ret = 0;
     76     void *ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0);
     77 
     78     if (ghptr) {
     79         memcpy(ghptr, hptr, len);
     80         unlock_user(ghptr, gaddr, len);
     81     } else {
     82         ret = -TARGET_EFAULT;
     83     }
     84 
     85     return ret;
     86 }
     87 
     88 /* Return the length of a string in target memory or -TARGET_EFAULT if
     89    access error  */
     90 ssize_t target_strlen(abi_ulong guest_addr1)
     91 {
     92     uint8_t *ptr;
     93     abi_ulong guest_addr;
     94     size_t max_len, len;
     95 
     96     guest_addr = guest_addr1;
     97     for(;;) {
     98         max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK);
     99         ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1);
    100         if (!ptr)
    101             return -TARGET_EFAULT;
    102         len = qemu_strnlen((const char *)ptr, max_len);
    103         unlock_user(ptr, guest_addr, 0);
    104         guest_addr += len;
    105         /* we don't allow wrapping or integer overflow */
    106         if (guest_addr == 0 || (guest_addr - guest_addr1) > 0x7fffffff) {
    107             return -TARGET_EFAULT;
    108         }
    109         if (len != max_len) {
    110             break;
    111         }
    112     }
    113     return guest_addr - guest_addr1;
    114 }