1*eda7c7bbSmaxv /* $NetBSD: linux_uselib.c,v 1.33 2014/11/09 17:48:08 maxv Exp $ */
2798f64c8Sjdolecek
3798f64c8Sjdolecek /*-
4798f64c8Sjdolecek * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5798f64c8Sjdolecek * All rights reserved.
6798f64c8Sjdolecek *
7798f64c8Sjdolecek * This code is derived from software contributed to The NetBSD Foundation
8798f64c8Sjdolecek * by Christos Zoulas, Frank van der Linden and Eric Haszlakiewicz.
9798f64c8Sjdolecek *
10798f64c8Sjdolecek * Redistribution and use in source and binary forms, with or without
11798f64c8Sjdolecek * modification, are permitted provided that the following conditions
12798f64c8Sjdolecek * are met:
13798f64c8Sjdolecek * 1. Redistributions of source code must retain the above copyright
14798f64c8Sjdolecek * notice, this list of conditions and the following disclaimer.
15798f64c8Sjdolecek * 2. Redistributions in binary form must reproduce the above copyright
16798f64c8Sjdolecek * notice, this list of conditions and the following disclaimer in the
17798f64c8Sjdolecek * documentation and/or other materials provided with the distribution.
18798f64c8Sjdolecek *
19798f64c8Sjdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20798f64c8Sjdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21798f64c8Sjdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22798f64c8Sjdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23798f64c8Sjdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24798f64c8Sjdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25798f64c8Sjdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26798f64c8Sjdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27798f64c8Sjdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28798f64c8Sjdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29798f64c8Sjdolecek * POSSIBILITY OF SUCH DAMAGE.
30798f64c8Sjdolecek */
31798f64c8Sjdolecek
32dab6ef8bSlukem #include <sys/cdefs.h>
33*eda7c7bbSmaxv __KERNEL_RCSID(0, "$NetBSD: linux_uselib.c,v 1.33 2014/11/09 17:48:08 maxv Exp $");
34dab6ef8bSlukem
35798f64c8Sjdolecek #include <sys/param.h>
36798f64c8Sjdolecek #include <sys/systm.h>
37798f64c8Sjdolecek #include <sys/kernel.h>
38798f64c8Sjdolecek #include <sys/proc.h>
39798f64c8Sjdolecek #include <sys/namei.h>
40798f64c8Sjdolecek #include <sys/vnode.h>
41798f64c8Sjdolecek #include <sys/mount.h>
42798f64c8Sjdolecek #include <sys/exec.h>
43dbb9a414Sdholland #include <sys/exec_aout.h>
44798f64c8Sjdolecek
45798f64c8Sjdolecek #include <sys/mman.h>
46798f64c8Sjdolecek #include <sys/syscallargs.h>
47798f64c8Sjdolecek
48a2a38285Sad #include <sys/cpu.h>
49798f64c8Sjdolecek #include <machine/reg.h>
50798f64c8Sjdolecek
51798f64c8Sjdolecek #include <compat/linux/common/linux_types.h>
52798f64c8Sjdolecek #include <compat/linux/common/linux_signal.h>
53798f64c8Sjdolecek #include <compat/linux/common/linux_util.h>
54798f64c8Sjdolecek #include <compat/linux/common/linux_exec.h>
55798f64c8Sjdolecek #include <compat/linux/common/linux_machdep.h>
56a478f23bSnjoly #include <compat/linux/common/linux_ipc.h>
57a478f23bSnjoly #include <compat/linux/common/linux_sem.h>
58798f64c8Sjdolecek
59dbb9a414Sdholland #ifndef EXEC_AOUT
60dbb9a414Sdholland /* define EXEC_AOUT to get prototype from linux_syscall.h */
61dbb9a414Sdholland #define EXEC_AOUT
62dbb9a414Sdholland #endif
63dbb9a414Sdholland
64798f64c8Sjdolecek #include <compat/linux/linux_syscallargs.h>
65798f64c8Sjdolecek #include <compat/linux/linux_syscall.h>
66798f64c8Sjdolecek
67798f64c8Sjdolecek /*
68798f64c8Sjdolecek * The Linux system call to load shared libraries, a.out version. The
69798f64c8Sjdolecek * a.out shared libs are just files that are mapped onto a fixed
70798f64c8Sjdolecek * address in the process' address space. The address is given in
71798f64c8Sjdolecek * a_entry. Read in the header, set up some VM commands and run them.
72798f64c8Sjdolecek *
73798f64c8Sjdolecek * Yes, both text and data are mapped at once, so we're left with
741035faffSwiz * writable text for the shared libs. The Linux crt0 seemed to break
75a9356936Swiz * sometimes when data was mapped separately. It munmapped a uselib()
76798f64c8Sjdolecek * of ld.so by hand, which failed with shared text and data for ld.so
77798f64c8Sjdolecek * Yuck.
78798f64c8Sjdolecek *
79798f64c8Sjdolecek * Because of the problem with ZMAGIC executables (text starts
80798f64c8Sjdolecek * at 0x400 in the file, but needs to be mapped at 0), ZMAGIC
81798f64c8Sjdolecek * shared libs are not handled very efficiently :-(
82798f64c8Sjdolecek */
83798f64c8Sjdolecek
84798f64c8Sjdolecek int
linux_sys_uselib(struct lwp * l,const struct linux_sys_uselib_args * uap,register_t * retval)857e2790cfSdsl linux_sys_uselib(struct lwp *l, const struct linux_sys_uselib_args *uap, register_t *retval)
86798f64c8Sjdolecek {
877e2790cfSdsl /* {
88798f64c8Sjdolecek syscallarg(const char *) path;
897e2790cfSdsl } */
90798f64c8Sjdolecek long bsize, dsize, tsize, taddr, baddr, daddr;
91798f64c8Sjdolecek struct vnode *vp;
92798f64c8Sjdolecek struct exec hdr;
93798f64c8Sjdolecek struct exec_vmcmd_set vcset;
94798f64c8Sjdolecek int i, magic, error;
95798f64c8Sjdolecek size_t rem;
96798f64c8Sjdolecek
97effcf1afSdholland error = namei_simple_user(SCARG(uap, path),
98effcf1afSdholland NSM_FOLLOW_TRYEMULROOT, &vp);
99effcf1afSdholland if (error != 0)
100798f64c8Sjdolecek return error;
101798f64c8Sjdolecek
1027eb4355dSmaxv if (vp->v_type != VREG) {
1037eb4355dSmaxv error = EINVAL;
1047eb4355dSmaxv goto out;
1057eb4355dSmaxv }
1067eb4355dSmaxv
10753524e44Schristos if ((error = vn_rdwr(UIO_READ, vp, (void *) &hdr, LINUX_AOUT_HDR_SIZE,
108f474dcebSad 0, UIO_SYSSPACE, IO_NODELOCKED, l->l_cred,
109f7155e40Sskrll &rem, NULL))) {
1104202f47dSmaxv goto out;
111798f64c8Sjdolecek }
112798f64c8Sjdolecek
113798f64c8Sjdolecek if (rem != 0) {
1144202f47dSmaxv error = ENOEXEC;
1154202f47dSmaxv goto out;
116798f64c8Sjdolecek }
117798f64c8Sjdolecek
1184202f47dSmaxv if (LINUX_N_MACHTYPE(&hdr) != LINUX_MID_MACHINE) {
1194202f47dSmaxv error = ENOEXEC;
1204202f47dSmaxv goto out;
1214202f47dSmaxv }
122798f64c8Sjdolecek
123798f64c8Sjdolecek magic = LINUX_N_MAGIC(&hdr);
124d071d9a8Sthorpej taddr = hdr.a_entry & (~(PAGE_SIZE - 1));
125798f64c8Sjdolecek tsize = hdr.a_text;
126798f64c8Sjdolecek daddr = taddr + tsize;
127798f64c8Sjdolecek dsize = hdr.a_data + hdr.a_bss;
128798f64c8Sjdolecek
129993948e9Schs error = vn_marktext(vp);
130993948e9Schs if (error)
1314202f47dSmaxv goto out;
132798f64c8Sjdolecek
133798f64c8Sjdolecek vcset.evs_cnt = 0;
134798f64c8Sjdolecek vcset.evs_used = 0;
135798f64c8Sjdolecek
136798f64c8Sjdolecek NEW_VMCMD(&vcset,
137798f64c8Sjdolecek magic == ZMAGIC ? vmcmd_map_readvn : vmcmd_map_pagedvn,
138798f64c8Sjdolecek hdr.a_text + hdr.a_data, taddr,
139798f64c8Sjdolecek vp, LINUX_N_TXTOFF(hdr, magic),
140798f64c8Sjdolecek VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE);
141798f64c8Sjdolecek
142d071d9a8Sthorpej baddr = roundup(daddr + hdr.a_data, PAGE_SIZE);
143798f64c8Sjdolecek bsize = daddr + dsize - baddr;
144798f64c8Sjdolecek if (bsize > 0) {
145798f64c8Sjdolecek NEW_VMCMD(&vcset, vmcmd_map_zero, bsize, baddr,
146798f64c8Sjdolecek NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
147798f64c8Sjdolecek }
148798f64c8Sjdolecek
149798f64c8Sjdolecek for (i = 0; i < vcset.evs_used && !error; i++) {
150798f64c8Sjdolecek struct exec_vmcmd *vcp;
151798f64c8Sjdolecek
152798f64c8Sjdolecek vcp = &vcset.evs_cmds[i];
15395e1ffb1Schristos error = (*vcp->ev_proc)(l, vcp);
154798f64c8Sjdolecek }
155798f64c8Sjdolecek
156798f64c8Sjdolecek kill_vmcmds(&vcset);
157798f64c8Sjdolecek
1584202f47dSmaxv out:
159798f64c8Sjdolecek vrele(vp);
160798f64c8Sjdolecek return error;
161798f64c8Sjdolecek }
162