Commit 3dd98412ba5a54be627531a385faa539167ddbdf

Authored by bellard
1 parent 271a916e

added lock_user() in target_strlen()


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3639 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 34 additions and 9 deletions
linux-user/uaccess.c
... ... @@ -37,15 +37,40 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
37 37 return ret;
38 38 }
39 39  
  40 +/* XXX: use host strnlen if available ? */
  41 +static int qemu_strnlen(const char *s, int max_len)
  42 +{
  43 + int i;
  44 + for(i = 0; i < max_len; i++) {
  45 + if (s[i] == '\0')
  46 + break;
  47 + }
  48 + return i;
  49 +}
40 50  
41   -/* Return the length of a string in target memory. */
42   -/* FIXME - this doesn't check access_ok() - it's rather complicated to
43   - * do it correctly because we need to check the bytes in a page and then
44   - * skip to the next page and check the bytes there until we find the
45   - * terminator. There should be a general function to do this that
46   - * can look for any byte terminator in a buffer - not strlen().
47   - */
48   -abi_long target_strlen(abi_ulong gaddr)
  51 +/* Return the length of a string in target memory or -TARGET_EFAULT if
  52 + access error */
  53 +abi_long target_strlen(abi_ulong guest_addr1)
49 54 {
50   - return strlen(g2h(gaddr));
  55 + uint8_t *ptr;
  56 + abi_ulong guest_addr;
  57 + int max_len, len;
  58 +
  59 + guest_addr = guest_addr1;
  60 + for(;;) {
  61 + max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK);
  62 + ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1);
  63 + if (!ptr)
  64 + return -TARGET_EFAULT;
  65 + len = qemu_strnlen(ptr, max_len);
  66 + unlock_user(ptr, guest_addr, 0);
  67 + guest_addr += len;
  68 + /* we don't allow wrapping or integer overflow */
  69 + if (guest_addr == 0 ||
  70 + (guest_addr - guest_addr1) > 0x7fffffff)
  71 + return -TARGET_EFAULT;
  72 + if (len != max_len)
  73 + break;
  74 + }
  75 + return guest_addr - guest_addr1;
51 76 }
... ...