freebsd32_ioctl.c revision 330897
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: stable/11/sys/compat/freebsd32/freebsd32_ioctl.c 330897 2018-03-14 03:19:51Z eadler $");
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/* Cannot get exact size in 64-bit due to alignment issue of entire struct. */
61CTASSERT((sizeof(struct md_ioctl32)+4) == 436);
62CTASSERT(sizeof(struct ioc_read_toc_entry32) == 8);
63CTASSERT(sizeof(struct ioc_toc_header32) == 4);
64CTASSERT(sizeof(struct mem_range_op32) == 12);
65CTASSERT(sizeof(struct pci_conf_io32) == 36);
66CTASSERT(sizeof(struct pci_match_conf32) == 44);
67CTASSERT(sizeof(struct pci_conf32) == 44);
68
69
70static int
71freebsd32_ioctl_md(struct thread *td, struct freebsd32_ioctl_args *uap,
72    struct file *fp)
73{
74	struct md_ioctl mdv;
75	struct md_ioctl32 md32;
76	u_long com = 0;
77	int i, error;
78
79	if (uap->com & IOC_IN) {
80		if ((error = copyin(uap->data, &md32, sizeof(md32)))) {
81			return (error);
82		}
83		CP(md32, mdv, md_version);
84		CP(md32, mdv, md_unit);
85		CP(md32, mdv, md_type);
86		PTRIN_CP(md32, mdv, md_file);
87		CP(md32, mdv, md_mediasize);
88		CP(md32, mdv, md_sectorsize);
89		CP(md32, mdv, md_options);
90		CP(md32, mdv, md_base);
91		CP(md32, mdv, md_fwheads);
92		CP(md32, mdv, md_fwsectors);
93	} else if (uap->com & IOC_OUT) {
94		/*
95		 * Zero the buffer so the user always
96		 * gets back something deterministic.
97		 */
98		bzero(&mdv, sizeof mdv);
99	}
100
101	switch (uap->com) {
102	case MDIOCATTACH_32:
103		com = MDIOCATTACH;
104		break;
105	case MDIOCDETACH_32:
106		com = MDIOCDETACH;
107		break;
108	case MDIOCQUERY_32:
109		com = MDIOCQUERY;
110		break;
111	case MDIOCLIST_32:
112		com = MDIOCLIST;
113		break;
114	default:
115		panic("%s: unknown MDIOC %#x", __func__, uap->com);
116	}
117	error = fo_ioctl(fp, com, (caddr_t)&mdv, td->td_ucred, td);
118	if (error == 0 && (com & IOC_OUT)) {
119		CP(mdv, md32, md_version);
120		CP(mdv, md32, md_unit);
121		CP(mdv, md32, md_type);
122		PTROUT_CP(mdv, md32, md_file);
123		CP(mdv, md32, md_mediasize);
124		CP(mdv, md32, md_sectorsize);
125		CP(mdv, md32, md_options);
126		CP(mdv, md32, md_base);
127		CP(mdv, md32, md_fwheads);
128		CP(mdv, md32, md_fwsectors);
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
143static int
144freebsd32_ioctl_ioc_toc_header(struct thread *td,
145    struct freebsd32_ioctl_args *uap, struct file *fp)
146{
147	struct ioc_toc_header toch;
148	struct ioc_toc_header32 toch32;
149	int error;
150
151	if ((error = copyin(uap->data, &toch32, sizeof(toch32))))
152		return (error);
153	CP(toch32, toch, len);
154	CP(toch32, toch, starting_track);
155	CP(toch32, toch, ending_track);
156	error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&toch,
157	    td->td_ucred, td);
158	return (error);
159}
160
161
162static int
163freebsd32_ioctl_ioc_read_toc(struct thread *td,
164    struct freebsd32_ioctl_args *uap, struct file *fp)
165{
166	struct ioc_read_toc_entry toce;
167	struct ioc_read_toc_entry32 toce32;
168	int error;
169
170	if ((error = copyin(uap->data, &toce32, sizeof(toce32))))
171		return (error);
172	CP(toce32, toce, address_format);
173	CP(toce32, toce, starting_track);
174	CP(toce32, toce, data_len);
175	PTRIN_CP(toce32, toce, data);
176
177	if ((error = fo_ioctl(fp, CDIOREADTOCENTRYS, (caddr_t)&toce,
178	    td->td_ucred, td))) {
179		CP(toce, toce32, address_format);
180		CP(toce, toce32, starting_track);
181		CP(toce, toce32, data_len);
182		PTROUT_CP(toce, toce32, data);
183		error = copyout(&toce32, uap->data, sizeof(toce32));
184	}
185	return error;
186}
187
188static int
189freebsd32_ioctl_fiodgname(struct thread *td,
190    struct freebsd32_ioctl_args *uap, struct file *fp)
191{
192	struct fiodgname_arg fgn;
193	struct fiodgname_arg32 fgn32;
194	int error;
195
196	if ((error = copyin(uap->data, &fgn32, sizeof fgn32)) != 0)
197		return (error);
198	CP(fgn32, fgn, len);
199	PTRIN_CP(fgn32, fgn, buf);
200	error = fo_ioctl(fp, FIODGNAME, (caddr_t)&fgn, td->td_ucred, td);
201	return (error);
202}
203
204static int
205freebsd32_ioctl_memrange(struct thread *td,
206    struct freebsd32_ioctl_args *uap, struct file *fp)
207{
208	struct mem_range_op mro;
209	struct mem_range_op32 mro32;
210	int error;
211	u_long com;
212
213	if ((error = copyin(uap->data, &mro32, sizeof(mro32))) != 0)
214		return (error);
215
216	PTRIN_CP(mro32, mro, mo_desc);
217	CP(mro32, mro, mo_arg[0]);
218	CP(mro32, mro, mo_arg[1]);
219
220	com = 0;
221	switch (uap->com) {
222	case MEMRANGE_GET32:
223		com = MEMRANGE_GET;
224		break;
225
226	case MEMRANGE_SET32:
227		com = MEMRANGE_SET;
228		break;
229
230	default:
231		panic("%s: unknown MEMRANGE %#x", __func__, uap->com);
232	}
233
234	if ((error = fo_ioctl(fp, com, (caddr_t)&mro, td->td_ucred, td)) != 0)
235		return (error);
236
237	if ( (com & IOC_OUT) ) {
238		CP(mro, mro32, mo_arg[0]);
239		CP(mro, mro32, mo_arg[1]);
240
241		error = copyout(&mro32, uap->data, sizeof(mro32));
242	}
243
244	return (error);
245}
246
247static int
248freebsd32_ioctl_pciocgetconf(struct thread *td,
249    struct freebsd32_ioctl_args *uap, struct file *fp)
250{
251	struct pci_conf_io pci;
252	struct pci_conf_io32 pci32;
253	struct pci_match_conf32 pmc32;
254	struct pci_match_conf32 *pmc32p;
255	struct pci_match_conf pmc;
256	struct pci_match_conf *pmcp;
257	struct pci_conf32 pc32;
258	struct pci_conf32 *pc32p;
259	struct pci_conf pc;
260	struct pci_conf *pcp;
261	u_int32_t i;
262	u_int32_t npat_to_convert;
263	u_int32_t nmatch_to_convert;
264	vm_offset_t addr;
265	int error;
266
267	if ((error = copyin(uap->data, &pci32, sizeof(pci32))) != 0)
268		return (error);
269
270	CP(pci32, pci, num_patterns);
271	CP(pci32, pci, offset);
272	CP(pci32, pci, generation);
273
274	npat_to_convert = pci32.pat_buf_len / sizeof(struct pci_match_conf32);
275	pci.pat_buf_len = npat_to_convert * sizeof(struct pci_match_conf);
276	pci.patterns = NULL;
277	nmatch_to_convert = pci32.match_buf_len / sizeof(struct pci_conf32);
278	pci.match_buf_len = nmatch_to_convert * sizeof(struct pci_conf);
279	pci.matches = NULL;
280
281	if ((error = copyout_map(td, &addr, pci.pat_buf_len)) != 0)
282		goto cleanup;
283	pci.patterns = (struct pci_match_conf *)addr;
284	if ((error = copyout_map(td, &addr, pci.match_buf_len)) != 0)
285		goto cleanup;
286	pci.matches = (struct pci_conf *)addr;
287
288	npat_to_convert = min(npat_to_convert, pci.num_patterns);
289
290	for (i = 0, pmc32p = (struct pci_match_conf32 *)PTRIN(pci32.patterns),
291	     pmcp = pci.patterns;
292	     i < npat_to_convert; i++, pmc32p++, pmcp++) {
293		if ((error = copyin(pmc32p, &pmc32, sizeof(pmc32))) != 0)
294			goto cleanup;
295		CP(pmc32,pmc,pc_sel);
296		strlcpy(pmc.pd_name, pmc32.pd_name, sizeof(pmc.pd_name));
297		CP(pmc32,pmc,pd_unit);
298		CP(pmc32,pmc,pc_vendor);
299		CP(pmc32,pmc,pc_device);
300		CP(pmc32,pmc,pc_class);
301		CP(pmc32,pmc,flags);
302		if ((error = copyout(&pmc, pmcp, sizeof(pmc))) != 0)
303			goto cleanup;
304	}
305
306	if ((error = fo_ioctl(fp, PCIOCGETCONF, (caddr_t)&pci,
307			      td->td_ucred, td)) != 0)
308		goto cleanup;
309
310	nmatch_to_convert = min(nmatch_to_convert, pci.num_matches);
311
312	for (i = 0, pcp = pci.matches,
313	     pc32p = (struct pci_conf32 *)PTRIN(pci32.matches);
314	     i < nmatch_to_convert; i++, pcp++, pc32p++) {
315		if ((error = copyin(pcp, &pc, sizeof(pc))) != 0)
316			goto cleanup;
317		CP(pc,pc32,pc_sel);
318		CP(pc,pc32,pc_hdr);
319		CP(pc,pc32,pc_subvendor);
320		CP(pc,pc32,pc_subdevice);
321		CP(pc,pc32,pc_vendor);
322		CP(pc,pc32,pc_device);
323		CP(pc,pc32,pc_class);
324		CP(pc,pc32,pc_subclass);
325		CP(pc,pc32,pc_progif);
326		CP(pc,pc32,pc_revid);
327		strlcpy(pc32.pd_name, pc.pd_name, sizeof(pc32.pd_name));
328		CP(pc,pc32,pd_unit);
329		if ((error = copyout(&pc32, pc32p, sizeof(pc32))) != 0)
330			goto cleanup;
331	}
332
333	CP(pci, pci32, num_matches);
334	CP(pci, pci32, offset);
335	CP(pci, pci32, generation);
336	CP(pci, pci32, status);
337
338	error = copyout(&pci32, uap->data, sizeof(pci32));
339
340cleanup:
341	if (pci.patterns)
342		copyout_unmap(td, (vm_offset_t)pci.patterns, pci.pat_buf_len);
343	if (pci.matches)
344		copyout_unmap(td, (vm_offset_t)pci.matches, pci.match_buf_len);
345
346	return (error);
347}
348
349static int
350freebsd32_ioctl_sg(struct thread *td,
351    struct freebsd32_ioctl_args *uap, struct file *fp)
352{
353	struct sg_io_hdr io;
354	struct sg_io_hdr32 io32;
355	int error;
356
357	if ((error = copyin(uap->data, &io32, sizeof(io32))) != 0)
358		return (error);
359
360	CP(io32, io, interface_id);
361	CP(io32, io, dxfer_direction);
362	CP(io32, io, cmd_len);
363	CP(io32, io, mx_sb_len);
364	CP(io32, io, iovec_count);
365	CP(io32, io, dxfer_len);
366	PTRIN_CP(io32, io, dxferp);
367	PTRIN_CP(io32, io, cmdp);
368	PTRIN_CP(io32, io, sbp);
369	CP(io32, io, timeout);
370	CP(io32, io, flags);
371	CP(io32, io, pack_id);
372	PTRIN_CP(io32, io, usr_ptr);
373	CP(io32, io, status);
374	CP(io32, io, masked_status);
375	CP(io32, io, msg_status);
376	CP(io32, io, sb_len_wr);
377	CP(io32, io, host_status);
378	CP(io32, io, driver_status);
379	CP(io32, io, resid);
380	CP(io32, io, duration);
381	CP(io32, io, info);
382
383	if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
384		return (error);
385
386	CP(io, io32, interface_id);
387	CP(io, io32, dxfer_direction);
388	CP(io, io32, cmd_len);
389	CP(io, io32, mx_sb_len);
390	CP(io, io32, iovec_count);
391	CP(io, io32, dxfer_len);
392	PTROUT_CP(io, io32, dxferp);
393	PTROUT_CP(io, io32, cmdp);
394	PTROUT_CP(io, io32, sbp);
395	CP(io, io32, timeout);
396	CP(io, io32, flags);
397	CP(io, io32, pack_id);
398	PTROUT_CP(io, io32, usr_ptr);
399	CP(io, io32, status);
400	CP(io, io32, masked_status);
401	CP(io, io32, msg_status);
402	CP(io, io32, sb_len_wr);
403	CP(io, io32, host_status);
404	CP(io, io32, driver_status);
405	CP(io, io32, resid);
406	CP(io, io32, duration);
407	CP(io, io32, info);
408
409	error = copyout(&io32, uap->data, sizeof(io32));
410
411	return (error);
412}
413
414int
415freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap)
416{
417	struct ioctl_args ap /*{
418		int	fd;
419		u_long	com;
420		caddr_t	data;
421	}*/ ;
422	struct file *fp;
423	cap_rights_t rights;
424	int error;
425
426	error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
427	if (error != 0)
428		return (error);
429	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
430		fdrop(fp, td);
431		return (EBADF);
432	}
433
434	switch (uap->com) {
435	case MDIOCATTACH_32:	/* FALLTHROUGH */
436	case MDIOCDETACH_32:	/* FALLTHROUGH */
437	case MDIOCQUERY_32:	/* FALLTHROUGH */
438	case MDIOCLIST_32:
439		error = freebsd32_ioctl_md(td, uap, fp);
440		break;
441
442	case CDIOREADTOCENTRYS_32:
443		error = freebsd32_ioctl_ioc_read_toc(td, uap, fp);
444		break;
445
446	case CDIOREADTOCHEADER_32:
447		error = freebsd32_ioctl_ioc_toc_header(td, uap, fp);
448		break;
449
450	case FIODGNAME_32:
451		error = freebsd32_ioctl_fiodgname(td, uap, fp);
452		break;
453
454	case MEMRANGE_GET32:	/* FALLTHROUGH */
455	case MEMRANGE_SET32:
456		error = freebsd32_ioctl_memrange(td, uap, fp);
457		break;
458
459	case PCIOCGETCONF_32:
460		error = freebsd32_ioctl_pciocgetconf(td, uap, fp);
461		break;
462
463	case SG_IO_32:
464		error = freebsd32_ioctl_sg(td, uap, fp);
465		break;
466
467	default:
468		fdrop(fp, td);
469		ap.fd = uap->fd;
470		ap.com = uap->com;
471		PTRIN_CP(*uap, ap, data);
472		return sys_ioctl(td, &ap);
473	}
474
475	fdrop(fp, td);
476	return error;
477}
478