1 /*- 2 * Copyright (c) 1999 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_compat.h" 33 #include "opt_kdtrace.h" 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/sdt.h> 38 #include <sys/systm.h> 39 #include <sys/sysctl.h> 40 #include <sys/proc.h> 41 #include <sys/malloc.h> 42 #include <sys/mount.h> 43 #include <sys/jail.h> 44 #include <sys/lock.h> 45 #include <sys/mutex.h> 46 #include <sys/sx.h> 47 48 #ifdef COMPAT_LINUX32 49 #include <machine/../linux32/linux.h> 50 #else 51 #include <machine/../linux/linux.h> 52 #endif 53 #include <compat/linux/linux_dtrace.h> 54 #include <compat/linux/linux_mib.h> 55 #include <compat/linux/linux_misc.h> 56 57 /* DTrace init */ 58 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 59 60 /** 61 * DTrace probes in this module. 62 */ 63 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osname, entry); 64 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, sysctl_string_error, "int"); 65 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, return, "int"); 66 67 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osrelease, entry); 68 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, sysctl_string_error, "int"); 69 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, return, "int"); 70 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_oss_version, entry); 71 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, sysctl_string_error, 72 "int"); 73 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, return, "int"); 74 LIN_SDT_PROBE_DEFINE2(mib, linux_map_osrel, entry, "char *", "int *"); 75 LIN_SDT_PROBE_DEFINE1(mib, linux_map_osrel, return, "int"); 76 LIN_SDT_PROBE_DEFINE2(mib, linux_get_prison, entry, "struct prison *", 77 "struct prison **"); 78 LIN_SDT_PROBE_DEFINE1(mib, linux_get_prison, return, "struct linux_prison *"); 79 LIN_SDT_PROBE_DEFINE2(mib, linux_alloc_prison, entry, "struct prison *", 80 "struct linux_prison **"); 81 LIN_SDT_PROBE_DEFINE1(mib, linux_alloc_prison, return, "int"); 82 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_create, entry, "void *", "void *"); 83 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, vfs_copyopt_error, "int"); 84 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, return, "int"); 85 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_check, entry, "void *", "void *"); 86 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_copyopt_error, "int"); 87 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_getopt_error, "int"); 88 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, return, "int"); 89 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_set, entry, "void *", "void *"); 90 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_copyopt_error, "int"); 91 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_getopt_error, "int"); 92 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, return, "int"); 93 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_get, entry, "void *", "void *"); 94 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopt_error, "int"); 95 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopts_error, "int"); 96 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, return, "int"); 97 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_destructor, entry, "void *"); 98 LIN_SDT_PROBE_DEFINE0(mib, linux_prison_destructor, return); 99 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, entry); 100 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, return); 101 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, entry); 102 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, return); 103 LIN_SDT_PROBE_DEFINE2(mib, linux_get_osname, entry, "struct thread *", 104 "char *"); 105 LIN_SDT_PROBE_DEFINE0(mib, linux_get_osname, return); 106 LIN_SDT_PROBE_DEFINE2(mib, linux_set_osname, entry, "struct thread *", 107 "char *"); 108 LIN_SDT_PROBE_DEFINE1(mib, linux_set_osname, return, "int"); 109 LIN_SDT_PROBE_DEFINE2(mib, linux_get_osrelease, entry, "struct thread *", 110 "char *"); 111 LIN_SDT_PROBE_DEFINE0(mib, linux_get_osrelease, return); 112 LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, entry, "struct thread *"); 113 LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, return, "int"); 114 LIN_SDT_PROBE_DEFINE2(mib, linux_set_osrelease, entry, "struct thread *", 115 "char *"); 116 LIN_SDT_PROBE_DEFINE1(mib, linux_set_osrelease, return, "int"); 117 LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, entry, "struct thread *"); 118 LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, return, "int"); 119 120 LIN_SDT_PROBE_DEFINE2(mib, linux_set_oss_version, entry, "struct thread *", 121 "int"); 122 LIN_SDT_PROBE_DEFINE1(mib, linux_set_oss_version, return, "int"); 123 124 struct linux_prison { 125 char pr_osname[LINUX_MAX_UTSNAME]; 126 char pr_osrelease[LINUX_MAX_UTSNAME]; 127 int pr_oss_version; 128 int pr_osrel; 129 }; 130 131 static struct linux_prison lprison0 = { 132 .pr_osname = "Linux", 133 .pr_osrelease = "2.6.16", 134 .pr_oss_version = 0x030600, 135 .pr_osrel = 2006016 136 }; 137 138 static unsigned linux_osd_jail_slot; 139 140 static SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0, 141 "Linux mode"); 142 143 static int linux_set_osname(struct thread *td, char *osname); 144 static int linux_set_osrelease(struct thread *td, char *osrelease); 145 static int linux_set_oss_version(struct thread *td, int oss_version); 146 147 static int 148 linux_sysctl_osname(SYSCTL_HANDLER_ARGS) 149 { 150 char osname[LINUX_MAX_UTSNAME]; 151 int error; 152 153 LIN_SDT_PROBE0(mib, linux_sysctl_osname, entry); 154 155 linux_get_osname(req->td, osname); 156 error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); 157 if (error != 0 || req->newptr == NULL) { 158 LIN_SDT_PROBE1(mib, linux_sysctl_osname, sysctl_string_error, 159 error); 160 LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error); 161 return (error); 162 } 163 error = linux_set_osname(req->td, osname); 164 165 LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error); 166 return (error); 167 } 168 169 SYSCTL_PROC(_compat_linux, OID_AUTO, osname, 170 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 171 0, 0, linux_sysctl_osname, "A", 172 "Linux kernel OS name"); 173 174 static int 175 linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) 176 { 177 char osrelease[LINUX_MAX_UTSNAME]; 178 int error; 179 180 LIN_SDT_PROBE0(mib, linux_sysctl_osrelease, entry); 181 182 linux_get_osrelease(req->td, osrelease); 183 error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); 184 if (error != 0 || req->newptr == NULL) { 185 LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, sysctl_string_error, 186 error); 187 LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error); 188 return (error); 189 } 190 error = linux_set_osrelease(req->td, osrelease); 191 192 LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error); 193 return (error); 194 } 195 196 SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease, 197 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 198 0, 0, linux_sysctl_osrelease, "A", 199 "Linux kernel OS release"); 200 201 static int 202 linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS) 203 { 204 int oss_version; 205 int error; 206 207 LIN_SDT_PROBE0(mib, linux_sysctl_oss_version, entry); 208 209 oss_version = linux_get_oss_version(req->td); 210 error = sysctl_handle_int(oidp, &oss_version, 0, req); 211 if (error != 0 || req->newptr == NULL) { 212 LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, 213 sysctl_string_error, error); 214 LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error); 215 return (error); 216 } 217 error = linux_set_oss_version(req->td, oss_version); 218 219 LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error); 220 return (error); 221 } 222 223 SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, 224 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 225 0, 0, linux_sysctl_oss_version, "I", 226 "Linux OSS version"); 227 228 /* 229 * Map the osrelease into integer 230 */ 231 static int 232 linux_map_osrel(char *osrelease, int *osrel) 233 { 234 char *sep, *eosrelease; 235 int len, v0, v1, v2, v; 236 237 LIN_SDT_PROBE2(mib, linux_map_osrel, entry, osrelease, osrel); 238 239 len = strlen(osrelease); 240 eosrelease = osrelease + len; 241 v0 = strtol(osrelease, &sep, 10); 242 if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') { 243 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); 244 return (EINVAL); 245 } 246 osrelease = sep + 1; 247 v1 = strtol(osrelease, &sep, 10); 248 if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') { 249 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); 250 return (EINVAL); 251 } 252 osrelease = sep + 1; 253 v2 = strtol(osrelease, &sep, 10); 254 if (osrelease == sep || sep != eosrelease) { 255 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); 256 return (EINVAL); 257 } 258 259 v = v0 * 1000000 + v1 * 1000 + v2; 260 if (v < 1000000) { 261 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); 262 return (EINVAL); 263 } 264 265 *osrel = v; 266 267 LIN_SDT_PROBE1(mib, linux_map_osrel, return, 0); 268 return (0); 269 } 270 271 /* 272 * Find a prison with Linux info. 273 * Return the Linux info and the (locked) prison. 274 */ 275 static struct linux_prison * 276 linux_find_prison(struct prison *spr, struct prison **prp) 277 { 278 struct prison *pr; 279 struct linux_prison *lpr; 280 281 LIN_SDT_PROBE2(mib, linux_get_prison, entry, spr, prp); 282 283 if (!linux_osd_jail_slot) 284 /* In case osd_register failed. */ 285 spr = &prison0; 286 for (pr = spr;; pr = pr->pr_parent) { 287 mtx_lock(&pr->pr_mtx); 288 lpr = (pr == &prison0) 289 ? &lprison0 290 : osd_jail_get(pr, linux_osd_jail_slot); 291 if (lpr != NULL) 292 break; 293 mtx_unlock(&pr->pr_mtx); 294 } 295 *prp = pr; 296 297 LIN_SDT_PROBE1(mib, linux_get_prison, return, lpr); 298 return (lpr); 299 } 300 301 /* 302 * Ensure a prison has its own Linux info. If lprp is non-null, point it to 303 * the Linux info and lock the prison. 304 */ 305 static int 306 linux_alloc_prison(struct prison *pr, struct linux_prison **lprp) 307 { 308 struct prison *ppr; 309 struct linux_prison *lpr, *nlpr; 310 int error; 311 312 LIN_SDT_PROBE2(mib, linux_alloc_prison, entry, pr, lprp); 313 314 /* If this prison already has Linux info, return that. */ 315 error = 0; 316 lpr = linux_find_prison(pr, &ppr); 317 if (ppr == pr) 318 goto done; 319 /* 320 * Allocate a new info record. Then check again, in case something 321 * changed during the allocation. 322 */ 323 mtx_unlock(&ppr->pr_mtx); 324 nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK); 325 lpr = linux_find_prison(pr, &ppr); 326 if (ppr == pr) { 327 free(nlpr, M_PRISON); 328 goto done; 329 } 330 /* Inherit the initial values from the ancestor. */ 331 mtx_lock(&pr->pr_mtx); 332 error = osd_jail_set(pr, linux_osd_jail_slot, nlpr); 333 if (error == 0) { 334 bcopy(lpr, nlpr, sizeof(*lpr)); 335 lpr = nlpr; 336 } else { 337 free(nlpr, M_PRISON); 338 lpr = NULL; 339 } 340 mtx_unlock(&ppr->pr_mtx); 341 done: 342 if (lprp != NULL) 343 *lprp = lpr; 344 else 345 mtx_unlock(&pr->pr_mtx); 346 347 LIN_SDT_PROBE1(mib, linux_alloc_prison, return, error); 348 return (error); 349 } 350 351 /* 352 * Jail OSD methods for Linux prison data. 353 */ 354 static int 355 linux_prison_create(void *obj, void *data) 356 { 357 struct prison *pr = obj; 358 struct vfsoptlist *opts = data; 359 int jsys, error; 360 361 LIN_SDT_PROBE2(mib, linux_prison_create, entry, obj, data); 362 363 error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); 364 if (error != 0) { 365 LIN_SDT_PROBE1(mib, linux_prison_create, vfs_copyopt_error, 366 error); 367 } else if (jsys == JAIL_SYS_INHERIT) { 368 LIN_SDT_PROBE1(mib, linux_prison_create, return, 0); 369 return (0); 370 } 371 /* 372 * Inherit a prison's initial values from its parent 373 * (different from JAIL_SYS_INHERIT which also inherits changes). 374 */ 375 error = linux_alloc_prison(pr, NULL); 376 377 LIN_SDT_PROBE1(mib, linux_prison_create, return, error); 378 return (error); 379 } 380 381 static int 382 linux_prison_check(void *obj __unused, void *data) 383 { 384 struct vfsoptlist *opts = data; 385 char *osname, *osrelease; 386 int error, jsys, len, osrel, oss_version; 387 388 LIN_SDT_PROBE2(mib, linux_prison_check, entry, obj, data); 389 390 /* Check that the parameters are correct. */ 391 error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); 392 if (error != 0) { 393 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, 394 error); 395 } 396 if (error != ENOENT) { 397 if (error != 0) { 398 LIN_SDT_PROBE1(mib, linux_prison_check, return, error); 399 return (error); 400 } 401 if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) { 402 LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); 403 return (EINVAL); 404 } 405 } 406 error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); 407 if (error != 0) { 408 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error, 409 error); 410 } 411 if (error != ENOENT) { 412 if (error != 0) { 413 LIN_SDT_PROBE1(mib, linux_prison_check, return, error); 414 return (error); 415 } 416 if (len == 0 || osname[len - 1] != '\0') { 417 LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); 418 return (EINVAL); 419 } 420 if (len > LINUX_MAX_UTSNAME) { 421 vfs_opterror(opts, "linux.osname too long"); 422 LIN_SDT_PROBE1(mib, linux_prison_check, return, 423 ENAMETOOLONG); 424 return (ENAMETOOLONG); 425 } 426 } 427 error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); 428 if (error != 0) { 429 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error, 430 error); 431 } 432 if (error != ENOENT) { 433 if (error != 0) { 434 LIN_SDT_PROBE1(mib, linux_prison_check, return, error); 435 return (error); 436 } 437 if (len == 0 || osrelease[len - 1] != '\0') { 438 LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); 439 return (EINVAL); 440 } 441 if (len > LINUX_MAX_UTSNAME) { 442 vfs_opterror(opts, "linux.osrelease too long"); 443 LIN_SDT_PROBE1(mib, linux_prison_check, return, 444 ENAMETOOLONG); 445 return (ENAMETOOLONG); 446 } 447 error = linux_map_osrel(osrelease, &osrel); 448 if (error != 0) { 449 vfs_opterror(opts, "linux.osrelease format error"); 450 LIN_SDT_PROBE1(mib, linux_prison_check, return, error); 451 return (error); 452 } 453 } 454 error = vfs_copyopt(opts, "linux.oss_version", &oss_version, 455 sizeof(oss_version)); 456 if (error != 0) 457 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, error); 458 459 if (error == ENOENT) 460 error = 0; 461 LIN_SDT_PROBE1(mib, linux_prison_check, return, error); 462 return (error); 463 } 464 465 static int 466 linux_prison_set(void *obj, void *data) 467 { 468 struct linux_prison *lpr; 469 struct prison *pr = obj; 470 struct vfsoptlist *opts = data; 471 char *osname, *osrelease; 472 int error, gotversion, jsys, len, oss_version; 473 474 LIN_SDT_PROBE2(mib, linux_prison_set, entry, obj, data); 475 476 /* Set the parameters, which should be correct. */ 477 error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); 478 if (error != 0) 479 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error); 480 if (error == ENOENT) 481 jsys = -1; 482 error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); 483 if (error != 0) 484 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error); 485 if (error == ENOENT) 486 osname = NULL; 487 else 488 jsys = JAIL_SYS_NEW; 489 error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); 490 if (error != 0) 491 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error); 492 if (error == ENOENT) 493 osrelease = NULL; 494 else 495 jsys = JAIL_SYS_NEW; 496 error = vfs_copyopt(opts, "linux.oss_version", &oss_version, 497 sizeof(oss_version)); 498 if (error != 0) 499 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error); 500 if (error == ENOENT) 501 gotversion = 0; 502 else { 503 gotversion = 1; 504 jsys = JAIL_SYS_NEW; 505 } 506 switch (jsys) { 507 case JAIL_SYS_INHERIT: 508 /* "linux=inherit": inherit the parent's Linux info. */ 509 mtx_lock(&pr->pr_mtx); 510 osd_jail_del(pr, linux_osd_jail_slot); 511 mtx_unlock(&pr->pr_mtx); 512 break; 513 case JAIL_SYS_NEW: 514 /* 515 * "linux=new" or "linux.*": 516 * the prison gets its own Linux info. 517 */ 518 error = linux_alloc_prison(pr, &lpr); 519 if (error) { 520 mtx_unlock(&pr->pr_mtx); 521 LIN_SDT_PROBE1(mib, linux_prison_set, return, error); 522 return (error); 523 } 524 if (osrelease) { 525 error = linux_map_osrel(osrelease, &lpr->pr_osrel); 526 if (error) { 527 mtx_unlock(&pr->pr_mtx); 528 LIN_SDT_PROBE1(mib, linux_prison_set, return, 529 error); 530 return (error); 531 } 532 strlcpy(lpr->pr_osrelease, osrelease, 533 LINUX_MAX_UTSNAME); 534 } 535 if (osname) 536 strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); 537 if (gotversion) 538 lpr->pr_oss_version = oss_version; 539 mtx_unlock(&pr->pr_mtx); 540 } 541 542 LIN_SDT_PROBE1(mib, linux_prison_set, return, 0); 543 return (0); 544 } 545 546 SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters"); 547 SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME, 548 "Jail Linux kernel OS name"); 549 SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME, 550 "Jail Linux kernel OS release"); 551 SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW, 552 "I", "Jail Linux OSS version"); 553 554 static int 555 linux_prison_get(void *obj, void *data) 556 { 557 struct linux_prison *lpr; 558 struct prison *ppr; 559 struct prison *pr = obj; 560 struct vfsoptlist *opts = data; 561 int error, i; 562 563 static int version0; 564 565 LIN_SDT_PROBE2(mib, linux_prison_get, entry, obj, data); 566 567 /* See if this prison is the one with the Linux info. */ 568 lpr = linux_find_prison(pr, &ppr); 569 i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 570 error = vfs_setopt(opts, "linux", &i, sizeof(i)); 571 if (error != 0) { 572 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, error); 573 if (error != ENOENT) 574 goto done; 575 } 576 if (i) { 577 error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); 578 if (error != 0) { 579 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, 580 error); 581 if (error != ENOENT) 582 goto done; 583 } 584 error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); 585 if (error != 0) { 586 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, 587 error); 588 if (error != ENOENT) 589 goto done; 590 } 591 error = vfs_setopt(opts, "linux.oss_version", 592 &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); 593 if (error != 0) { 594 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, 595 error); 596 if(error != ENOENT) 597 goto done; 598 } 599 } else { 600 /* 601 * If this prison is inheriting its Linux info, report 602 * empty/zero parameters. 603 */ 604 error = vfs_setopts(opts, "linux.osname", ""); 605 if (error != 0) { 606 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, 607 error); 608 if(error != ENOENT) 609 goto done; 610 } 611 error = vfs_setopts(opts, "linux.osrelease", ""); 612 if (error != 0) { 613 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, 614 error); 615 if(error != ENOENT) 616 goto done; 617 } 618 error = vfs_setopt(opts, "linux.oss_version", &version0, 619 sizeof(lpr->pr_oss_version)); 620 if (error != 0) { 621 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, 622 error); 623 if(error != ENOENT) 624 goto done; 625 } 626 } 627 error = 0; 628 629 done: 630 mtx_unlock(&ppr->pr_mtx); 631 632 LIN_SDT_PROBE1(mib, linux_prison_get, return, error); 633 return (error); 634 } 635 636 static void 637 linux_prison_destructor(void *data) 638 { 639 640 LIN_SDT_PROBE1(mib, linux_prison_destructor, entry, data); 641 free(data, M_PRISON); 642 LIN_SDT_PROBE0(mib, linux_prison_destructor, return); 643 } 644 645 void 646 linux_osd_jail_register(void) 647 { 648 struct prison *pr; 649 osd_method_t methods[PR_MAXMETHOD] = { 650 [PR_METHOD_CREATE] = linux_prison_create, 651 [PR_METHOD_GET] = linux_prison_get, 652 [PR_METHOD_SET] = linux_prison_set, 653 [PR_METHOD_CHECK] = linux_prison_check 654 }; 655 656 LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry); 657 658 linux_osd_jail_slot = 659 osd_jail_register(linux_prison_destructor, methods); 660 if (linux_osd_jail_slot > 0) { 661 /* Copy the system linux info to any current prisons. */ 662 sx_xlock(&allprison_lock); 663 TAILQ_FOREACH(pr, &allprison, pr_list) 664 (void)linux_alloc_prison(pr, NULL); 665 sx_xunlock(&allprison_lock); 666 } 667 668 LIN_SDT_PROBE0(mib, linux_osd_jail_register, return); 669 } 670 671 void 672 linux_osd_jail_deregister(void) 673 { 674 675 LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry); 676 677 if (linux_osd_jail_slot) 678 osd_jail_deregister(linux_osd_jail_slot); 679 680 LIN_SDT_PROBE0(mib, linux_osd_jail_register, return); 681 } 682 683 void 684 linux_get_osname(struct thread *td, char *dst) 685 { 686 struct prison *pr; 687 struct linux_prison *lpr; 688 689 LIN_SDT_PROBE2(mib, linux_get_osname, entry, td, dst); 690 691 lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 692 bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); 693 mtx_unlock(&pr->pr_mtx); 694 695 LIN_SDT_PROBE0(mib, linux_get_osname, return); 696 } 697 698 static int 699 linux_set_osname(struct thread *td, char *osname) 700 { 701 struct prison *pr; 702 struct linux_prison *lpr; 703 704 LIN_SDT_PROBE2(mib, linux_set_osname, entry, td, osname); 705 706 lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 707 strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); 708 mtx_unlock(&pr->pr_mtx); 709 710 LIN_SDT_PROBE1(mib, linux_set_osname, return, 0); 711 return (0); 712 } 713 714 void 715 linux_get_osrelease(struct thread *td, char *dst) 716 { 717 struct prison *pr; 718 struct linux_prison *lpr; 719 720 LIN_SDT_PROBE2(mib, linux_get_osrelease, entry, td, dst); 721 722 lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 723 bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME); 724 mtx_unlock(&pr->pr_mtx); 725 726 LIN_SDT_PROBE0(mib, linux_get_osrelease, return); 727 } 728 729 int 730 linux_kernver(struct thread *td) 731 { 732 struct prison *pr; 733 struct linux_prison *lpr; 734 int osrel; 735 736 LIN_SDT_PROBE1(mib, linux_kernver, entry, td); 737 738 lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 739 osrel = lpr->pr_osrel; 740 mtx_unlock(&pr->pr_mtx); 741 742 LIN_SDT_PROBE1(mib, linux_kernver, return, osrel); 743 return (osrel); 744 } 745 746 static int 747 linux_set_osrelease(struct thread *td, char *osrelease) 748 { 749 struct prison *pr; 750 struct linux_prison *lpr; 751 int error; 752 753 LIN_SDT_PROBE2(mib, linux_set_osrelease, entry, td, osrelease); 754 755 lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 756 error = linux_map_osrel(osrelease, &lpr->pr_osrel); 757 if (error == 0) 758 strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME); 759 mtx_unlock(&pr->pr_mtx); 760 761 LIN_SDT_PROBE1(mib, linux_set_osrelease, return, error); 762 return (error); 763 } 764 765 int 766 linux_get_oss_version(struct thread *td) 767 { 768 struct prison *pr; 769 struct linux_prison *lpr; 770 int version; 771 772 LIN_SDT_PROBE1(mib, linux_get_oss_version, entry, td); 773 774 lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 775 version = lpr->pr_oss_version; 776 mtx_unlock(&pr->pr_mtx); 777 778 LIN_SDT_PROBE1(mib, linux_get_oss_version, return, version); 779 return (version); 780 } 781 782 static int 783 linux_set_oss_version(struct thread *td, int oss_version) 784 { 785 struct prison *pr; 786 struct linux_prison *lpr; 787 788 LIN_SDT_PROBE2(mib, linux_set_oss_version, entry, td, oss_version); 789 790 lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 791 lpr->pr_oss_version = oss_version; 792 mtx_unlock(&pr->pr_mtx); 793 794 LIN_SDT_PROBE1(mib, linux_set_oss_version, return, 0); 795 return (0); 796 } 797 798 #if defined(DEBUG) || defined(KTR) 799 /* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */ 800 801 u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))]; 802 803 static int 804 linux_debug(int syscall, int toggle, int global) 805 { 806 807 if (global) { 808 char c = toggle ? 0 : 0xff; 809 810 memset(linux_debug_map, c, sizeof(linux_debug_map)); 811 return (0); 812 } 813 if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL) 814 return (EINVAL); 815 if (toggle) 816 clrbit(linux_debug_map, syscall); 817 else 818 setbit(linux_debug_map, syscall); 819 return (0); 820 } 821 822 /* 823 * Usage: sysctl linux.debug=<syscall_nr>.<0/1> 824 * 825 * E.g.: sysctl linux.debug=21.0 826 * 827 * As a special case, syscall "all" will apply to all syscalls globally. 828 */ 829 #define LINUX_MAX_DEBUGSTR 16 830 static int 831 linux_sysctl_debug(SYSCTL_HANDLER_ARGS) 832 { 833 char value[LINUX_MAX_DEBUGSTR], *p; 834 int error, sysc, toggle; 835 int global = 0; 836 837 value[0] = '\0'; 838 error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); 839 if (error || req->newptr == NULL) 840 return (error); 841 for (p = value; *p != '\0' && *p != '.'; p++); 842 if (*p == '\0') 843 return (EINVAL); 844 *p++ = '\0'; 845 sysc = strtol(value, NULL, 0); 846 toggle = strtol(p, NULL, 0); 847 if (strcmp(value, "all") == 0) 848 global = 1; 849 error = linux_debug(sysc, toggle, global); 850 return (error); 851 } 852 853 SYSCTL_PROC(_compat_linux, OID_AUTO, debug, 854 CTLTYPE_STRING | CTLFLAG_RW, 855 0, 0, linux_sysctl_debug, "A", 856 "Linux debugging control"); 857 858 #endif /* DEBUG || KTR */ 859