1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
25 * Copyright 2015, Joyent, Inc.
26 */
27
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/fpu/fpusystm.h>
32 #include <sys/sysmacros.h>
33 #include <sys/signal.h>
34 #include <sys/cred.h>
35 #include <sys/user.h>
36 #include <sys/errno.h>
37 #include <sys/vnode.h>
38 #include <sys/mman.h>
39 #include <sys/kmem.h>
40 #include <sys/proc.h>
41 #include <sys/pathname.h>
42 #include <sys/cmn_err.h>
43 #include <sys/debug.h>
44 #include <sys/exec.h>
45 #include <sys/exechdr.h>
46 #include <sys/auxv.h>
47 #include <sys/core.h>
48 #include <sys/vmparam.h>
49 #include <sys/archsystm.h>
50 #include <sys/fs/swapnode.h>
51 #include <sys/modctl.h>
52 #include <vm/anon.h>
53 #include <vm/as.h>
54 #include <vm/seg.h>
55
56 static int aoutexec(vnode_t *vp, execa_t *uap, uarg_t *args,
57 intpdata_t *idatap, int level, long *execsz, int setid,
58 caddr_t exec_file, cred_t *cred, int *brand_action);
59 static int get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz,
60 int *isdyn);
61 static int aoutcore(vnode_t *vp, proc_t *pp, cred_t *credp,
62 rlim64_t rlimit, int sig, core_content_t content);
63 extern int elf32exec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
64 long *, int, caddr_t, cred_t *, int);
65 extern int elf32core(vnode_t *, proc_t *, cred_t *, rlim64_t, int,
66 core_content_t);
67
68 static struct execsw nesw = {
69 aout_nmagicstr,
70 2,
71 2,
72 aoutexec,
73 aoutcore
74 };
75
76 static struct execsw zesw = {
77 aout_zmagicstr,
78 2,
79 2,
80 aoutexec,
81 aoutcore
82 };
83
84 static struct execsw oesw = {
85 aout_omagicstr,
86 2,
87 2,
88 aoutexec,
89 aoutcore
90 };
91
92 /*
93 * Module linkage information for the kernel.
94 */
95 static struct modlexec nexec = {
96 &mod_execops, "exec for NMAGIC", &nesw
97 };
98
99 static struct modlexec zexec = {
100 &mod_execops, "exec for ZMAGIC", &zesw
101 };
102
103 static struct modlexec oexec = {
104 &mod_execops, "exec for OMAGIC", &oesw
105 };
106
107 static struct modlinkage modlinkage = {
108 MODREV_1, &nexec, &zexec, &oexec, NULL
109 };
110
111 int
112 _init(void)
113 {
114 return (mod_install(&modlinkage));
115 }
116
117 int
118 _fini(void)
119 {
120 return (mod_remove(&modlinkage));
121 }
122
123 int
124 _info(struct modinfo *modinfop)
125 {
126 return (mod_info(&modlinkage, modinfop));
127 }
128
129
130 /*ARGSUSED*/
131 static int
132 aoutexec(vnode_t *vp, struct execa *uap, struct uarg *args,
133 struct intpdata *idatap, int level, long *execsz, int setid,
134 caddr_t exec_file, cred_t *cred, int *brand_action)
135 {
136 auxv32_t auxflags_auxv32;
137 int error;
138 struct exdata edp, edpout;
139 struct execenv exenv;
140 proc_t *pp = ttoproc(curthread);
141 struct vnode *nvp;
142 int pagetext, pagedata;
143 int dataprot = PROT_ALL;
144 int textprot = PROT_ALL & ~PROT_WRITE;
145 int isdyn;
146
147
148 args->to_model = DATAMODEL_ILP32;
149 *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1);
150
151 /*
152 * Read in and validate the file header.
153 */
154 if (error = get_aout_head(&vp, &edp, execsz, &isdyn))
155 return (error);
156
157 if (error = chkaout(&edp))
158 return (error);
159
160 /*
161 * Take a quick look to see if it looks like we will have
162 * enough swap space for the program to get started. This
163 * is not a guarantee that we will succeed, but it is definitely
164 * better than finding this out after we are committed to the
165 * new memory image. Maybe what is needed is a way to "prereserve"
166 * swap space for some segment mappings here.
167 *
168 * But with shared libraries the process can make it through
169 * the exec only to have ld.so fail to get the program going
170 * because its mmap's will not be able to succeed if the system
171 * is running low on swap space. In fact this is a far more
172 * common failure mode, but we cannot do much about this here
173 * other than add some slop to our anonymous memory resources
174 * requirements estimate based on some guess since we cannot know
175 * what else the program will really need to get to a useful state.
176 *
177 * XXX - The stack size (clrnd(SSIZE + btopr(nargc))) should also
178 * be used when checking for swap space. This requires some work
179 * since nargc is actually determined in exec_args() which is done
180 * after this check and hence we punt for now.
181 *
182 * nargc = SA(nc + (na + 4) * NBPW) + sizeof (struct rwindow);
183 */
184 if (CURRENT_TOTAL_AVAILABLE_SWAP < btopr(edp.ux_dsize) + btopr(SSIZE))
185 return (ENOMEM);
186
187 /*
188 * Load the trap 0 interpreter.
189 */
190 if (error = lookupname("/usr/4lib/sbcp", UIO_SYSSPACE, FOLLOW,
191 NULLVPP, &nvp)) {
192 goto done;
193 }
194 if (error = elf32exec(nvp, uap, args, idatap, level, execsz,
195 setid, exec_file, cred, brand_action)) {
196 VN_RELE(nvp);
197 return (error);
198 }
199 VN_RELE(nvp);
200
201 /*
202 * Determine the a.out's characteristics.
203 */
204 getexinfo(&edp, &edpout, &pagetext, &pagedata);
205
206 /*
207 * Load the a.out's text and data.
208 */
209 if (error = execmap(edp.vp, edp.ux_txtorg, edp.ux_tsize,
210 (size_t)0, edp.ux_toffset, textprot, pagetext, 0))
211 goto done;
212 if (error = execmap(edp.vp, edp.ux_datorg, edp.ux_dsize,
213 edp.ux_bsize, edp.ux_doffset, dataprot, pagedata, 0))
214 goto done;
215
216 exenv.ex_bssbase = (caddr_t)edp.ux_datorg;
217 exenv.ex_brkbase = (caddr_t)edp.ux_datorg;
218 exenv.ex_brksize = edp.ux_dsize + edp.ux_bsize;
219 exenv.ex_magic = edp.ux_mag;
220 exenv.ex_vp = edp.vp;
221 setexecenv(&exenv);
222
223 /*
224 * It's time to manipulate the process aux vectors.
225 * We need to update the AT_SUN_AUXFLAGS aux vector to set
226 * the AF_SUN_NOPLM flag.
227 */
228 if (copyin(args->auxp_auxflags, &auxflags_auxv32,
229 sizeof (auxflags_auxv32)) != 0)
230 return (EFAULT);
231
232 ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS);
233 auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM;
234 if (copyout(&auxflags_auxv32, args->auxp_auxflags,
235 sizeof (auxflags_auxv32)) != 0)
236 return (EFAULT);
237
238 done:
239 if (error != 0)
240 psignal(pp, SIGKILL);
241 else {
242 /*
243 * Ensure that the max fds do not exceed 256 (this is
244 * applicable to 4.x binaries, which is why we only
245 * do it on a.out files).
246 */
247 struct rlimit64 fdno_rlim;
248 rctl_alloc_gp_t *gp = rctl_rlimit_set_prealloc(1);
249
250 mutex_enter(&curproc->p_lock);
251 (void) rctl_rlimit_get(rctlproc_legacy[RLIMIT_NOFILE], curproc,
252 &fdno_rlim);
253 if (fdno_rlim.rlim_cur > 256) {
254 fdno_rlim.rlim_cur = fdno_rlim.rlim_max = 256;
255 (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE],
256 curproc, &fdno_rlim, gp,
257 rctlproc_flags[RLIMIT_NOFILE],
258 rctlproc_signals[RLIMIT_NOFILE], CRED());
259 } else if (fdno_rlim.rlim_max > 256) {
260 fdno_rlim.rlim_max = 256;
261 (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE],
262 curproc, &fdno_rlim, gp,
263 rctlproc_flags[RLIMIT_NOFILE],
264 rctlproc_signals[RLIMIT_NOFILE], CRED());
265 }
266 mutex_exit(&curproc->p_lock);
267
268 rctl_prealloc_destroy(gp);
269 }
270
271 return (error);
272 }
273
274 /*
275 * Read in and validate the file header.
276 */
277 static int
278 get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz, int *isdyn)
279 {
280 struct vnode *vp = *vpp;
281 struct exec filhdr;
282 int error;
283 ssize_t resid;
284 rlim64_t limit;
285 rlim64_t roundlimit;
286
287 if (error = vn_rdwr(UIO_READ, vp, (caddr_t)&filhdr,
288 (ssize_t)sizeof (filhdr), (offset_t)0, UIO_SYSSPACE, 0,
289 (rlim64_t)0, CRED(), &resid))
290 return (error);
291
292 if (resid != 0)
293 return (ENOEXEC);
294
295 switch (filhdr.a_magic) {
296 case OMAGIC:
297 filhdr.a_data += filhdr.a_text;
298 filhdr.a_text = 0;
299 break;
300 case ZMAGIC:
301 case NMAGIC:
302 break;
303 default:
304 return (ENOEXEC);
305 }
306
307 /*
308 * Check total memory requirements (in pages) for a new process
309 * against the available memory or upper limit of memory allowed.
310 *
311 * For the 64-bit kernel, the limit can be set large enough so that
312 * rounding it up to a page can overflow, so we check for btopr()
313 * overflowing here by comparing it with the unrounded limit in pages.
314 */
315 *execsz += btopr(filhdr.a_text + filhdr.a_data);
316 limit = btop(curproc->p_vmem_ctl);
317 roundlimit = btopr(curproc->p_vmem_ctl);
318 if ((roundlimit > limit && *execsz > roundlimit) ||
319 (roundlimit < limit && *execsz > limit)) {
320 mutex_enter(&curproc->p_lock);
321 (void) rctl_action(rctlproc_legacy[RLIMIT_VMEM],
322 curproc->p_rctls, curproc, RCA_SAFE);
323 mutex_exit(&curproc->p_lock);
324 return (ENOMEM);
325 }
326
327 edp->ux_mach = filhdr.a_machtype;
328 edp->ux_tsize = filhdr.a_text;
329 edp->ux_dsize = filhdr.a_data;
330 edp->ux_bsize = filhdr.a_bss;
331 edp->ux_mag = filhdr.a_magic;
332 edp->ux_toffset = gettfile(&filhdr);
333 edp->ux_doffset = getdfile(&filhdr);
334 edp->ux_txtorg = gettmem(&filhdr);
335 edp->ux_datorg = getdmem(&filhdr);
336 edp->ux_entloc = (caddr_t)(uintptr_t)filhdr.a_entry;
337 edp->vp = vp;
338 *isdyn = filhdr.a_dynamic;
339
340 return (0);
341 }
342
343 static int
344 aoutcore(vnode_t *vp, proc_t *pp, struct cred *credp, rlim64_t rlimit, int sig,
345 core_content_t content)
346 {
347 return (elf32core(vp, pp, credp, rlimit, sig, content));
348 }