1 /*
2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "opt_compat.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/imgact.h>
40 #include <sys/imgact_aout.h>
41 #include <sys/imgact_elf.h>
42 #include <sys/kern_syscall.h>
43 #include <sys/lock.h>
44 #include <sys/mplock2.h>
45 #include <sys/malloc.h>
46 #include <sys/ptrace.h>
47 #include <sys/proc.h>
48 #include <sys/signalvar.h>
49 #include <sys/sysent.h>
50 #include <sys/sysproto.h>
51
52 #include <vm/vm.h>
53 #include <vm/vm_param.h>
54 #include <vm/vm_page.h>
55 #include <vm/vm_extern.h>
56 #include <sys/exec.h>
57 #include <sys/kernel.h>
58 #include <sys/module.h>
59 #include <machine/cpu.h>
60
61 #include "i386/linux.h"
62 #include "i386/linux_proto.h"
63 #include "linux_signal.h"
64 #include "linux_util.h"
65 #include "linux_emuldata.h"
66
67
68 struct lock emul_lock;
69
70 struct linux_emuldata *
71 emuldata_get(struct proc *p)
72 {
73 struct linux_emuldata *em;
74
75 EMUL_LOCK();
76
77 em = p->p_emuldata;
78
79 EMUL_UNLOCK();
80 return (em);
81 }
82
83 void
84 emuldata_set_robust(struct proc *p, struct linux_robust_list_head *robust_ftx)
85 {
86 struct linux_emuldata *em;
87
88 EMUL_LOCK();
89
90 em = emuldata_get(p);
91 KKASSERT(em != NULL);
92
93 em->robust_futexes = robust_ftx;
94 EMUL_UNLOCK();
95 }
96
97 int
98 emuldata_init(struct proc *p, struct proc *pchild, int flags)
99 {
100 struct linux_emuldata_shared *s;
101 struct linux_emuldata *em, *ep;
102 int error = 0;
103
104 EMUL_LOCK();
105
106 em = emuldata_get(p);
107
108 if (pchild == NULL) {
109 ep = NULL;
110 /* This is the execv* case, where a process gets overwritten */
111 KKASSERT(em != NULL);
112 KKASSERT(em->s != NULL);
113 if (atomic_fetchadd_int(&em->s->refs, -1) == 1) {
114 kfree(em->s, M_LINUX);
115 em->s = NULL;
116 }
117 if (em->s)
118 KKASSERT(em->s->refs >= 0);
119
120 em->parent_tidptr = NULL;
121 em->child_tidptr = NULL;
122 em->clone_flags = 0;
123 em->clear_tid = NULL;
124 em->set_tls = NULL;
125 em->proc = p;
126 } else {
127 ep = em;
128 em = kmalloc(sizeof(*em), M_LINUX, M_WAITOK | M_ZERO);
129 }
130
131 if (flags & LINUX_CLONE_THREAD) {
132 /*
133 * If CLONE_THREAD is set, the child is placed in the same
134 * thread group as the calling process.
135 */
136 KKASSERT(ep != NULL);
137 em->s = ep->s;
138 s = em->s;
139 } else {
140 /* new thread group */
141 s = kmalloc(sizeof(*s), M_LINUX, M_WAITOK | M_ZERO);
142 LIST_INIT(&s->threads);
143 if (pchild)
144 s->group_pid = pchild->p_pid;
145 else
146 s->group_pid = p->p_pid;
147 }
148
149 if (ep != NULL) {
150 em->parent_tidptr = ep->parent_tidptr;
151 em->child_tidptr = ep->child_tidptr;
152 #if 0
153 em->clone_flags = ep->clone_flags;
154 #endif
155 }
156
157 em->clone_flags = flags;
158
159 atomic_add_int(&s->refs, 1);
160 KKASSERT(s->refs >= 0);
161 em->s = s;
162 LIST_INSERT_HEAD(&s->threads, em, threads);
163
164
165 if (pchild != NULL) {
166 em->proc = pchild;
167 pchild->p_emuldata = em;
168 }
169
170 EMUL_UNLOCK();
171 return (error);
172 }
173
174 /* emuldata_exit is modelled after NetBSD's */
175 void
176 emuldata_exit(void *unused, struct proc *p)
177 {
178 struct linux_sys_futex_args cup;
179 struct linux_emuldata *em;
180 int error = 0;
181
182 if (__predict_true(p->p_sysent != &elf_linux_sysvec))
183 return;
184
185 release_futexes(p);
186 EMUL_LOCK();
187
188 em = emuldata_get(p);
189 if (em == NULL) {
190 EMUL_UNLOCK();
191 return;
192 }
193
194 LIST_REMOVE(em, threads);
195 p->p_emuldata = NULL;
196
197 /*
198 * Members of the thread groups others than the leader should
199 * exit quietely: no zombie stage, no signal. We do that by
200 * reparenting to init. init will collect us and nobody will
201 * notice what happened.
202 */
203 if ((em->s->group_pid != p->p_pid) &&
204 (em->clone_flags & LINUX_CLONE_THREAD)) {
205 p->p_sigparent = SIGCHLD;
206
207 proc_reparent(p, initproc);
208 wakeup((caddr_t)initproc); /* kern_exit seems to do this */
209 }
210
211 if ((em->s->group_pid == p->p_pid) &&
212 (em->s->flags & LINUX_LES_INEXITGROUP)) {
213 p->p_xstat = em->s->xstat;
214 }
215
216 if (atomic_fetchadd_int(&em->s->refs, -1) == 1) {
217 kfree(em->s, M_LINUX);
218 em->s = NULL;
219 }
220 if (em->s)
221 KKASSERT(em->s->refs >= 0);
222
223 EMUL_UNLOCK();
224
225 if (em->clear_tid != NULL) {
226 int tid = 0;
227 copyout(&tid, em->clear_tid, sizeof(tid));
228 cup.uaddr = em->clear_tid;
229 cup.op = LINUX_FUTEX_WAKE;
230 cup.val = 0x7fffffff; /* Awake everyone */
231 cup.timeout = NULL;
232 cup.uaddr2 = NULL;
233 cup.val3 = 0;
234 error = sys_linux_sys_futex(&cup);
235 if (error)
236 kprintf("emuldata_exit futex stuff failed miserably\n");
237 }
238
239 kfree(em, M_LINUX);
240 }
241
242 void
243 linux_proc_transition(void *unused, struct image_params *imgp)
244 {
245 struct proc *p;
246
247 p = imgp->proc;
248 if (__predict_false(imgp->proc->p_sysent == &elf_linux_sysvec &&
249 imgp->proc->p_emuldata == NULL)) {
250 #ifdef LINUX_DEBUG
251 kprintf("timidly hello from proc_transition\n");
252 #endif
253 emuldata_init(p, p, 0);
254 }
255 }
256
257 static void
258 linux_proc_userret(void)
259 {
260 struct proc *p = curproc;
261 struct linux_emuldata *em;
262
263 em = emuldata_get(p);
264 KKASSERT(em != NULL);
265
266 if (em->clone_flags & LINUX_CLONE_CHILD_SETTID) {
267 copyout(&p->p_pid, (int *)em->child_tidptr,
268 sizeof(p->p_pid));
269 }
270
271 return;
272 }
273
274 void
275 linux_proc_fork(struct proc *p, struct proc *parent, void *child_tidptr)
276 {
277 struct linux_emuldata *em;
278
279 em = emuldata_get(p);
280 KKASSERT(em != NULL);
281
282 if (child_tidptr != NULL)
283 em->child_tidptr = child_tidptr;
284
285 /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
286 if (em->clone_flags & LINUX_CLONE_CHILD_CLEARTID)
287 em->clear_tid = em->child_tidptr;
288
289 if (em->clone_flags & LINUX_CLONE_CHILD_SETTID)
290 p->p_userret = linux_proc_userret;
291
292 return;
293 }
294
295 int
296 sys_linux_set_tid_address(struct linux_set_tid_address_args *args)
297 {
298 struct linux_emuldata *em;
299
300 EMUL_LOCK();
301
302 em = emuldata_get(curproc);
303 KKASSERT(em != NULL);
304
305 em->clear_tid = args->tidptr;
306 args->sysmsg_iresult = curproc->p_pid;
307
308 EMUL_UNLOCK();
309 return 0;
310 }
Cache object: c04ddfc4ec3a17b11e990df8ab8517c4
|