Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20220120-1' into...
[qemu.git] / bsd-user / freebsd / target_os_stack.h
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
20 #ifndef _TARGET_OS_STACK_H_
21 #define _TARGET_OS_STACK_H_
22
23 #include <sys/param.h>
24 #include "target_arch_sigtramp.h"
25 #include "qemu/guest-random.h"
26
27 /*
28 * The inital FreeBSD stack is as follows:
29 * (see kern/kern_exec.c exec_copyout_strings() )
30 *
31 * Hi Address -> char **ps_argvstr (struct ps_strings for ps, w, etc.)
32 * unsigned ps_nargvstr
33 * char **ps_envstr
34 * PS_STRINGS -> unsigned ps_nenvstr
35 *
36 * machine dependent sigcode (sv_sigcode of size
37 * sv_szsigcode)
38 *
39 * execpath (absolute image path for rtld)
40 *
41 * SSP Canary (sizeof(long) * 8)
42 *
43 * page sizes array (usually sizeof(u_long) )
44 *
45 * "destp" -> argv, env strings (up to 262144 bytes)
46 */
47 static inline int setup_initial_stack(struct bsd_binprm *bprm,
48 abi_ulong *ret_addr, abi_ulong *stringp)
49 {
50 int i;
51 abi_ulong stack_hi_addr;
52 size_t execpath_len, stringspace;
53 abi_ulong destp, argvp, envp, p;
54 struct target_ps_strings ps_strs;
55 char canary[sizeof(abi_long) * 8];
56
57 stack_hi_addr = p = target_stkbas + target_stksiz;
58
59 /* Save some space for ps_strings. */
60 p -= sizeof(struct target_ps_strings);
61
62 /* Add machine depedent sigcode. */
63 p -= TARGET_SZSIGCODE;
64 if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
65 TARGET_FREEBSD_NR_sigreturn)) {
66 errno = EFAULT;
67 return -1;
68 }
69 if (bprm->fullpath) {
70 execpath_len = strlen(bprm->fullpath) + 1;
71 p -= roundup(execpath_len, sizeof(abi_ulong));
72 if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
73 errno = EFAULT;
74 return -1;
75 }
76 }
77 /* Add canary for SSP. */
78 qemu_guest_getrandom_nofail(canary, sizeof(canary));
79 p -= roundup(sizeof(canary), sizeof(abi_ulong));
80 if (memcpy_to_target(p, canary, sizeof(canary))) {
81 errno = EFAULT;
82 return -1;
83 }
84 /* Add page sizes array. */
85 p -= sizeof(abi_ulong);
86 if (put_user_ual(TARGET_PAGE_SIZE, p)) {
87 errno = EFAULT;
88 return -1;
89 }
90 /*
91 * Deviate from FreeBSD stack layout: force stack to new page here
92 * so that signal trampoline is not sharing the page with user stack
93 * frames. This is actively harmful in qemu as it marks pages with
94 * code it translated as read-only, which is somewhat problematic
95 * for user trying to use the stack as intended.
96 */
97 p = rounddown(p, TARGET_PAGE_SIZE);
98
99 /* Calculate the string space needed */
100 stringspace = 0;
101 for (i = 0; i < bprm->argc; ++i) {
102 stringspace += strlen(bprm->argv[i]) + 1;
103 }
104 for (i = 0; i < bprm->envc; ++i) {
105 stringspace += strlen(bprm->envp[i]) + 1;
106 }
107 if (stringspace > TARGET_ARG_MAX) {
108 errno = ENOMEM;
109 return -1;
110 }
111 /* Make room for the argv and envp strings */
112 destp = rounddown(p - stringspace, sizeof(abi_ulong));
113 p = argvp = destp - (bprm->argc + bprm->envc + 2) * sizeof(abi_ulong);
114 /* Remember the strings pointer */
115 if (stringp) {
116 *stringp = destp;
117 }
118 /*
119 * Add argv strings. Note that the argv[] vectors are added by
120 * loader_build_argptr()
121 */
122 /* XXX need to make room for auxargs */
123 ps_strs.ps_argvstr = tswapl(argvp);
124 ps_strs.ps_nargvstr = tswap32(bprm->argc);
125 for (i = 0; i < bprm->argc; ++i) {
126 size_t len = strlen(bprm->argv[i]) + 1;
127
128 if (memcpy_to_target(destp, bprm->argv[i], len)) {
129 errno = EFAULT;
130 return -1;
131 }
132 if (put_user_ual(destp, argvp)) {
133 errno = EFAULT;
134 return -1;
135 }
136 argvp += sizeof(abi_ulong);
137 destp += len;
138 }
139 if (put_user_ual(0, argvp)) {
140 errno = EFAULT;
141 return -1;
142 }
143 /*
144 * Add env strings. Note that the envp[] vectors are added by
145 * loader_build_argptr().
146 */
147 envp = argvp + sizeof(abi_ulong);
148 ps_strs.ps_envstr = tswapl(envp);
149 ps_strs.ps_nenvstr = tswap32(bprm->envc);
150 for (i = 0; i < bprm->envc; ++i) {
151 size_t len = strlen(bprm->envp[i]) + 1;
152
153 if (memcpy_to_target(destp, bprm->envp[i], len)) {
154 errno = EFAULT;
155 return -1;
156 }
157 if (put_user_ual(destp, envp)) {
158 errno = EFAULT;
159 return -1;
160 }
161 envp += sizeof(abi_ulong);
162 destp += len;
163 }
164 if (put_user_ual(0, envp)) {
165 errno = EFAULT;
166 return -1;
167 }
168 if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
169 sizeof(ps_strs))) {
170 errno = EFAULT;
171 return -1;
172 }
173
174 if (ret_addr) {
175 *ret_addr = p;
176 }
177
178 return 0;
179 }
180
181 #endif /* !_TARGET_OS_STACK_H_ */