xref: /f-stack/freebsd/amd64/linux/linux_machdep.c (revision a9643ea8)
1*a9643ea8Slogwang /*-
2*a9643ea8Slogwang  * Copyright (c) 2013 Dmitry Chagin
3*a9643ea8Slogwang  * Copyright (c) 2004 Tim J. Robbins
4*a9643ea8Slogwang  * Copyright (c) 2002 Doug Rabson
5*a9643ea8Slogwang  * Copyright (c) 2000 Marcel Moolenaar
6*a9643ea8Slogwang  * All rights reserved.
7*a9643ea8Slogwang  *
8*a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
9*a9643ea8Slogwang  * modification, are permitted provided that the following conditions
10*a9643ea8Slogwang  * are met:
11*a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
12*a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer
13*a9643ea8Slogwang  *    in this position and unchanged.
14*a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
15*a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
16*a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
17*a9643ea8Slogwang  * 3. The name of the author may not be used to endorse or promote products
18*a9643ea8Slogwang  *    derived from this software without specific prior written permission.
19*a9643ea8Slogwang  *
20*a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21*a9643ea8Slogwang  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22*a9643ea8Slogwang  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23*a9643ea8Slogwang  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24*a9643ea8Slogwang  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25*a9643ea8Slogwang  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*a9643ea8Slogwang  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*a9643ea8Slogwang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*a9643ea8Slogwang  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29*a9643ea8Slogwang  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*a9643ea8Slogwang  */
31*a9643ea8Slogwang 
32*a9643ea8Slogwang #include <sys/cdefs.h>
33*a9643ea8Slogwang __FBSDID("$FreeBSD$");
34*a9643ea8Slogwang 
35*a9643ea8Slogwang #include <sys/param.h>
36*a9643ea8Slogwang #include <sys/kernel.h>
37*a9643ea8Slogwang #include <sys/systm.h>
38*a9643ea8Slogwang #include <sys/capability.h>
39*a9643ea8Slogwang #include <sys/dirent.h>
40*a9643ea8Slogwang #include <sys/file.h>
41*a9643ea8Slogwang #include <sys/fcntl.h>
42*a9643ea8Slogwang #include <sys/filedesc.h>
43*a9643ea8Slogwang #include <sys/clock.h>
44*a9643ea8Slogwang #include <sys/imgact.h>
45*a9643ea8Slogwang #include <sys/ktr.h>
46*a9643ea8Slogwang #include <sys/limits.h>
47*a9643ea8Slogwang #include <sys/lock.h>
48*a9643ea8Slogwang #include <sys/malloc.h>
49*a9643ea8Slogwang #include <sys/mman.h>
50*a9643ea8Slogwang #include <sys/mutex.h>
51*a9643ea8Slogwang #include <sys/priv.h>
52*a9643ea8Slogwang #include <sys/proc.h>
53*a9643ea8Slogwang #include <sys/resource.h>
54*a9643ea8Slogwang #include <sys/resourcevar.h>
55*a9643ea8Slogwang #include <sys/sched.h>
56*a9643ea8Slogwang #include <sys/syscallsubr.h>
57*a9643ea8Slogwang #include <sys/sysproto.h>
58*a9643ea8Slogwang #include <sys/vnode.h>
59*a9643ea8Slogwang #include <sys/unistd.h>
60*a9643ea8Slogwang #include <sys/wait.h>
61*a9643ea8Slogwang 
62*a9643ea8Slogwang #include <security/mac/mac_framework.h>
63*a9643ea8Slogwang 
64*a9643ea8Slogwang #include <ufs/ufs/extattr.h>
65*a9643ea8Slogwang #include <ufs/ufs/quota.h>
66*a9643ea8Slogwang #include <ufs/ufs/ufsmount.h>
67*a9643ea8Slogwang 
68*a9643ea8Slogwang #include <machine/frame.h>
69*a9643ea8Slogwang #include <machine/md_var.h>
70*a9643ea8Slogwang #include <machine/pcb.h>
71*a9643ea8Slogwang #include <machine/psl.h>
72*a9643ea8Slogwang #include <machine/segments.h>
73*a9643ea8Slogwang #include <machine/specialreg.h>
74*a9643ea8Slogwang 
75*a9643ea8Slogwang #include <vm/vm.h>
76*a9643ea8Slogwang #include <vm/pmap.h>
77*a9643ea8Slogwang #include <vm/vm_extern.h>
78*a9643ea8Slogwang #include <vm/vm_kern.h>
79*a9643ea8Slogwang #include <vm/vm_map.h>
80*a9643ea8Slogwang 
81*a9643ea8Slogwang #include <amd64/linux/linux.h>
82*a9643ea8Slogwang #include <amd64/linux/linux_proto.h>
83*a9643ea8Slogwang #include <compat/linux/linux_ipc.h>
84*a9643ea8Slogwang #include <compat/linux/linux_file.h>
85*a9643ea8Slogwang #include <compat/linux/linux_misc.h>
86*a9643ea8Slogwang #include <compat/linux/linux_mmap.h>
87*a9643ea8Slogwang #include <compat/linux/linux_signal.h>
88*a9643ea8Slogwang #include <compat/linux/linux_util.h>
89*a9643ea8Slogwang #include <compat/linux/linux_emul.h>
90*a9643ea8Slogwang 
91*a9643ea8Slogwang 
92*a9643ea8Slogwang int
93*a9643ea8Slogwang linux_execve(struct thread *td, struct linux_execve_args *args)
94*a9643ea8Slogwang {
95*a9643ea8Slogwang 	struct image_args eargs;
96*a9643ea8Slogwang 	char *path;
97*a9643ea8Slogwang 	int error;
98*a9643ea8Slogwang 
99*a9643ea8Slogwang 	LCONVPATHEXIST(td, args->path, &path);
100*a9643ea8Slogwang 
101*a9643ea8Slogwang 	LINUX_CTR(execve);
102*a9643ea8Slogwang 
103*a9643ea8Slogwang 	error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, args->argp,
104*a9643ea8Slogwang 	    args->envp);
105*a9643ea8Slogwang 	free(path, M_TEMP);
106*a9643ea8Slogwang 	if (error == 0)
107*a9643ea8Slogwang 		error = linux_common_execve(td, &eargs);
108*a9643ea8Slogwang 	return (error);
109*a9643ea8Slogwang }
110*a9643ea8Slogwang 
111*a9643ea8Slogwang int
112*a9643ea8Slogwang linux_set_upcall_kse(struct thread *td, register_t stack)
113*a9643ea8Slogwang {
114*a9643ea8Slogwang 
115*a9643ea8Slogwang 	if (stack)
116*a9643ea8Slogwang 		td->td_frame->tf_rsp = stack;
117*a9643ea8Slogwang 
118*a9643ea8Slogwang 	/*
119*a9643ea8Slogwang 	 * The newly created Linux thread returns
120*a9643ea8Slogwang 	 * to the user space by the same path that a parent do.
121*a9643ea8Slogwang 	 */
122*a9643ea8Slogwang 	td->td_frame->tf_rax = 0;
123*a9643ea8Slogwang 	return (0);
124*a9643ea8Slogwang }
125*a9643ea8Slogwang 
126*a9643ea8Slogwang int
127*a9643ea8Slogwang linux_mmap2(struct thread *td, struct linux_mmap2_args *args)
128*a9643ea8Slogwang {
129*a9643ea8Slogwang 
130*a9643ea8Slogwang 	return (linux_mmap_common(td, PTROUT(args->addr), args->len, args->prot,
131*a9643ea8Slogwang 		args->flags, args->fd, args->pgoff));
132*a9643ea8Slogwang }
133*a9643ea8Slogwang 
134*a9643ea8Slogwang int
135*a9643ea8Slogwang linux_mprotect(struct thread *td, struct linux_mprotect_args *uap)
136*a9643ea8Slogwang {
137*a9643ea8Slogwang 
138*a9643ea8Slogwang 	return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len, uap->prot));
139*a9643ea8Slogwang }
140*a9643ea8Slogwang 
141*a9643ea8Slogwang int
142*a9643ea8Slogwang linux_iopl(struct thread *td, struct linux_iopl_args *args)
143*a9643ea8Slogwang {
144*a9643ea8Slogwang 	int error;
145*a9643ea8Slogwang 
146*a9643ea8Slogwang 	LINUX_CTR(iopl);
147*a9643ea8Slogwang 
148*a9643ea8Slogwang 	if (args->level > 3)
149*a9643ea8Slogwang 		return (EINVAL);
150*a9643ea8Slogwang 	if ((error = priv_check(td, PRIV_IO)) != 0)
151*a9643ea8Slogwang 		return (error);
152*a9643ea8Slogwang 	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
153*a9643ea8Slogwang 		return (error);
154*a9643ea8Slogwang 	td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) |
155*a9643ea8Slogwang 	    (args->level * (PSL_IOPL / 3));
156*a9643ea8Slogwang 
157*a9643ea8Slogwang 	return (0);
158*a9643ea8Slogwang }
159*a9643ea8Slogwang 
160*a9643ea8Slogwang int
161*a9643ea8Slogwang linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap)
162*a9643ea8Slogwang {
163*a9643ea8Slogwang 	l_sigset_t lmask;
164*a9643ea8Slogwang 	sigset_t sigmask;
165*a9643ea8Slogwang 	int error;
166*a9643ea8Slogwang 
167*a9643ea8Slogwang 	LINUX_CTR2(rt_sigsuspend, "%p, %ld",
168*a9643ea8Slogwang 	    uap->newset, uap->sigsetsize);
169*a9643ea8Slogwang 
170*a9643ea8Slogwang 	if (uap->sigsetsize != sizeof(l_sigset_t))
171*a9643ea8Slogwang 		return (EINVAL);
172*a9643ea8Slogwang 
173*a9643ea8Slogwang 	error = copyin(uap->newset, &lmask, sizeof(l_sigset_t));
174*a9643ea8Slogwang 	if (error)
175*a9643ea8Slogwang 		return (error);
176*a9643ea8Slogwang 
177*a9643ea8Slogwang 	linux_to_bsd_sigset(&lmask, &sigmask);
178*a9643ea8Slogwang 	return (kern_sigsuspend(td, sigmask));
179*a9643ea8Slogwang }
180*a9643ea8Slogwang 
181*a9643ea8Slogwang int
182*a9643ea8Slogwang linux_pause(struct thread *td, struct linux_pause_args *args)
183*a9643ea8Slogwang {
184*a9643ea8Slogwang 	struct proc *p = td->td_proc;
185*a9643ea8Slogwang 	sigset_t sigmask;
186*a9643ea8Slogwang 
187*a9643ea8Slogwang 	LINUX_CTR(pause);
188*a9643ea8Slogwang 
189*a9643ea8Slogwang 	PROC_LOCK(p);
190*a9643ea8Slogwang 	sigmask = td->td_sigmask;
191*a9643ea8Slogwang 	PROC_UNLOCK(p);
192*a9643ea8Slogwang 	return (kern_sigsuspend(td, sigmask));
193*a9643ea8Slogwang }
194*a9643ea8Slogwang 
195*a9643ea8Slogwang int
196*a9643ea8Slogwang linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
197*a9643ea8Slogwang {
198*a9643ea8Slogwang 	stack_t ss, oss;
199*a9643ea8Slogwang 	l_stack_t lss;
200*a9643ea8Slogwang 	int error;
201*a9643ea8Slogwang 
202*a9643ea8Slogwang 	LINUX_CTR2(sigaltstack, "%p, %p", uap->uss, uap->uoss);
203*a9643ea8Slogwang 
204*a9643ea8Slogwang 	if (uap->uss != NULL) {
205*a9643ea8Slogwang 		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
206*a9643ea8Slogwang 		if (error)
207*a9643ea8Slogwang 			return (error);
208*a9643ea8Slogwang 
209*a9643ea8Slogwang 		ss.ss_sp = PTRIN(lss.ss_sp);
210*a9643ea8Slogwang 		ss.ss_size = lss.ss_size;
211*a9643ea8Slogwang 		ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
212*a9643ea8Slogwang 	}
213*a9643ea8Slogwang 	error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL,
214*a9643ea8Slogwang 	    (uap->uoss != NULL) ? &oss : NULL);
215*a9643ea8Slogwang 	if (!error && uap->uoss != NULL) {
216*a9643ea8Slogwang 		lss.ss_sp = PTROUT(oss.ss_sp);
217*a9643ea8Slogwang 		lss.ss_size = oss.ss_size;
218*a9643ea8Slogwang 		lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags);
219*a9643ea8Slogwang 		error = copyout(&lss, uap->uoss, sizeof(l_stack_t));
220*a9643ea8Slogwang 	}
221*a9643ea8Slogwang 
222*a9643ea8Slogwang 	return (error);
223*a9643ea8Slogwang }
224*a9643ea8Slogwang 
225*a9643ea8Slogwang int
226*a9643ea8Slogwang linux_arch_prctl(struct thread *td, struct linux_arch_prctl_args *args)
227*a9643ea8Slogwang {
228*a9643ea8Slogwang 	int error;
229*a9643ea8Slogwang 	struct pcb *pcb;
230*a9643ea8Slogwang 
231*a9643ea8Slogwang 	LINUX_CTR2(arch_prctl, "0x%x, %p", args->code, args->addr);
232*a9643ea8Slogwang 
233*a9643ea8Slogwang 	error = ENOTSUP;
234*a9643ea8Slogwang 	pcb = td->td_pcb;
235*a9643ea8Slogwang 
236*a9643ea8Slogwang 	switch (args->code) {
237*a9643ea8Slogwang 	case LINUX_ARCH_GET_GS:
238*a9643ea8Slogwang 		error = copyout(&pcb->pcb_gsbase, (unsigned long *)args->addr,
239*a9643ea8Slogwang 		    sizeof(args->addr));
240*a9643ea8Slogwang 		break;
241*a9643ea8Slogwang 	case LINUX_ARCH_SET_GS:
242*a9643ea8Slogwang 		if (args->addr >= VM_MAXUSER_ADDRESS)
243*a9643ea8Slogwang 			return(EPERM);
244*a9643ea8Slogwang 		break;
245*a9643ea8Slogwang 	case LINUX_ARCH_GET_FS:
246*a9643ea8Slogwang 		error = copyout(&pcb->pcb_fsbase, (unsigned long *)args->addr,
247*a9643ea8Slogwang 		    sizeof(args->addr));
248*a9643ea8Slogwang 		break;
249*a9643ea8Slogwang 	case LINUX_ARCH_SET_FS:
250*a9643ea8Slogwang 		error = linux_set_cloned_tls(td, (void *)args->addr);
251*a9643ea8Slogwang 		break;
252*a9643ea8Slogwang 	default:
253*a9643ea8Slogwang 		error = EINVAL;
254*a9643ea8Slogwang 	}
255*a9643ea8Slogwang 	return (error);
256*a9643ea8Slogwang }
257*a9643ea8Slogwang 
258*a9643ea8Slogwang int
259*a9643ea8Slogwang linux_set_cloned_tls(struct thread *td, void *desc)
260*a9643ea8Slogwang {
261*a9643ea8Slogwang 	struct pcb *pcb;
262*a9643ea8Slogwang 
263*a9643ea8Slogwang 	if ((uint64_t)desc >= VM_MAXUSER_ADDRESS)
264*a9643ea8Slogwang 		return (EPERM);
265*a9643ea8Slogwang 
266*a9643ea8Slogwang 	pcb = td->td_pcb;
267*a9643ea8Slogwang 	pcb->pcb_fsbase = (register_t)desc;
268*a9643ea8Slogwang 	td->td_frame->tf_fs = _ufssel;
269*a9643ea8Slogwang 
270*a9643ea8Slogwang 	return (0);
271*a9643ea8Slogwang }
272