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