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/bus.h> 36 #include <sys/conf.h> 37 #include <sys/fcntl.h> 38 #include <sys/jail.h> 39 #include <sys/malloc.h> 40 #include <sys/namei.h> 41 #include <sys/proc.h> 42 #include <sys/stat.h> 43 #include <sys/syscallsubr.h> 44 #include <sys/vnode.h> 45 46 #include <machine/stdarg.h> 47 48 #include <compat/linux/linux_dtrace.h> 49 #include <compat/linux/linux_mib.h> 50 #include <compat/linux/linux_util.h> 51 52 MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 53 MALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures"); 54 55 FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator"); 56 FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator"); 57 58 /** 59 * Special DTrace provider for the linuxulator. 60 * 61 * In this file we define the provider for the entire linuxulator. All 62 * modules (= files of the linuxulator) use it. 63 * 64 * We define a different name depending on the emulated bitsize, see 65 * ../../<ARCH>/linux{,32}/linux.h, e.g.: 66 * native bitsize = linuxulator 67 * amd64, 32bit emulation = linuxulator32 68 */ 69 LIN_SDT_PROVIDER_DEFINE(linuxulator); 70 LIN_SDT_PROVIDER_DEFINE(linuxulator32); 71 72 char linux_emul_path[MAXPATHLEN] = "/compat/linux"; 73 74 SYSCTL_STRING(_compat_linux, OID_AUTO, emul_path, CTLFLAG_RWTUN, 75 linux_emul_path, sizeof(linux_emul_path), 76 "Linux runtime environment path"); 77 78 int 79 linux_pwd_onexec(struct thread *td) 80 { 81 struct nameidata nd; 82 int error; 83 84 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path); 85 error = namei(&nd); 86 if (error != 0) { 87 /* Do not prevent execution if altroot is non-existent. */ 88 pwd_altroot(td, NULL); 89 return (0); 90 } 91 NDFREE_PNBUF(&nd); 92 pwd_altroot(td, nd.ni_vp); 93 vrele(nd.ni_vp); 94 return (0); 95 } 96 97 void 98 linux_pwd_onexec_native(struct thread *td) 99 { 100 101 pwd_altroot(td, NULL); 102 } 103 104 void 105 linux_msg(const struct thread *td, const char *fmt, ...) 106 { 107 va_list ap; 108 struct proc *p; 109 110 if (linux_debug == 0) 111 return; 112 113 p = td->td_proc; 114 printf("linux: jid %d pid %d (%s): ", p->p_ucred->cr_prison->pr_id, 115 (int)p->p_pid, p->p_comm); 116 va_start(ap, fmt); 117 vprintf(fmt, ap); 118 va_end(ap); 119 printf("\n"); 120 } 121 122 struct device_element 123 { 124 TAILQ_ENTRY(device_element) list; 125 struct linux_device_handler entry; 126 }; 127 128 static TAILQ_HEAD(, device_element) devices = 129 TAILQ_HEAD_INITIALIZER(devices); 130 131 static struct linux_device_handler null_handler = 132 { "mem", "mem", "null", "null", 1, 3, 1}; 133 134 DATA_SET(linux_device_handler_set, null_handler); 135 136 char * 137 linux_driver_get_name_dev(device_t dev) 138 { 139 struct device_element *de; 140 const char *device_name = device_get_name(dev); 141 142 if (device_name == NULL) 143 return (NULL); 144 TAILQ_FOREACH(de, &devices, list) { 145 if (strcmp(device_name, de->entry.bsd_driver_name) == 0) 146 return (de->entry.linux_driver_name); 147 } 148 149 return (NULL); 150 } 151 152 int 153 linux_driver_get_major_minor(const char *node, int *major, int *minor) 154 { 155 struct device_element *de; 156 unsigned long devno; 157 size_t sz; 158 159 if (node == NULL || major == NULL || minor == NULL) 160 return (1); 161 162 sz = sizeof("pts/") - 1; 163 if (strncmp(node, "pts/", sz) == 0 && node[sz] != '\0') { 164 /* 165 * Linux checks major and minors of the slave device 166 * to make sure it's a pty device, so let's make him 167 * believe it is. 168 */ 169 devno = strtoul(node + sz, NULL, 10); 170 *major = 136 + (devno / 256); 171 *minor = devno % 256; 172 return (0); 173 } 174 175 sz = sizeof("dri/card") - 1; 176 if (strncmp(node, "dri/card", sz) == 0 && node[sz] != '\0') { 177 devno = strtoul(node + sz, NULL, 10); 178 *major = 226 + (devno / 256); 179 *minor = devno % 256; 180 return (0); 181 } 182 sz = sizeof("dri/controlD") - 1; 183 if (strncmp(node, "dri/controlD", sz) == 0 && node[sz] != '\0') { 184 devno = strtoul(node + sz, NULL, 10); 185 *major = 226 + (devno / 256); 186 *minor = devno % 256; 187 return (0); 188 } 189 sz = sizeof("dri/renderD") - 1; 190 if (strncmp(node, "dri/renderD", sz) == 0 && node[sz] != '\0') { 191 devno = strtoul(node + sz, NULL, 10); 192 *major = 226 + (devno / 256); 193 *minor = devno % 256; 194 return (0); 195 } 196 sz = sizeof("drm/") - 1; 197 if (strncmp(node, "drm/", sz) == 0 && node[sz] != '\0') { 198 devno = strtoul(node + sz, NULL, 10); 199 *major = 226 + (devno / 256); 200 *minor = devno % 256; 201 return (0); 202 } 203 204 TAILQ_FOREACH(de, &devices, list) { 205 if (strcmp(node, de->entry.bsd_device_name) == 0) { 206 *major = de->entry.linux_major; 207 *minor = de->entry.linux_minor; 208 return (0); 209 } 210 } 211 212 return (1); 213 } 214 215 int 216 linux_vn_get_major_minor(const struct vnode *vp, int *major, int *minor) 217 { 218 int error; 219 220 if (vp->v_type != VCHR) 221 return (ENOTBLK); 222 dev_lock(); 223 if (vp->v_rdev == NULL) { 224 dev_unlock(); 225 return (ENXIO); 226 } 227 error = linux_driver_get_major_minor(devtoname(vp->v_rdev), 228 major, minor); 229 dev_unlock(); 230 return (error); 231 } 232 233 void 234 translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) 235 { 236 int major, minor; 237 238 if (vn_isdisk(vp)) { 239 sb->st_mode &= ~S_IFMT; 240 sb->st_mode |= S_IFBLK; 241 } 242 243 /* 244 * Return the same st_dev for every devfs instance. The reason 245 * for this is to work around an idiosyncrasy of glibc getttynam() 246 * implementation: it checks whether st_dev returned for fd 0 247 * is the same as st_dev returned for the target of /proc/self/fd/0 248 * symlink, and with linux chroots having their own devfs instance, 249 * the check will fail if you chroot into it. 250 */ 251 if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc) 252 sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0]; 253 254 if (linux_vn_get_major_minor(vp, &major, &minor) == 0) 255 sb->st_rdev = makedev(major, minor); 256 } 257 258 char * 259 linux_get_char_devices(void) 260 { 261 struct device_element *de; 262 char *temp, *string, *last; 263 char formated[256]; 264 int current_size = 0, string_size = 1024; 265 266 string = malloc(string_size, M_LINUX, M_WAITOK); 267 string[0] = '\000'; 268 last = ""; 269 TAILQ_FOREACH(de, &devices, list) { 270 if (!de->entry.linux_char_device) 271 continue; 272 temp = string; 273 if (strcmp(last, de->entry.bsd_driver_name) != 0) { 274 last = de->entry.bsd_driver_name; 275 276 snprintf(formated, sizeof(formated), "%3d %s\n", 277 de->entry.linux_major, 278 de->entry.linux_device_name); 279 if (strlen(formated) + current_size 280 >= string_size) { 281 string_size *= 2; 282 string = malloc(string_size, 283 M_LINUX, M_WAITOK); 284 bcopy(temp, string, current_size); 285 free(temp, M_LINUX); 286 } 287 strcat(string, formated); 288 current_size = strlen(string); 289 } 290 } 291 292 return (string); 293 } 294 295 void 296 linux_free_get_char_devices(char *string) 297 { 298 299 free(string, M_LINUX); 300 } 301 302 static int linux_major_starting = 200; 303 304 int 305 linux_device_register_handler(struct linux_device_handler *d) 306 { 307 struct device_element *de; 308 309 if (d == NULL) 310 return (EINVAL); 311 312 de = malloc(sizeof(*de), M_LINUX, M_WAITOK); 313 if (d->linux_major < 0) { 314 d->linux_major = linux_major_starting++; 315 } 316 bcopy(d, &de->entry, sizeof(*d)); 317 318 /* Add the element to the list, sorted on span. */ 319 TAILQ_INSERT_TAIL(&devices, de, list); 320 321 return (0); 322 } 323 324 int 325 linux_device_unregister_handler(struct linux_device_handler *d) 326 { 327 struct device_element *de; 328 329 if (d == NULL) 330 return (EINVAL); 331 332 TAILQ_FOREACH(de, &devices, list) { 333 if (bcmp(d, &de->entry, sizeof(*d)) == 0) { 334 TAILQ_REMOVE(&devices, de, list); 335 free(de, M_LINUX); 336 337 return (0); 338 } 339 } 340 341 return (EINVAL); 342 } 343