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  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/errno.h>
29 #include <sys/exec.h>
30 #include <sys/kmem.h>
31 #include <sys/modctl.h>
32 #include <sys/model.h>
33 #include <sys/proc.h>
34 #include <sys/syscall.h>
35 #include <sys/systm.h>
36 #include <sys/thread.h>
37 #include <sys/cmn_err.h>
38 #include <sys/archsystm.h>
39 
40 #include <sys/machbrand.h>
41 #include <sys/brand.h>
42 #include "sn1_brand.h"
43 
44 char *sn1_emulation_table = NULL;
45 
46 void	sn1_init_brand_data(zone_t *);
47 void	sn1_free_brand_data(zone_t *);
48 void	sn1_setbrand(proc_t *);
49 int	sn1_getattr(zone_t *, int, void *, size_t *);
50 int	sn1_setattr(zone_t *, int, void *, size_t);
51 int	sn1_brandsys(int, int64_t *, uintptr_t, uintptr_t, uintptr_t,
52 		uintptr_t, uintptr_t, uintptr_t);
53 void	sn1_copy_procdata(proc_t *, proc_t *);
54 void	sn1_proc_exit(struct proc *, klwp_t *);
55 void	sn1_exec();
56 int	sn1_initlwp(klwp_t *);
57 void	sn1_forklwp(klwp_t *, klwp_t *);
58 void	sn1_freelwp(klwp_t *);
59 void	sn1_lwpexit(klwp_t *);
60 int	sn1_elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
61 	long *, int, caddr_t, cred_t *, int);
62 
63 /* sn1 brand */
64 struct brand_ops sn1_brops = {
65 	sn1_init_brand_data,
66 	sn1_free_brand_data,
67 	sn1_brandsys,
68 	sn1_setbrand,
69 	sn1_getattr,
70 	sn1_setattr,
71 	sn1_copy_procdata,
72 	sn1_proc_exit,
73 	sn1_exec,
74 	lwp_setrval,
75 	sn1_initlwp,
76 	sn1_forklwp,
77 	sn1_freelwp,
78 	sn1_lwpexit,
79 	sn1_elfexec
80 };
81 
82 #ifdef	sparc
83 
84 struct brand_mach_ops sn1_mops = {
85 	sn1_brand_syscall_callback,
86 	sn1_brand_syscall_callback
87 };
88 
89 #else	/* sparc */
90 
91 #ifdef	__amd64
92 
93 struct brand_mach_ops sn1_mops = {
94 	sn1_brand_sysenter_callback,
95 	NULL,
96 	sn1_brand_int91_callback,
97 	sn1_brand_syscall_callback,
98 	sn1_brand_syscall32_callback,
99 	NULL
100 };
101 
102 #else	/* ! __amd64 */
103 
104 struct brand_mach_ops sn1_mops = {
105 	sn1_brand_sysenter_callback,
106 	NULL,
107 	NULL,
108 	sn1_brand_syscall_callback,
109 	NULL,
110 	NULL
111 };
112 #endif	/* __amd64 */
113 
114 #endif	/* _sparc */
115 
116 struct brand	sn1_brand = {
117 	BRAND_VER_1,
118 	"sn1",
119 	&sn1_brops,
120 	&sn1_mops
121 };
122 
123 static struct modlbrand modlbrand = {
124 	&mod_brandops,		/* type of module */
125 	"Solaris N-1 Brand",	/* description of module */
126 	&sn1_brand		/* driver ops */
127 };
128 
129 static struct modlinkage modlinkage = {
130 	MODREV_1, (void *)&modlbrand, NULL
131 };
132 
133 void
134 sn1_setbrand(proc_t *p)
135 {
136 	ASSERT(p->p_brand == &sn1_brand);
137 	ASSERT(p->p_brand_data == NULL);
138 	p->p_brand_data = NULL;
139 
140 	/*
141 	 * We should only be called from exec(), when we know the process
142 	 * is single-threaded.
143 	 */
144 	ASSERT(p->p_tlist == p->p_tlist->t_forw);
145 	(void) sn1_initlwp(p->p_tlist->t_lwp);
146 }
147 
148 /* ARGSUSED */
149 int
150 sn1_getattr(zone_t *zone, int attr, void *buf, size_t *bufsize)
151 {
152 	return (EINVAL);
153 }
154 
155 /* ARGSUSED */
156 int
157 sn1_setattr(zone_t *zone, int attr, void *buf, size_t bufsize)
158 {
159 	return (EINVAL);
160 }
161 
162 /*
163  * Get the address of the user-space system call handler from the user
164  * process and attach it to the proc structure.
165  */
166 /*ARGSUSED*/
167 int
168 sn1_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2,
169     uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6)
170 {
171 	proc_t *p = curproc;
172 	*rval = 0;
173 
174 	/*
175 	 * There is one operation that is suppored for non-branded
176 	 * process.  B_EXEC_BRAND.  This brand operaion is redundant
177 	 * since the kernel assumes a native process doing an exec
178 	 * in a branded zone is going to run a branded processes.
179 	 * hence we don't support this operation.
180 	 */
181 	if (cmd == B_EXEC_BRAND)
182 		return (ENOSYS);
183 
184 	/* For all other operations this must be a branded process. */
185 	if (p->p_brand == &native_brand)
186 		return (ENOSYS);
187 
188 	ASSERT(p->p_brand == &sn1_brand);
189 
190 	if (cmd == B_REGISTER) {
191 		ASSERT(p->p_brand_data == NULL);
192 		p->p_brand_data = (void *)arg1;
193 		return (0);
194 	}
195 
196 	return (EINVAL);
197 }
198 
199 /*
200  * Copy the per-process brand data from a parent proc to a child.  In the
201  * sn1 brand, the only per-process state is the address of the user-space
202  * handler.
203  */
204 void
205 sn1_copy_procdata(proc_t *child, proc_t *parent)
206 {
207 	ASSERT(parent->p_brand == &sn1_brand);
208 	ASSERT(child->p_brand == &sn1_brand);
209 
210 	child->p_brand_data = NULL;
211 }
212 
213 /*ARGSUSED*/
214 void
215 sn1_proc_exit(struct proc *p, klwp_t *l)
216 {
217 	ASSERT(p->p_brand == &sn1_brand);
218 
219 	/*
220 	 * We should only be called from proc_exit(), when we know that
221 	 * process is single-threaded.
222 	 */
223 	ASSERT(p->p_tlist == p->p_tlist->t_forw);
224 
225 	p->p_brand_data = NULL;
226 	l->lwp_brand = NULL;
227 }
228 
229 void
230 sn1_exec()
231 {
232 	ASSERT(curproc->p_brand == &sn1_brand);
233 	ASSERT(ttolwp(curthread)->lwp_brand != NULL);
234 
235 	/*
236 	 * We should only be called from exec(), when we know the process
237 	 * is single-threaded.
238 	 */
239 	ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw);
240 
241 	/* upon exec, reset our user-land handler callback entry point */
242 	curproc->p_brand_data = NULL;
243 }
244 
245 /*ARGSUSED*/
246 int
247 sn1_initlwp(klwp_t *l)
248 {
249 	ASSERT(l->lwp_procp->p_brand == &sn1_brand);
250 	ASSERT(l->lwp_brand == NULL);
251 	l->lwp_brand = (void *)-1;
252 	return (0);
253 }
254 
255 /*ARGSUSED*/
256 void
257 sn1_forklwp(klwp_t *p, klwp_t *c)
258 {
259 	ASSERT(p->lwp_procp->p_brand == &sn1_brand);
260 	ASSERT(c->lwp_procp->p_brand == &sn1_brand);
261 
262 	/* Both LWPs have already had been initialized via sn1_initlwp() */
263 	ASSERT(p->lwp_brand != NULL);
264 	ASSERT(c->lwp_brand != NULL);
265 }
266 
267 /*ARGSUSED*/
268 void
269 sn1_freelwp(klwp_t *l)
270 {
271 	/* This lwp died during birth */
272 	ASSERT(l->lwp_procp->p_brand == &sn1_brand);
273 	ASSERT(l->lwp_brand != NULL);
274 	l->lwp_brand = NULL;
275 }
276 
277 /*ARGSUSED*/
278 void
279 sn1_lwpexit(klwp_t *l)
280 {
281 	proc_t	*p = l->lwp_procp;
282 
283 	ASSERT(l->lwp_procp->p_brand == &sn1_brand);
284 	ASSERT(l->lwp_brand != NULL);
285 
286 	/*
287 	 * We should never be called for the last thread in a process.
288 	 * (That case is handled by sn1_proc_exit().)  There for this lwp
289 	 * must be exiting from a multi-threaded process.
290 	 */
291 	ASSERT(p->p_tlist != p->p_tlist->t_forw);
292 
293 	l->lwp_brand = NULL;
294 }
295 
296 /*ARGSUSED*/
297 void
298 sn1_init_brand_data(zone_t *zone)
299 {
300 }
301 
302 /*ARGSUSED*/
303 void
304 sn1_free_brand_data(zone_t *zone)
305 {
306 }
307 
308 int
309 sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
310 	int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
311 	int brand_action)
312 {
313 	args->brandname = "sn1";
314 	return ((args->execswp->exec_func)(vp, uap, args, idatap, level + 1,
315 	    execsz, setid, exec_file, cred, brand_action));
316 }
317 
318 
319 int
320 _init(void)
321 {
322 	int err;
323 
324 	/*
325 	 * Set up the table indicating which system calls we want to
326 	 * interpose on.  We should probably build this automatically from
327 	 * a list of system calls that is shared with the user-space
328 	 * library.
329 	 */
330 	sn1_emulation_table = kmem_zalloc(NSYSCALL, KM_SLEEP);
331 	sn1_emulation_table[SYS_uname] = 1;
332 
333 	err = mod_install(&modlinkage);
334 	if (err) {
335 		cmn_err(CE_WARN, "Couldn't install brand module");
336 		kmem_free(sn1_emulation_table, NSYSCALL);
337 	}
338 
339 	return (err);
340 }
341 
342 int
343 _info(struct modinfo *modinfop)
344 {
345 	return (mod_info(&modlinkage, modinfop));
346 }
347 
348 int
349 _fini(void)
350 {
351 	int err;
352 
353 	/*
354 	 * If there are any zones using this brand, we can't allow it to be
355 	 * unloaded.
356 	 */
357 	if (brand_zone_count(&sn1_brand))
358 		return (EBUSY);
359 
360 	kmem_free(sn1_emulation_table, NSYSCALL);
361 	sn1_emulation_table = NULL;
362 
363 	err = mod_remove(&modlinkage);
364 	if (err)
365 		cmn_err(CE_WARN, "Couldn't unload sn1 brand module");
366 
367 	return (err);
368 }
369