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