1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1994 Christos Zoulas 5 * Copyright (c) 1995 Frank van der Linden 6 * Copyright (c) 1995 Scott Bartram 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp 32 */ 33 34 #include <sys/param.h> 35 #include <sys/types.h> 36 #include <sys/bus.h> 37 #include <sys/conf.h> 38 #include <sys/fcntl.h> 39 #include <sys/jail.h> 40 #include <sys/malloc.h> 41 #include <sys/namei.h> 42 #include <sys/proc.h> 43 #include <sys/stat.h> 44 #include <sys/syscallsubr.h> 45 #include <sys/vnode.h> 46 47 #include <machine/stdarg.h> 48 49 #include <compat/linux/linux_dtrace.h> 50 #include <compat/linux/linux_mib.h> 51 #include <compat/linux/linux_util.h> 52 53 MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 54 MALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures"); 55 56 FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator"); 57 FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator"); 58 59 /** 60 * Special DTrace provider for the linuxulator. 61 * 62 * In this file we define the provider for the entire linuxulator. All 63 * modules (= files of the linuxulator) use it. 64 * 65 * We define a different name depending on the emulated bitsize, see 66 * ../../<ARCH>/linux{,32}/linux.h, e.g.: 67 * native bitsize = linuxulator 68 * amd64, 32bit emulation = linuxulator32 69 */ 70 LIN_SDT_PROVIDER_DEFINE(linuxulator); 71 LIN_SDT_PROVIDER_DEFINE(linuxulator32); 72 73 char linux_emul_path[MAXPATHLEN] = "/compat/linux"; 74 75 SYSCTL_STRING(_compat_linux, OID_AUTO, emul_path, CTLFLAG_RWTUN, 76 linux_emul_path, sizeof(linux_emul_path), 77 "Linux runtime environment path"); 78 79 int 80 linux_pwd_onexec(struct thread *td) 81 { 82 struct nameidata nd; 83 struct pwd *pwd; 84 int error; 85 86 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path); 87 error = namei(&nd); 88 if (error != 0) { 89 /* 90 * Do not bother if we are in chroot or jail. 91 */ 92 pwd = pwd_hold(td); 93 if (pwd->pwd_rdir != rootvnode) { 94 pwd_drop(pwd); 95 return (0); 96 } 97 pwd_drop(pwd); 98 return (error); 99 } 100 NDFREE_PNBUF(&nd); 101 pwd_altroot(td, nd.ni_vp); 102 vrele(nd.ni_vp); 103 return (0); 104 } 105 106 void 107 linux_pwd_onexec_native(struct thread *td) 108 { 109 110 pwd_altroot(td, NULL); 111 } 112 113 void 114 linux_msg(const struct thread *td, const char *fmt, ...) 115 { 116 va_list ap; 117 struct proc *p; 118 119 if (linux_debug == 0) 120 return; 121 122 p = td->td_proc; 123 printf("linux: jid %d pid %d (%s): ", p->p_ucred->cr_prison->pr_id, 124 (int)p->p_pid, p->p_comm); 125 va_start(ap, fmt); 126 vprintf(fmt, ap); 127 va_end(ap); 128 printf("\n"); 129 } 130 131 struct device_element 132 { 133 TAILQ_ENTRY(device_element) list; 134 struct linux_device_handler entry; 135 }; 136 137 static TAILQ_HEAD(, device_element) devices = 138 TAILQ_HEAD_INITIALIZER(devices); 139 140 static struct linux_device_handler null_handler = 141 { "mem", "mem", "null", "null", 1, 3, 1}; 142 143 DATA_SET(linux_device_handler_set, null_handler); 144 145 char * 146 linux_driver_get_name_dev(device_t dev) 147 { 148 struct device_element *de; 149 const char *device_name = device_get_name(dev); 150 151 if (device_name == NULL) 152 return (NULL); 153 TAILQ_FOREACH(de, &devices, list) { 154 if (strcmp(device_name, de->entry.bsd_driver_name) == 0) 155 return (de->entry.linux_driver_name); 156 } 157 158 return (NULL); 159 } 160 161 int 162 linux_driver_get_major_minor(const char *node, int *major, int *minor) 163 { 164 struct device_element *de; 165 unsigned long devno; 166 size_t sz; 167 168 if (node == NULL || major == NULL || minor == NULL) 169 return (1); 170 171 sz = sizeof("pts/") - 1; 172 if (strncmp(node, "pts/", sz) == 0 && node[sz] != '\0') { 173 /* 174 * Linux checks major and minors of the slave device 175 * to make sure it's a pty device, so let's make him 176 * believe it is. 177 */ 178 devno = strtoul(node + sz, NULL, 10); 179 *major = 136 + (devno / 256); 180 *minor = devno % 256; 181 return (0); 182 } 183 184 sz = sizeof("dri/card") - 1; 185 if (strncmp(node, "dri/card", sz) == 0 && node[sz] != '\0') { 186 devno = strtoul(node + sz, NULL, 10); 187 *major = 226 + (devno / 256); 188 *minor = devno % 256; 189 return (0); 190 } 191 sz = sizeof("dri/controlD") - 1; 192 if (strncmp(node, "dri/controlD", sz) == 0 && node[sz] != '\0') { 193 devno = strtoul(node + sz, NULL, 10); 194 *major = 226 + (devno / 256); 195 *minor = devno % 256; 196 return (0); 197 } 198 sz = sizeof("dri/renderD") - 1; 199 if (strncmp(node, "dri/renderD", sz) == 0 && node[sz] != '\0') { 200 devno = strtoul(node + sz, NULL, 10); 201 *major = 226 + (devno / 256); 202 *minor = devno % 256; 203 return (0); 204 } 205 sz = sizeof("drm/") - 1; 206 if (strncmp(node, "drm/", sz) == 0 && node[sz] != '\0') { 207 devno = strtoul(node + sz, NULL, 10); 208 *major = 226 + (devno / 256); 209 *minor = devno % 256; 210 return (0); 211 } 212 213 TAILQ_FOREACH(de, &devices, list) { 214 if (strcmp(node, de->entry.bsd_device_name) == 0) { 215 *major = de->entry.linux_major; 216 *minor = de->entry.linux_minor; 217 return (0); 218 } 219 } 220 221 return (1); 222 } 223 224 int 225 linux_vn_get_major_minor(const struct vnode *vp, int *major, int *minor) 226 { 227 int error; 228 229 if (vp->v_type != VCHR) 230 return (ENOTBLK); 231 dev_lock(); 232 if (vp->v_rdev == NULL) { 233 dev_unlock(); 234 return (ENXIO); 235 } 236 error = linux_driver_get_major_minor(devtoname(vp->v_rdev), 237 major, minor); 238 dev_unlock(); 239 return (error); 240 } 241 242 void 243 translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) 244 { 245 int major, minor; 246 247 if (vn_isdisk(vp)) { 248 sb->st_mode &= ~S_IFMT; 249 sb->st_mode |= S_IFBLK; 250 } 251 252 /* 253 * Return the same st_dev for every devfs instance. The reason 254 * for this is to work around an idiosyncrasy of glibc getttynam() 255 * implementation: it checks whether st_dev returned for fd 0 256 * is the same as st_dev returned for the target of /proc/self/fd/0 257 * symlink, and with linux chroots having their own devfs instance, 258 * the check will fail if you chroot into it. 259 */ 260 if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc) 261 sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0]; 262 263 if (linux_vn_get_major_minor(vp, &major, &minor) == 0) 264 sb->st_rdev = makedev(major, minor); 265 } 266 267 char * 268 linux_get_char_devices(void) 269 { 270 struct device_element *de; 271 char *temp, *string, *last; 272 char formated[256]; 273 int current_size = 0, string_size = 1024; 274 275 string = malloc(string_size, M_LINUX, M_WAITOK); 276 string[0] = '\000'; 277 last = ""; 278 TAILQ_FOREACH(de, &devices, list) { 279 if (!de->entry.linux_char_device) 280 continue; 281 temp = string; 282 if (strcmp(last, de->entry.bsd_driver_name) != 0) { 283 last = de->entry.bsd_driver_name; 284 285 snprintf(formated, sizeof(formated), "%3d %s\n", 286 de->entry.linux_major, 287 de->entry.linux_device_name); 288 if (strlen(formated) + current_size 289 >= string_size) { 290 string_size *= 2; 291 string = malloc(string_size, 292 M_LINUX, M_WAITOK); 293 bcopy(temp, string, current_size); 294 free(temp, M_LINUX); 295 } 296 strcat(string, formated); 297 current_size = strlen(string); 298 } 299 } 300 301 return (string); 302 } 303 304 void 305 linux_free_get_char_devices(char *string) 306 { 307 308 free(string, M_LINUX); 309 } 310 311 static int linux_major_starting = 200; 312 313 int 314 linux_device_register_handler(struct linux_device_handler *d) 315 { 316 struct device_element *de; 317 318 if (d == NULL) 319 return (EINVAL); 320 321 de = malloc(sizeof(*de), M_LINUX, M_WAITOK); 322 if (d->linux_major < 0) { 323 d->linux_major = linux_major_starting++; 324 } 325 bcopy(d, &de->entry, sizeof(*d)); 326 327 /* Add the element to the list, sorted on span. */ 328 TAILQ_INSERT_TAIL(&devices, de, list); 329 330 return (0); 331 } 332 333 int 334 linux_device_unregister_handler(struct linux_device_handler *d) 335 { 336 struct device_element *de; 337 338 if (d == NULL) 339 return (EINVAL); 340 341 TAILQ_FOREACH(de, &devices, list) { 342 if (bcmp(d, &de->entry, sizeof(*d)) == 0) { 343 TAILQ_REMOVE(&devices, de, list); 344 free(de, M_LINUX); 345 346 return (0); 347 } 348 } 349 350 return (EINVAL); 351 } 352