qemu/linux-user/uaccess.c
<<
>>
Prefs
   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
   8void *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
  28void 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
  46void *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 */
  59int 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
  73int 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  */
  90ssize_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}
 115