1 | /* $NetBSD: linux_exec_machdep.c,v 1.22 2014/02/23 12:01:51 njoly Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. All advertising materials mentioning features or use of this software |
15 | * must display the following acknowledgement: |
16 | * This product includes software developed by Emmanuel Dreyfus |
17 | * 4. The name of the author may not be used to endorse or promote |
18 | * products derived from this software without specific prior written |
19 | * permission. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' |
22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
23 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | |
34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: linux_exec_machdep.c,v 1.22 2014/02/23 12:01:51 njoly Exp $" ); |
36 | |
37 | #define ELFSIZE 64 |
38 | |
39 | #include <sys/param.h> |
40 | #include <sys/systm.h> |
41 | #include <sys/kernel.h> |
42 | #include <sys/resource.h> |
43 | #include <sys/proc.h> |
44 | #include <sys/conf.h> |
45 | #include <sys/kmem.h> |
46 | #include <sys/exec_elf.h> |
47 | #include <sys/vnode.h> |
48 | #include <sys/lwp.h> |
49 | #include <sys/exec.h> |
50 | #include <sys/stat.h> |
51 | #include <sys/kauth.h> |
52 | #include <sys/cprng.h> |
53 | |
54 | #include <sys/cpu.h> |
55 | #include <machine/vmparam.h> |
56 | #include <sys/syscallargs.h> |
57 | |
58 | #include <uvm/uvm.h> |
59 | |
60 | #include <compat/linux/common/linux_types.h> |
61 | #include <compat/linux/common/linux_signal.h> |
62 | #include <compat/linux/common/linux_machdep.h> |
63 | #include <compat/linux/common/linux_util.h> |
64 | #include <compat/linux/common/linux_ioctl.h> |
65 | #include <compat/linux/common/linux_hdio.h> |
66 | #include <compat/linux/common/linux_exec.h> |
67 | #include <compat/linux/common/linux_errno.h> |
68 | #include <compat/linux/common/linux_prctl.h> |
69 | #include <compat/linux/common/linux_ipc.h> |
70 | #include <compat/linux/common/linux_sem.h> |
71 | #include <compat/linux/linux_syscallargs.h> |
72 | |
73 | int |
74 | linux_exec_setup_stack(struct lwp *l, struct exec_package *epp) |
75 | { |
76 | u_long max_stack_size; |
77 | u_long access_linear_min, access_size; |
78 | u_long noaccess_linear_min, noaccess_size; |
79 | |
80 | #ifndef USRSTACK32 |
81 | #define USRSTACK32 (0x00000000ffffffffL & ~PGOFSET) |
82 | #endif |
83 | |
84 | if (epp->ep_flags & EXEC_32) { |
85 | epp->ep_minsaddr = USRSTACK32; |
86 | max_stack_size = MAXSSIZ; |
87 | if (epp->ep_minsaddr > LINUX_USRSTACK32) |
88 | epp->ep_minsaddr = LINUX_USRSTACK32; |
89 | } else { |
90 | epp->ep_minsaddr = USRSTACK; |
91 | max_stack_size = MAXSSIZ; |
92 | if (epp->ep_minsaddr > LINUX_USRSTACK) |
93 | epp->ep_minsaddr = LINUX_USRSTACK; |
94 | |
95 | } |
96 | |
97 | epp->ep_maxsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, |
98 | max_stack_size); |
99 | epp->ep_ssize = l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur; |
100 | |
101 | /* |
102 | * set up commands for stack. note that this takes *two*, one to |
103 | * map the part of the stack which we can access, and one to map |
104 | * the part which we can't. |
105 | * |
106 | * arguably, it could be made into one, but that would require the |
107 | * addition of another mapping proc, which is unnecessary |
108 | */ |
109 | access_size = epp->ep_ssize; |
110 | access_linear_min = (u_long)STACK_ALLOC(epp->ep_minsaddr, access_size); |
111 | noaccess_size = max_stack_size - access_size; |
112 | noaccess_linear_min = (u_long)STACK_ALLOC(STACK_GROW(epp->ep_minsaddr, |
113 | access_size), noaccess_size); |
114 | if (noaccess_size > 0) { |
115 | NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size, |
116 | noaccess_linear_min, NULLVP, 0, VM_PROT_NONE, VMCMD_STACK); |
117 | } |
118 | KASSERT(access_size > 0); |
119 | NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, access_size, |
120 | access_linear_min, NULLVP, 0, VM_PROT_READ | VM_PROT_WRITE, |
121 | VMCMD_STACK); |
122 | |
123 | return 0; |
124 | } |
125 | |
126 | int |
127 | ELFNAME2(linux,copyargs)(struct lwp *l, struct exec_package *pack, |
128 | struct ps_strings *arginfo, char **stackp, void *argp) |
129 | { |
130 | struct linux_extra_stack_data64 *esdp, esd; |
131 | struct elf_args *ap; |
132 | struct vattr *vap; |
133 | Elf_Ehdr *eh; |
134 | Elf_Phdr *ph; |
135 | u_long phsize; |
136 | Elf_Addr phdr = 0; |
137 | int error; |
138 | int i; |
139 | |
140 | if ((error = copyargs(l, pack, arginfo, stackp, argp)) != 0) |
141 | return error; |
142 | |
143 | /* |
144 | * Push extra arguments on the stack needed by dynamically |
145 | * linked binaries and static binaries as well. |
146 | */ |
147 | memset(&esd, 0, sizeof(esd)); |
148 | esdp = (struct linux_extra_stack_data64 *)(*stackp); |
149 | ap = (struct elf_args *)pack->ep_emul_arg; |
150 | vap = pack->ep_vap; |
151 | eh = (Elf_Ehdr *)pack->ep_hdr; |
152 | |
153 | /* |
154 | * We forgot this, so we need to reload it now. XXX keep track of it? |
155 | */ |
156 | if (ap == NULL) { |
157 | phsize = eh->e_phnum * sizeof(Elf_Phdr); |
158 | ph = (Elf_Phdr *)kmem_alloc(phsize, KM_SLEEP); |
159 | error = exec_read_from(l, pack->ep_vp, eh->e_phoff, ph, phsize); |
160 | if (error != 0) { |
161 | for (i = 0; i < eh->e_phnum; i++) { |
162 | if (ph[i].p_type == PT_PHDR) { |
163 | phdr = ph[i].p_vaddr; |
164 | break; |
165 | } |
166 | } |
167 | } |
168 | kmem_free(ph, phsize); |
169 | } |
170 | |
171 | |
172 | /* |
173 | * The exec_package doesn't have a proc pointer and it's not |
174 | * exactly trivial to add one since the credentials are |
175 | * changing. XXX Linux uses curlwp's credentials. |
176 | * Why can't we use them too? |
177 | */ |
178 | |
179 | i = 0; |
180 | esd.ai[i].a_type = LINUX_AT_HWCAP; |
181 | esd.ai[i++].a_v = rcr4(); |
182 | |
183 | esd.ai[i].a_type = AT_PAGESZ; |
184 | esd.ai[i++].a_v = PAGE_SIZE; |
185 | |
186 | esd.ai[i].a_type = LINUX_AT_CLKTCK; |
187 | esd.ai[i++].a_v = hz; |
188 | |
189 | esd.ai[i].a_type = AT_PHDR; |
190 | esd.ai[i++].a_v = (ap ? ap->arg_phaddr: phdr); |
191 | |
192 | esd.ai[i].a_type = AT_PHENT; |
193 | esd.ai[i++].a_v = (ap ? ap->arg_phentsize : eh->e_phentsize); |
194 | |
195 | esd.ai[i].a_type = AT_PHNUM; |
196 | esd.ai[i++].a_v = (ap ? ap->arg_phnum : eh->e_phnum); |
197 | |
198 | esd.ai[i].a_type = AT_BASE; |
199 | esd.ai[i++].a_v = (ap ? ap->arg_interp : 0); |
200 | |
201 | esd.ai[i].a_type = AT_FLAGS; |
202 | esd.ai[i++].a_v = 0; |
203 | |
204 | esd.ai[i].a_type = AT_ENTRY; |
205 | esd.ai[i++].a_v = (ap ? ap->arg_entry : eh->e_entry); |
206 | |
207 | esd.ai[i].a_type = LINUX_AT_EGID; |
208 | esd.ai[i++].a_v = ((vap->va_mode & S_ISGID) ? |
209 | vap->va_gid : kauth_cred_getegid(l->l_cred)); |
210 | |
211 | esd.ai[i].a_type = LINUX_AT_GID; |
212 | esd.ai[i++].a_v = kauth_cred_getgid(l->l_cred); |
213 | |
214 | esd.ai[i].a_type = LINUX_AT_EUID; |
215 | esd.ai[i++].a_v = ((vap->va_mode & S_ISUID) ? |
216 | vap->va_uid : kauth_cred_geteuid(l->l_cred)); |
217 | |
218 | esd.ai[i].a_type = LINUX_AT_UID; |
219 | esd.ai[i++].a_v = kauth_cred_getuid(l->l_cred); |
220 | |
221 | esd.ai[i].a_type = LINUX_AT_SECURE; |
222 | esd.ai[i++].a_v = 0; |
223 | |
224 | esd.ai[i].a_type = LINUX_AT_PLATFORM; |
225 | esd.ai[i++].a_v = (Elf_Addr)&esdp->hw_platform[0]; |
226 | |
227 | esd.ai[i].a_type = LINUX_AT_RANDOM; |
228 | esd.ai[i++].a_v = (Elf_Addr)&esdp->randbytes[0]; |
229 | esd.randbytes[0] = cprng_strong32(); |
230 | esd.randbytes[1] = cprng_strong32(); |
231 | esd.randbytes[2] = cprng_strong32(); |
232 | esd.randbytes[3] = cprng_strong32(); |
233 | |
234 | esd.ai[i].a_type = AT_NULL; |
235 | esd.ai[i++].a_v = 0; |
236 | |
237 | KASSERT(i == LINUX_ELF_AUX_ENTRIES); |
238 | |
239 | strcpy(esd.hw_platform, LINUX_PLATFORM); |
240 | |
241 | exec_free_emul_arg(pack); |
242 | |
243 | /* |
244 | * Copy out the ELF auxiliary table and hw platform name |
245 | */ |
246 | if ((error = copyout(&esd, esdp, sizeof(esd))) != 0) |
247 | return error; |
248 | *stackp += sizeof(esd); |
249 | |
250 | return 0; |
251 | } |
252 | |