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 2007 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, "Solaris N-1 Brand %I%", &sn1_brand
125 };
126 
127 static struct modlinkage modlinkage = {
128 	MODREV_1, (void *)&modlbrand, NULL
129 };
130 
131 void
132 sn1_setbrand(proc_t *p)
133 {
134 	p->p_brand_data = NULL;
135 	p->p_brand = &sn1_brand;
136 }
137 
138 /* ARGSUSED */
139 int
140 sn1_getattr(zone_t *zone, int attr, void *buf, size_t *bufsize)
141 {
142 	return (EINVAL);
143 }
144 
145 /* ARGSUSED */
146 int
147 sn1_setattr(zone_t *zone, int attr, void *buf, size_t bufsize)
148 {
149 	return (EINVAL);
150 }
151 
152 /*
153  * Get the address of the user-space system call handler from the user
154  * process and attach it to the proc structure.
155  */
156 /*ARGSUSED*/
157 int
158 sn1_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2,
159     uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6)
160 {
161 	proc_t *p = curproc;
162 	*rval = 0;
163 
164 	if (cmd == B_REGISTER) {
165 		p->p_brand = &sn1_brand;
166 		p->p_brand_data = (void *) arg1;
167 		return (0);
168 	}
169 
170 	ASSERT(p->p_brand == &sn1_brand);
171 
172 	return (EINVAL);
173 }
174 
175 /*
176  * Copy the per-process brand data from a parent proc to a child.  In the
177  * sn1 brand, the only per-process state is the address of the user-space
178  * handler.
179  */
180 void
181 sn1_copy_procdata(proc_t *child, proc_t *parent)
182 {
183 	child->p_brand_data = parent->p_brand_data;
184 }
185 
186 /*ARGSUSED*/
187 void
188 sn1_proc_exit(struct proc *p, klwp_t *l)
189 {
190 	p->p_brand_data = NULL;
191 	p->p_brand = &native_brand;
192 }
193 
194 void
195 sn1_exec()
196 {
197 	curproc->p_brand_data = NULL;
198 }
199 
200 /*ARGSUSED*/
201 int
202 sn1_initlwp(klwp_t *l)
203 {
204 	return (0);
205 }
206 
207 /*ARGSUSED*/
208 void
209 sn1_init_brand_data(zone_t *zone)
210 {
211 }
212 
213 /*ARGSUSED*/
214 void
215 sn1_free_brand_data(zone_t *zone)
216 {
217 }
218 
219 /*ARGSUSED*/
220 void
221 sn1_forklwp(klwp_t *p, klwp_t *c)
222 {
223 }
224 
225 /*ARGSUSED*/
226 void
227 sn1_freelwp(klwp_t *l)
228 {
229 }
230 
231 /*ARGSUSED*/
232 void
233 sn1_lwpexit(klwp_t *l)
234 {
235 }
236 
237 int
238 sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
239 	int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
240 	int brand_action)
241 {
242 	args->brandname = "sn1";
243 	return ((args->execswp->exec_func)(vp, uap, args, idatap, level + 1,
244 	    execsz, setid, exec_file, cred, brand_action));
245 }
246 
247 
248 int
249 _init(void)
250 {
251 	int err;
252 
253 	/*
254 	 * Set up the table indicating which system calls we want to
255 	 * interpose on.  We should probably build this automatically from
256 	 * a list of system calls that is shared with the user-space
257 	 * library.
258 	 */
259 	sn1_emulation_table = kmem_zalloc(NSYSCALL, KM_SLEEP);
260 	sn1_emulation_table[SYS_uname] = 1;
261 
262 	err = mod_install(&modlinkage);
263 	if (err) {
264 		cmn_err(CE_WARN, "Couldn't install brand module");
265 		kmem_free(sn1_emulation_table, NSYSCALL);
266 	}
267 
268 	return (err);
269 }
270 
271 int
272 _info(struct modinfo *modinfop)
273 {
274 	return (mod_info(&modlinkage, modinfop));
275 }
276 
277 int
278 _fini(void)
279 {
280 	int err;
281 
282 	/*
283 	 * If there are any zones using this brand, we can't allow it to be
284 	 * unloaded.
285 	 */
286 	if (brand_zone_count(&sn1_brand))
287 		return (EBUSY);
288 
289 	kmem_free(sn1_emulation_table, NSYSCALL);
290 	sn1_emulation_table = NULL;
291 
292 	err = mod_remove(&modlinkage);
293 	if (err)
294 		cmn_err(CE_WARN, "Couldn't unload sn1 brand module");
295 
296 	return (err);
297 }
298