1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2008 David E. O'Brien
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the author nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include "opt_compat.h"
36 
37 #include <sys/param.h>
38 #include <sys/capsicum.h>
39 #include <sys/cdio.h>
40 #include <sys/fcntl.h>
41 #include <sys/filio.h>
42 #include <sys/file.h>
43 #include <sys/ioccom.h>
44 #include <sys/malloc.h>
45 #include <sys/mdioctl.h>
46 #include <sys/memrange.h>
47 #include <sys/pciio.h>
48 #include <sys/proc.h>
49 #include <sys/syscall.h>
50 #include <sys/syscallsubr.h>
51 #include <sys/sysctl.h>
52 #include <sys/sysent.h>
53 #include <sys/sysproto.h>
54 #include <sys/systm.h>
55 
56 #include <compat/freebsd32/freebsd32.h>
57 #include <compat/freebsd32/freebsd32_ioctl.h>
58 #include <compat/freebsd32/freebsd32_proto.h>
59 
60 CTASSERT((sizeof(struct md_ioctl32)) == 436);
61 CTASSERT(sizeof(struct ioc_read_toc_entry32) == 8);
62 CTASSERT(sizeof(struct mem_range_op32) == 12);
63 CTASSERT(sizeof(struct pci_conf_io32) == 36);
64 CTASSERT(sizeof(struct pci_match_conf32) == 44);
65 CTASSERT(sizeof(struct pci_conf32) == 44);
66 
67 
68 static int
69 freebsd32_ioctl_md(struct thread *td, struct freebsd32_ioctl_args *uap,
70     struct file *fp)
71 {
72 	struct md_ioctl mdv;
73 	struct md_ioctl32 md32;
74 	u_long com = 0;
75 	int i, error;
76 
77 	if (uap->com & IOC_IN) {
78 		if ((error = copyin(uap->data, &md32, sizeof(md32)))) {
79 			return (error);
80 		}
81 		CP(md32, mdv, md_version);
82 		CP(md32, mdv, md_unit);
83 		CP(md32, mdv, md_type);
84 		PTRIN_CP(md32, mdv, md_file);
85 		CP(md32, mdv, md_mediasize);
86 		CP(md32, mdv, md_sectorsize);
87 		CP(md32, mdv, md_options);
88 		CP(md32, mdv, md_base);
89 		CP(md32, mdv, md_fwheads);
90 		CP(md32, mdv, md_fwsectors);
91 		PTRIN_CP(md32, mdv, md_label);
92 	} else if (uap->com & IOC_OUT) {
93 		/*
94 		 * Zero the buffer so the user always
95 		 * gets back something deterministic.
96 		 */
97 		bzero(&mdv, sizeof mdv);
98 	}
99 
100 	switch (uap->com) {
101 	case MDIOCATTACH_32:
102 		com = MDIOCATTACH;
103 		break;
104 	case MDIOCDETACH_32:
105 		com = MDIOCDETACH;
106 		break;
107 	case MDIOCQUERY_32:
108 		com = MDIOCQUERY;
109 		break;
110 	case MDIOCLIST_32:
111 		com = MDIOCLIST;
112 		break;
113 	default:
114 		panic("%s: unknown MDIOC %#x", __func__, uap->com);
115 	}
116 	error = fo_ioctl(fp, com, (caddr_t)&mdv, td->td_ucred, td);
117 	if (error == 0 && (com & IOC_OUT)) {
118 		CP(mdv, md32, md_version);
119 		CP(mdv, md32, md_unit);
120 		CP(mdv, md32, md_type);
121 		PTROUT_CP(mdv, md32, md_file);
122 		CP(mdv, md32, md_mediasize);
123 		CP(mdv, md32, md_sectorsize);
124 		CP(mdv, md32, md_options);
125 		CP(mdv, md32, md_base);
126 		CP(mdv, md32, md_fwheads);
127 		CP(mdv, md32, md_fwsectors);
128 		PTROUT_CP(mdv, md32, md_label);
129 		if (com == MDIOCLIST) {
130 			/*
131 			 * Use MDNPAD, and not MDNPAD32.  Padding is
132 			 * allocated and used by compat32 ABI.
133 			 */
134 			for (i = 0; i < MDNPAD; i++)
135 				CP(mdv, md32, md_pad[i]);
136 		}
137 		error = copyout(&md32, uap->data, sizeof(md32));
138 	}
139 	return error;
140 }
141 
142 
143 static int
144 freebsd32_ioctl_ioc_read_toc(struct thread *td,
145     struct freebsd32_ioctl_args *uap, struct file *fp)
146 {
147 	struct ioc_read_toc_entry toce;
148 	struct ioc_read_toc_entry32 toce32;
149 	int error;
150 
151 	if ((error = copyin(uap->data, &toce32, sizeof(toce32))))
152 		return (error);
153 	CP(toce32, toce, address_format);
154 	CP(toce32, toce, starting_track);
155 	CP(toce32, toce, data_len);
156 	PTRIN_CP(toce32, toce, data);
157 
158 	if ((error = fo_ioctl(fp, CDIOREADTOCENTRYS, (caddr_t)&toce,
159 	    td->td_ucred, td))) {
160 		CP(toce, toce32, address_format);
161 		CP(toce, toce32, starting_track);
162 		CP(toce, toce32, data_len);
163 		PTROUT_CP(toce, toce32, data);
164 		error = copyout(&toce32, uap->data, sizeof(toce32));
165 	}
166 	return error;
167 }
168 
169 static int
170 freebsd32_ioctl_fiodgname(struct thread *td,
171     struct freebsd32_ioctl_args *uap, struct file *fp)
172 {
173 	struct fiodgname_arg fgn;
174 	struct fiodgname_arg32 fgn32;
175 	int error;
176 
177 	if ((error = copyin(uap->data, &fgn32, sizeof fgn32)) != 0)
178 		return (error);
179 	CP(fgn32, fgn, len);
180 	PTRIN_CP(fgn32, fgn, buf);
181 	error = fo_ioctl(fp, FIODGNAME, (caddr_t)&fgn, td->td_ucred, td);
182 	return (error);
183 }
184 
185 static int
186 freebsd32_ioctl_memrange(struct thread *td,
187     struct freebsd32_ioctl_args *uap, struct file *fp)
188 {
189 	struct mem_range_op mro;
190 	struct mem_range_op32 mro32;
191 	int error;
192 	u_long com;
193 
194 	if ((error = copyin(uap->data, &mro32, sizeof(mro32))) != 0)
195 		return (error);
196 
197 	PTRIN_CP(mro32, mro, mo_desc);
198 	CP(mro32, mro, mo_arg[0]);
199 	CP(mro32, mro, mo_arg[1]);
200 
201 	com = 0;
202 	switch (uap->com) {
203 	case MEMRANGE_GET32:
204 		com = MEMRANGE_GET;
205 		break;
206 
207 	case MEMRANGE_SET32:
208 		com = MEMRANGE_SET;
209 		break;
210 
211 	default:
212 		panic("%s: unknown MEMRANGE %#x", __func__, uap->com);
213 	}
214 
215 	if ((error = fo_ioctl(fp, com, (caddr_t)&mro, td->td_ucred, td)) != 0)
216 		return (error);
217 
218 	if ( (com & IOC_OUT) ) {
219 		CP(mro, mro32, mo_arg[0]);
220 		CP(mro, mro32, mo_arg[1]);
221 
222 		error = copyout(&mro32, uap->data, sizeof(mro32));
223 	}
224 
225 	return (error);
226 }
227 
228 static int
229 freebsd32_ioctl_pciocgetconf(struct thread *td,
230     struct freebsd32_ioctl_args *uap, struct file *fp)
231 {
232 	struct pci_conf_io pci;
233 	struct pci_conf_io32 pci32;
234 	struct pci_match_conf32 pmc32;
235 	struct pci_match_conf32 *pmc32p;
236 	struct pci_match_conf pmc;
237 	struct pci_match_conf *pmcp;
238 	struct pci_conf32 pc32;
239 	struct pci_conf32 *pc32p;
240 	struct pci_conf pc;
241 	struct pci_conf *pcp;
242 	u_int32_t i;
243 	u_int32_t npat_to_convert;
244 	u_int32_t nmatch_to_convert;
245 	vm_offset_t addr;
246 	int error;
247 
248 	if ((error = copyin(uap->data, &pci32, sizeof(pci32))) != 0)
249 		return (error);
250 
251 	CP(pci32, pci, num_patterns);
252 	CP(pci32, pci, offset);
253 	CP(pci32, pci, generation);
254 
255 	npat_to_convert = pci32.pat_buf_len / sizeof(struct pci_match_conf32);
256 	pci.pat_buf_len = npat_to_convert * sizeof(struct pci_match_conf);
257 	pci.patterns = NULL;
258 	nmatch_to_convert = pci32.match_buf_len / sizeof(struct pci_conf32);
259 	pci.match_buf_len = nmatch_to_convert * sizeof(struct pci_conf);
260 	pci.matches = NULL;
261 
262 	if ((error = copyout_map(td, &addr, pci.pat_buf_len)) != 0)
263 		goto cleanup;
264 	pci.patterns = (struct pci_match_conf *)addr;
265 	if ((error = copyout_map(td, &addr, pci.match_buf_len)) != 0)
266 		goto cleanup;
267 	pci.matches = (struct pci_conf *)addr;
268 
269 	npat_to_convert = min(npat_to_convert, pci.num_patterns);
270 
271 	for (i = 0, pmc32p = (struct pci_match_conf32 *)PTRIN(pci32.patterns),
272 	     pmcp = pci.patterns;
273 	     i < npat_to_convert; i++, pmc32p++, pmcp++) {
274 		if ((error = copyin(pmc32p, &pmc32, sizeof(pmc32))) != 0)
275 			goto cleanup;
276 		CP(pmc32,pmc,pc_sel);
277 		strlcpy(pmc.pd_name, pmc32.pd_name, sizeof(pmc.pd_name));
278 		CP(pmc32,pmc,pd_unit);
279 		CP(pmc32,pmc,pc_vendor);
280 		CP(pmc32,pmc,pc_device);
281 		CP(pmc32,pmc,pc_class);
282 		CP(pmc32,pmc,flags);
283 		if ((error = copyout(&pmc, pmcp, sizeof(pmc))) != 0)
284 			goto cleanup;
285 	}
286 
287 	if ((error = fo_ioctl(fp, PCIOCGETCONF, (caddr_t)&pci,
288 			      td->td_ucred, td)) != 0)
289 		goto cleanup;
290 
291 	nmatch_to_convert = min(nmatch_to_convert, pci.num_matches);
292 
293 	for (i = 0, pcp = pci.matches,
294 	     pc32p = (struct pci_conf32 *)PTRIN(pci32.matches);
295 	     i < nmatch_to_convert; i++, pcp++, pc32p++) {
296 		if ((error = copyin(pcp, &pc, sizeof(pc))) != 0)
297 			goto cleanup;
298 		CP(pc,pc32,pc_sel);
299 		CP(pc,pc32,pc_hdr);
300 		CP(pc,pc32,pc_subvendor);
301 		CP(pc,pc32,pc_subdevice);
302 		CP(pc,pc32,pc_vendor);
303 		CP(pc,pc32,pc_device);
304 		CP(pc,pc32,pc_class);
305 		CP(pc,pc32,pc_subclass);
306 		CP(pc,pc32,pc_progif);
307 		CP(pc,pc32,pc_revid);
308 		strlcpy(pc32.pd_name, pc.pd_name, sizeof(pc32.pd_name));
309 		CP(pc,pc32,pd_unit);
310 		if ((error = copyout(&pc32, pc32p, sizeof(pc32))) != 0)
311 			goto cleanup;
312 	}
313 
314 	CP(pci, pci32, num_matches);
315 	CP(pci, pci32, offset);
316 	CP(pci, pci32, generation);
317 	CP(pci, pci32, status);
318 
319 	error = copyout(&pci32, uap->data, sizeof(pci32));
320 
321 cleanup:
322 	if (pci.patterns)
323 		copyout_unmap(td, (vm_offset_t)pci.patterns, pci.pat_buf_len);
324 	if (pci.matches)
325 		copyout_unmap(td, (vm_offset_t)pci.matches, pci.match_buf_len);
326 
327 	return (error);
328 }
329 
330 static int
331 freebsd32_ioctl_sg(struct thread *td,
332     struct freebsd32_ioctl_args *uap, struct file *fp)
333 {
334 	struct sg_io_hdr io;
335 	struct sg_io_hdr32 io32;
336 	int error;
337 
338 	if ((error = copyin(uap->data, &io32, sizeof(io32))) != 0)
339 		return (error);
340 
341 	CP(io32, io, interface_id);
342 	CP(io32, io, dxfer_direction);
343 	CP(io32, io, cmd_len);
344 	CP(io32, io, mx_sb_len);
345 	CP(io32, io, iovec_count);
346 	CP(io32, io, dxfer_len);
347 	PTRIN_CP(io32, io, dxferp);
348 	PTRIN_CP(io32, io, cmdp);
349 	PTRIN_CP(io32, io, sbp);
350 	CP(io32, io, timeout);
351 	CP(io32, io, flags);
352 	CP(io32, io, pack_id);
353 	PTRIN_CP(io32, io, usr_ptr);
354 	CP(io32, io, status);
355 	CP(io32, io, masked_status);
356 	CP(io32, io, msg_status);
357 	CP(io32, io, sb_len_wr);
358 	CP(io32, io, host_status);
359 	CP(io32, io, driver_status);
360 	CP(io32, io, resid);
361 	CP(io32, io, duration);
362 	CP(io32, io, info);
363 
364 	if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
365 		return (error);
366 
367 	CP(io, io32, interface_id);
368 	CP(io, io32, dxfer_direction);
369 	CP(io, io32, cmd_len);
370 	CP(io, io32, mx_sb_len);
371 	CP(io, io32, iovec_count);
372 	CP(io, io32, dxfer_len);
373 	PTROUT_CP(io, io32, dxferp);
374 	PTROUT_CP(io, io32, cmdp);
375 	PTROUT_CP(io, io32, sbp);
376 	CP(io, io32, timeout);
377 	CP(io, io32, flags);
378 	CP(io, io32, pack_id);
379 	PTROUT_CP(io, io32, usr_ptr);
380 	CP(io, io32, status);
381 	CP(io, io32, masked_status);
382 	CP(io, io32, msg_status);
383 	CP(io, io32, sb_len_wr);
384 	CP(io, io32, host_status);
385 	CP(io, io32, driver_status);
386 	CP(io, io32, resid);
387 	CP(io, io32, duration);
388 	CP(io, io32, info);
389 
390 	error = copyout(&io32, uap->data, sizeof(io32));
391 
392 	return (error);
393 }
394 
395 int
396 freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap)
397 {
398 	struct ioctl_args ap /*{
399 		int	fd;
400 		u_long	com;
401 		caddr_t	data;
402 	}*/ ;
403 	struct file *fp;
404 	cap_rights_t rights;
405 	int error;
406 
407 	error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
408 	if (error != 0)
409 		return (error);
410 	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
411 		fdrop(fp, td);
412 		return (EBADF);
413 	}
414 
415 	switch (uap->com) {
416 	case MDIOCATTACH_32:	/* FALLTHROUGH */
417 	case MDIOCDETACH_32:	/* FALLTHROUGH */
418 	case MDIOCQUERY_32:	/* FALLTHROUGH */
419 	case MDIOCLIST_32:
420 		error = freebsd32_ioctl_md(td, uap, fp);
421 		break;
422 
423 	case CDIOREADTOCENTRYS_32:
424 		error = freebsd32_ioctl_ioc_read_toc(td, uap, fp);
425 		break;
426 
427 	case FIODGNAME_32:
428 		error = freebsd32_ioctl_fiodgname(td, uap, fp);
429 		break;
430 
431 	case MEMRANGE_GET32:	/* FALLTHROUGH */
432 	case MEMRANGE_SET32:
433 		error = freebsd32_ioctl_memrange(td, uap, fp);
434 		break;
435 
436 	case PCIOCGETCONF_32:
437 		error = freebsd32_ioctl_pciocgetconf(td, uap, fp);
438 		break;
439 
440 	case SG_IO_32:
441 		error = freebsd32_ioctl_sg(td, uap, fp);
442 		break;
443 
444 	default:
445 		fdrop(fp, td);
446 		ap.fd = uap->fd;
447 		ap.com = uap->com;
448 		PTRIN_CP(*uap, ap, data);
449 		return sys_ioctl(td, &ap);
450 	}
451 
452 	fdrop(fp, td);
453 	return error;
454 }
455