From eda897279aeef21d74b72c298534c91f2acedc28 Mon Sep 17 00:00:00 2001 From: tehzz Date: Mon, 11 May 2020 19:45:44 -0400 Subject: [PATCH] fix catalina issue of mprotect on stack memory by defaulting to mmap for darwin --- accel/tcg/translate-all.c | 23 ++++- darwin-user/irix/target_syscall.h | 2 +- darwin-user/syscall.c | 154 +++++------------------------- darwin-user/syscall_defs.h | 1 + 4 files changed, 46 insertions(+), 134 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 04bec8f896..838f1b8c6c 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -603,8 +603,27 @@ static inline void *split_cross_256mb(void *buf1, size_t size1) return buf1; } #endif - #ifdef USE_STATIC_CODE_GEN_BUFFER +#if defined(CONFIG_DARWIN_USER) +static inline void *alloc_code_gen_buffer(void) +{ + int prot = PROT_WRITE | PROT_READ | PROT_EXEC; + int flags = MAP_PRIVATE | MAP_ANON; + /* let a kernel pick an address close to the executable */ + uintptr_t start = 0; + /* Honor a command-line option limiting the size of the buffer. */ + size_t size = DEFAULT_CODE_GEN_BUFFER_SIZE; + void *buf; + + buf = mmap((void *)start, size, prot, flags, -1, 0); + if (buf == MAP_FAILED) { + return NULL; + } + + qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE); + return buf; +} +#else /* !CONFIG_DARWIN_USER */ static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE] __attribute__((aligned(CODE_GEN_ALIGN))); @@ -641,6 +660,8 @@ static inline void *alloc_code_gen_buffer(void) return buf; } +#endif /* CONFIG_DARWIN_USER */ + #elif defined(_WIN32) static inline void *alloc_code_gen_buffer(void) { diff --git a/darwin-user/irix/target_syscall.h b/darwin-user/irix/target_syscall.h index 25c2688122..449d5ddd51 100644 --- a/darwin-user/irix/target_syscall.h +++ b/darwin-user/irix/target_syscall.h @@ -41,7 +41,7 @@ struct target_dirent { char d_name[1]; }; /* size of struct target_dirent without the name array */ -#define target_dirent_len (offsetof(struct target_dirent, d_name)) +#define TARGET_DIRENT_LEN (offsetof(struct target_dirent, d_name)) /* IRIX sys/types.h */ typedef uint64_t target_ino64_t; diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c index 8a694654d5..dcba55f3a8 100644 --- a/darwin-user/syscall.c +++ b/darwin-user/syscall.c @@ -10806,12 +10806,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_getdents: { struct target_dirent *target_dirp; - struct dirent *host_dirp; DIR *dirp; abi_long dir_fd = arg1; abi_long count = arg3; - int found_err = FALSE; - // ret == bytes read, or target error code + + // ret == >0 => bytes read + // 0 => end of directory + // <0 => -(target errno) dirp = fdopendir(dir_fd); if (!dirp) { @@ -10819,12 +10820,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto fail; } - host_dirp = g_try_malloc(count); - if (!host_dirp) { - ret = -TARGET_ENOMEM; - goto fail; - } - // collect readdir calls into getdents dirp * buffer target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0); if (!target_dirp) { @@ -10837,10 +10832,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, uint target_reclen; uint name_len; + errno = 0; while ((de = readdir(dirp))) { // check if new entry will overflow the target buffer name_len = de->d_namlen + 1; - target_reclen = target_dirent_len + name_len; + target_reclen = TARGET_DIRENT_LEN + name_len; // is this the correct way to align this structure..? target_reclen = QEMU_ALIGN_UP(target_reclen, __alignof(struct target_dirent)); if (bytes_used + target_reclen > count) { @@ -10857,7 +10853,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, bytes_used += target_reclen; } - if (found_err) { + if (errno != 0) { ret = -host_to_target_errno(errno); } else { ret = bytes_used; @@ -10867,112 +10863,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, // which was used in `fdopendir` // closedir(dirp); } -// Old Linux code -// #ifdef __NR_getdents -// { -// struct target_dirent *target_dirp; -// struct linux_dirent *dirp; -// abi_long count = arg3; -// -// dirp = g_try_malloc(count); -// if (!dirp) { -// ret = -TARGET_ENOMEM; -// goto fail; -// } -// -// ret = get_errno(sys_getdents(arg1, dirp, count)); -// if (!is_error(ret)) { -// struct linux_dirent *de; -// struct target_dirent *tde; -// int len = ret; -// int reclen, treclen; -// int count1, tnamelen; -// -// count1 = 0; -// de = dirp; -// if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) -// goto efault; -// tde = target_dirp; -// while (len > 0) { -// reclen = de->d_reclen; -// tnamelen = reclen - offsetof(struct linux_dirent, d_name); -// tnamelen = strnlen(de->d_name, tnamelen) + 1; -// assert(tnamelen >= 0); -// treclen = tnamelen + offsetof(struct target_dirent, d_name); -// /* XXX: avoid buffer overflow, for the price of lost entries */ -// if (count1 + treclen > count) -// break; -// __put_user(treclen, &tde->d_reclen); -// __put_user(de->d_ino, &tde->d_ino); -// __put_user(de->d_off, &tde->d_off); -// memcpy(tde->d_name, de->d_name, tnamelen); -// de = (struct linux_dirent *)((char *)de + reclen); -// len -= reclen; -// tde = (struct target_dirent *)((char *)tde + treclen); -// count1 += treclen; -// } -// ret = count1; -// unlock_user(target_dirp, arg2, ret); -// } -// g_free(dirp); -// } -// #else -// /* Implement getdents in terms of getdents64 */ -// { -// struct linux_dirent64 *dirp; -// abi_long count = arg3; -// -// dirp = lock_user(VERIFY_WRITE, arg2, count, 0); -// if (!dirp) { -// goto efault; -// } -// ret = get_errno(sys_getdents64(arg1, dirp, count)); -// if (!is_error(ret)) { -// /* Convert the dirent64 structs to target dirent. We do this -// * in-place, since we can guarantee that a target_dirent is no -// * larger than a dirent64; however this means we have to be -// * careful to read everything before writing in the new format. -// */ -// struct linux_dirent64 *de; -// struct target_dirent *tde; -// int len = ret; -// int tlen = 0; -// -// de = dirp; -// tde = (struct target_dirent *)dirp; -// while (len > 0) { -// int namelen, treclen; -// int reclen = de->d_reclen; -// uint64_t ino = de->d_ino; -// int64_t off = de->d_off; -// uint8_t type = de->d_type; -// -// namelen = de->d_reclen - offsetof(struct linux_dirent64, d_name); -// namelen = strnlen(de->d_name, namelen); -// treclen = offsetof(struct target_dirent, d_name) -// + namelen + 2; -// treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long)); -// -// memmove(tde->d_name, de->d_name, namelen + 1); -// __put_user(ino, &tde->d_ino); -// __put_user(off, &tde->d_off); -// __put_user(treclen, &tde->d_reclen); -// #if !defined TARGET_ABI_IRIX && !defined TARGET_ABI_SOLARIS -// /* The target_dirent type is in what was formerly a padding -// * byte at the end of the structure: -// */ -// *(((char *)tde) + treclen - 1) = type; -// #endif -// de = (struct linux_dirent64 *)((char *)de + reclen); -// tde = (struct target_dirent *)((char *)tde + treclen); -// len -= reclen; -// tlen += treclen; -// } -// ret = tlen; -// } -// unlock_user(dirp, arg2, ret); -// } -// #endif #ifdef TARGET_NR_ngetdents if (ret >= 0 && num == TARGET_NR_ngetdents) { abi_long *p = lock_user(VERIFY_WRITE, arg4, sizeof(abi_long), 0); @@ -14484,23 +14374,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; - case TARGET_NR_syssgi_sysid: - { - char * buf = lock_user(VERIFY_WRITE, arg2, 64, 0); - if (!buf) { - goto efault; + case TARGET_NR_syssgi_sysid: + { + char * buf = lock_user(VERIFY_WRITE, arg2, 64, 0); + if (!buf) { + goto efault; + } + snprintf(buf, 64, "%12llx", 0x08006900000DULL); + ret = 0; + unlock_user(buf, arg2, 64); + break; } - snprintf(buf, 64, "%12llx", 0x08006900000DULL); + case TARGET_NR_syssgi_rldenv: + case TARGET_NR_syssgi_tosstsave: + case TARGET_NR_syssgi_fpbcopy: + case TARGET_NR_syssgi_getprocattr: /* ? 2nd=string 3rd=result ptr */ ret = 0; - unlock_user(buf, arg2, 64); break; - } - case TARGET_NR_syssgi_rldenv: - case TARGET_NR_syssgi_tosstsave: - case TARGET_NR_syssgi_fpbcopy: - case TARGET_NR_syssgi_getprocattr: /* ? 2nd=string 3rd=result ptr */ - ret = 0; - break; case TARGET_NR_syssgi_setgroups: case TARGET_NR_syssgi_getgroups: default: @@ -14508,7 +14398,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_ENOSYS; break; } - break; + break; } #endif #ifdef TARGET_NR_sginap diff --git a/darwin-user/syscall_defs.h b/darwin-user/syscall_defs.h index 316eea445e..2c8f02f814 100644 --- a/darwin-user/syscall_defs.h +++ b/darwin-user/syscall_defs.h @@ -3336,6 +3336,7 @@ struct target_utsname { /* wait flags */ #define TARGET_WEXITED 0001 +#define TARGET_WTRAPPED 0002 #define TARGET_WSTOPPED 0004 #define TARGET_WCONTINUED 0010 #define TARGET_WNOHANG 0100