target_os_stack.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * FreeBSD setup_initial_stack() implementation.
  3. *
  4. * Copyright (c) 2013-14 Stacey D. Son
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef TARGET_OS_STACK_H
  20. #define TARGET_OS_STACK_H
  21. #include <sys/param.h>
  22. #include "target_arch_sigtramp.h"
  23. #include "qemu/guest-random.h"
  24. #include "user/tswap-target.h"
  25. /*
  26. * The initial FreeBSD stack is as follows:
  27. * (see kern/kern_exec.c exec_copyout_strings() )
  28. *
  29. * Hi Address -> char **ps_argvstr (struct ps_strings for ps, w, etc.)
  30. * unsigned ps_nargvstr
  31. * char **ps_envstr
  32. * PS_STRINGS -> unsigned ps_nenvstr
  33. *
  34. * machine dependent sigcode (sv_sigcode of size
  35. * sv_szsigcode)
  36. *
  37. * execpath (absolute image path for rtld)
  38. *
  39. * SSP Canary (sizeof(long) * 8)
  40. *
  41. * page sizes array (usually sizeof(u_long) )
  42. *
  43. * "destp" -> argv, env strings (up to 262144 bytes)
  44. */
  45. static inline int setup_initial_stack(struct bsd_binprm *bprm,
  46. abi_ulong *ret_addr, abi_ulong *stringp)
  47. {
  48. int i;
  49. abi_ulong stack_hi_addr;
  50. size_t execpath_len, stringspace;
  51. abi_ulong destp, argvp, envp, p;
  52. struct target_ps_strings ps_strs;
  53. char canary[sizeof(abi_long) * 8];
  54. stack_hi_addr = p = target_stkbas + target_stksiz;
  55. /* Save some space for ps_strings. */
  56. p -= sizeof(struct target_ps_strings);
  57. /* Add machine dependent sigcode. */
  58. p -= TARGET_SZSIGCODE;
  59. if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
  60. TARGET_FREEBSD_NR_sigreturn)) {
  61. errno = EFAULT;
  62. return -1;
  63. }
  64. if (bprm->fullpath) {
  65. execpath_len = strlen(bprm->fullpath) + 1;
  66. p -= roundup(execpath_len, sizeof(abi_ulong));
  67. if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
  68. errno = EFAULT;
  69. return -1;
  70. }
  71. }
  72. /* Add canary for SSP. */
  73. qemu_guest_getrandom_nofail(canary, sizeof(canary));
  74. p -= roundup(sizeof(canary), sizeof(abi_ulong));
  75. if (memcpy_to_target(p, canary, sizeof(canary))) {
  76. errno = EFAULT;
  77. return -1;
  78. }
  79. /* Add page sizes array. */
  80. p -= sizeof(abi_ulong);
  81. if (put_user_ual(TARGET_PAGE_SIZE, p)) {
  82. errno = EFAULT;
  83. return -1;
  84. }
  85. /*
  86. * Deviate from FreeBSD stack layout: force stack to new page here
  87. * so that signal trampoline is not sharing the page with user stack
  88. * frames. This is actively harmful in qemu as it marks pages with
  89. * code it translated as read-only, which is somewhat problematic
  90. * for user trying to use the stack as intended.
  91. */
  92. p = rounddown(p, TARGET_PAGE_SIZE);
  93. /* Calculate the string space needed */
  94. stringspace = 0;
  95. for (i = 0; i < bprm->argc; ++i) {
  96. stringspace += strlen(bprm->argv[i]) + 1;
  97. }
  98. for (i = 0; i < bprm->envc; ++i) {
  99. stringspace += strlen(bprm->envp[i]) + 1;
  100. }
  101. if (stringspace > TARGET_ARG_MAX) {
  102. errno = ENOMEM;
  103. return -1;
  104. }
  105. /* Make room for the argv and envp strings */
  106. destp = rounddown(p - stringspace, sizeof(abi_ulong));
  107. p = argvp = destp - (bprm->argc + bprm->envc + 2) * sizeof(abi_ulong);
  108. /* Remember the strings pointer */
  109. if (stringp) {
  110. *stringp = destp;
  111. }
  112. /*
  113. * Add argv strings. Note that the argv[] vectors are added by
  114. * loader_build_argptr()
  115. */
  116. /* XXX need to make room for auxargs */
  117. ps_strs.ps_argvstr = tswapl(argvp);
  118. ps_strs.ps_nargvstr = tswap32(bprm->argc);
  119. for (i = 0; i < bprm->argc; ++i) {
  120. size_t len = strlen(bprm->argv[i]) + 1;
  121. if (memcpy_to_target(destp, bprm->argv[i], len)) {
  122. errno = EFAULT;
  123. return -1;
  124. }
  125. if (put_user_ual(destp, argvp)) {
  126. errno = EFAULT;
  127. return -1;
  128. }
  129. argvp += sizeof(abi_ulong);
  130. destp += len;
  131. }
  132. if (put_user_ual(0, argvp)) {
  133. errno = EFAULT;
  134. return -1;
  135. }
  136. /*
  137. * Add env strings. Note that the envp[] vectors are added by
  138. * loader_build_argptr().
  139. */
  140. envp = argvp + sizeof(abi_ulong);
  141. ps_strs.ps_envstr = tswapl(envp);
  142. ps_strs.ps_nenvstr = tswap32(bprm->envc);
  143. for (i = 0; i < bprm->envc; ++i) {
  144. size_t len = strlen(bprm->envp[i]) + 1;
  145. if (memcpy_to_target(destp, bprm->envp[i], len)) {
  146. errno = EFAULT;
  147. return -1;
  148. }
  149. if (put_user_ual(destp, envp)) {
  150. errno = EFAULT;
  151. return -1;
  152. }
  153. envp += sizeof(abi_ulong);
  154. destp += len;
  155. }
  156. if (put_user_ual(0, envp)) {
  157. errno = EFAULT;
  158. return -1;
  159. }
  160. if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
  161. sizeof(ps_strs))) {
  162. errno = EFAULT;
  163. return -1;
  164. }
  165. if (ret_addr) {
  166. *ret_addr = p;
  167. }
  168. return 0;
  169. }
  170. #endif /* TARGET_OS_STACK_H */