1 /* 2 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Alex Hornung <ahornung@gmail.com> 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/ioccom.h> 40 #include <sys/lock.h> 41 #include <sys/spinlock2.h> 42 #include <sys/fcntl.h> 43 #include <sys/device.h> 44 #include <sys/mount.h> 45 #include <sys/devfs.h> 46 #include <sys/devfs_rules.h> 47 48 MALLOC_DECLARE(M_DEVFS); 49 50 #if 0 51 static int WildCmp(const char *w, const char *s); 52 #endif 53 static int WildCaseCmp(const char *w, const char *s); 54 static int wildCmp(const char **mary, int d, const char *w, const char *s); 55 static int wildCaseCmp(const char **mary, int d, const char *w, const char *s); 56 57 static d_open_t devfs_dev_open; 58 static d_close_t devfs_dev_close; 59 static d_ioctl_t devfs_dev_ioctl; 60 61 static struct devfs_rule *devfs_rule_alloc(struct devfs_rule_ioctl *); 62 static void devfs_rule_free(struct devfs_rule *); 63 static void devfs_rule_insert(struct devfs_rule_ioctl *); 64 static void devfs_rule_remove(struct devfs_rule *); 65 static void devfs_rule_clear(struct devfs_rule_ioctl *); 66 static void devfs_rule_create_link(struct devfs_node *, struct devfs_rule *); 67 static int devfs_rule_checkname(struct devfs_rule *, struct devfs_node *); 68 69 static struct objcache *devfs_rule_cache; 70 static struct lock devfs_rule_lock; 71 72 static struct objcache_malloc_args devfs_rule_malloc_args = { 73 sizeof(struct devfs_rule), M_DEVFS }; 74 75 static cdev_t devfs_dev; 76 static struct devfs_rule_head devfs_rule_list = 77 TAILQ_HEAD_INITIALIZER(devfs_rule_list); 78 79 static struct dev_ops devfs_dev_ops = { 80 { "devfs", 0, 0 }, 81 .d_open = devfs_dev_open, 82 .d_close = devfs_dev_close, 83 .d_ioctl = devfs_dev_ioctl 84 }; 85 86 87 static struct devfs_rule * 88 devfs_rule_alloc(struct devfs_rule_ioctl *templ) 89 { 90 struct devfs_rule *rule; 91 size_t len; 92 93 rule = objcache_get(devfs_rule_cache, M_WAITOK); 94 memset(rule, 0, sizeof(struct devfs_rule)); 95 96 len = strlen(templ->mntpoint); 97 if (len > 0) { 98 rule->mntpoint = kstrdup(templ->mntpoint, M_DEVFS); 99 rule->mntpointlen = len; 100 } 101 102 if (templ->rule_type == DEVFS_RULE_NAME) { 103 len = strlen(templ->name); 104 if (len > 0) { 105 rule->name = kstrdup(templ->name, M_DEVFS); 106 rule->namlen = len; 107 } 108 } 109 110 if (templ->rule_cmd == DEVFS_RULE_LINK) { 111 len = strlen(templ->linkname); 112 if (len > 0) { 113 rule->linkname = kstrdup(templ->linkname, M_DEVFS); 114 rule->linknamlen = len; 115 } 116 } 117 118 rule->rule_type = templ->rule_type; 119 rule->rule_cmd = templ->rule_cmd; 120 rule->dev_type = templ->dev_type; 121 rule->mode = templ->mode; 122 rule->uid = templ->uid; 123 rule->gid = templ->gid; 124 125 return rule; 126 } 127 128 129 static void 130 devfs_rule_free(struct devfs_rule *rule) 131 { 132 if (rule->mntpoint != NULL) { 133 kfree(rule->mntpoint, M_DEVFS); 134 } 135 136 if (rule->name != NULL) { 137 kfree(rule->name, M_DEVFS); 138 } 139 140 if (rule->linkname != NULL) { 141 kfree(rule->linkname, M_DEVFS); 142 } 143 objcache_put(devfs_rule_cache, rule); 144 } 145 146 147 static void 148 devfs_rule_insert(struct devfs_rule_ioctl *templ) 149 { 150 struct devfs_rule *rule; 151 152 rule = devfs_rule_alloc(templ); 153 154 lockmgr(&devfs_rule_lock, LK_EXCLUSIVE); 155 TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link); 156 lockmgr(&devfs_rule_lock, LK_RELEASE); 157 } 158 159 160 static void 161 devfs_rule_remove(struct devfs_rule *rule) 162 { 163 TAILQ_REMOVE(&devfs_rule_list, rule, link); 164 devfs_rule_free(rule); 165 } 166 167 168 static void 169 devfs_rule_clear(struct devfs_rule_ioctl *templ) 170 { 171 struct devfs_rule *rule1, *rule2; 172 size_t mntpointlen = strlen(templ->mntpoint); 173 174 lockmgr(&devfs_rule_lock, LK_EXCLUSIVE); 175 TAILQ_FOREACH_MUTABLE(rule1, &devfs_rule_list, link, rule2) { 176 if ((templ->mntpoint[0] == '*') || 177 ( (mntpointlen == rule1->mntpointlen) && 178 (!memcmp(templ->mntpoint, rule1->mntpoint, mntpointlen)) )) { 179 devfs_rule_remove(rule1); 180 } 181 } 182 lockmgr(&devfs_rule_lock, LK_RELEASE); 183 } 184 185 186 void * 187 devfs_rule_reset_node(struct devfs_node *node, void *unused) 188 { 189 /* 190 * Don't blindly unhide all devices, some, like unix98 pty masters, 191 * haven't been hidden by a rule. 192 */ 193 if (node->flags & DEVFS_RULE_HIDDEN) 194 node->flags &= ~(DEVFS_HIDDEN | DEVFS_RULE_HIDDEN); 195 196 if ((node->node_type == Plink) && (node->flags & DEVFS_RULE_CREATED)) { 197 KKASSERT(node->link_target); 198 node->flags &= ~DEVFS_RULE_CREATED; 199 --node->link_target->nlinks; 200 devfs_gc(node); 201 } else if ((node->node_type == Pdev) && (node->d_dev)) { 202 node->uid = node->d_dev->si_uid; 203 node->gid = node->d_dev->si_gid; 204 node->mode = node->d_dev->si_perms; 205 } 206 207 return NULL; 208 } 209 210 static void 211 devfs_rule_create_link(struct devfs_node *node, struct devfs_rule *rule) 212 { 213 size_t len = 0; 214 char *path = NULL; 215 char *name, name_buf[PATH_MAX], buf[PATH_MAX]; 216 217 if (rule->name[rule->namlen-1] == '*') { 218 devfs_resolve_name_path(rule->name, name_buf, &path, &name); 219 len = strlen(name); 220 --len; 221 ksnprintf(buf, sizeof(buf), "%s%s", 222 rule->linkname, node->d_dir.d_name+len); 223 devfs_alias_create(buf, node, 1); 224 } else { 225 devfs_alias_create(rule->linkname, node, 1); 226 } 227 } 228 229 void * 230 devfs_rule_check_apply(struct devfs_node *node, void *unused) 231 { 232 struct devfs_rule *rule; 233 struct mount *mp = node->mp; 234 int applies = 0; 235 int locked = 0; 236 237 /* Check if it is locked already. if not, we acquire the devfs lock */ 238 if (!(lockstatus(&devfs_rule_lock, curthread)) == LK_EXCLUSIVE) { 239 lockmgr(&devfs_rule_lock, LK_EXCLUSIVE); 240 locked = 1; 241 } 242 243 TAILQ_FOREACH(rule, &devfs_rule_list, link) { 244 /* 245 * Skip this rule if it is only intended for jailed mount points 246 * and the current mount point isn't jailed 247 */ 248 if ((rule->rule_type & DEVFS_RULE_JAIL) && 249 (!(DEVFS_MNTDATA(mp)->jailed)) ) 250 continue; 251 252 /* 253 * Skip this rule if it is not intended for jailed mount points 254 * and the current mount point is jailed. 255 */ 256 if (!(rule->rule_type & DEVFS_RULE_JAIL) && 257 (DEVFS_MNTDATA(mp)->jailed)) 258 continue; 259 260 /* 261 * Skip this rule if the mount point specified in the rule doesn't 262 * match the mount point of the node 263 */ 264 if ((rule->mntpoint[0] != '*') && 265 (strcmp(rule->mntpoint, mp->mnt_stat.f_mntonname))) 266 continue; 267 268 /* 269 * Skip this rule if this is a by-type rule and the device flags 270 * don't match the specified device type in the rule 271 */ 272 if ((rule->rule_type & DEVFS_RULE_TYPE) && 273 ( (rule->dev_type == 0) || (!dev_is_good(node->d_dev)) || 274 (!(dev_dflags(node->d_dev) & rule->dev_type))) ) 275 continue; 276 277 /* 278 * Skip this rule if this is a by-name rule and the node name 279 * doesn't match the wildcard string in the rule 280 */ 281 if ((rule->rule_type & DEVFS_RULE_NAME) && 282 (!devfs_rule_checkname(rule, node)) ) 283 continue; 284 285 if (rule->rule_cmd & DEVFS_RULE_HIDE) { 286 /* 287 * If we should hide the device, we just apply the relevant 288 * hide flag to the node and let devfs do the rest in the 289 * vnops 290 */ 291 if ((node->d_dir.d_namlen == 5) && 292 (!memcmp(node->d_dir.d_name, "devfs", 5))) { 293 /* 294 * Magically avoid /dev/devfs from being hidden, so that one 295 * can still use the rule system even after a "* hide". 296 */ 297 continue; 298 } 299 node->flags |= (DEVFS_HIDDEN | DEVFS_RULE_HIDDEN); 300 applies = 1; 301 } else if (rule->rule_cmd & DEVFS_RULE_SHOW) { 302 /* 303 * Show rule just means that the node should not be hidden, so 304 * what we do is clear the hide flag from the node. 305 */ 306 node->flags &= ~DEVFS_HIDDEN; 307 applies = 1; 308 } else if (rule->rule_cmd & DEVFS_RULE_LINK) { 309 /* 310 * This is a LINK rule, so we tell devfs to create 311 * a link with the correct name to this node. 312 */ 313 devfs_rule_create_link(node, rule); 314 #if 0 315 devfs_alias_create(rule->linkname, node, 1); 316 #endif 317 applies = 1; 318 } else if (rule->rule_cmd & DEVFS_RULE_PERM) { 319 /* 320 * This is a normal ownership/permission rule. We 321 * just apply the permissions and ownership and 322 * we are done. 323 */ 324 node->mode = rule->mode; 325 node->uid = rule->uid; 326 node->gid = rule->gid; 327 applies = 1; 328 } 329 } 330 331 /* If we acquired the lock, we also get rid of it */ 332 if (locked) 333 lockmgr(&devfs_rule_lock, LK_RELEASE); 334 335 return NULL; 336 } 337 338 339 static int 340 devfs_rule_checkname(struct devfs_rule *rule, struct devfs_node *node) 341 { 342 struct devfs_node *parent = DEVFS_MNTDATA(node->mp)->root_node; 343 char *path = NULL; 344 char *name, name_buf[PATH_MAX]; 345 int no_match = 0; 346 347 devfs_resolve_name_path(rule->name, name_buf, &path, &name); 348 parent = devfs_resolve_or_create_path(parent, path, 0); 349 350 if (parent == NULL) 351 return 0; /* no match */ 352 353 /* Check if node is a child of the parent we found */ 354 if (node->parent != parent) 355 return 0; /* no match */ 356 357 #if 0 358 if (rule->rule_type & DEVFS_RULE_LINK) 359 no_match = memcmp(name, node->d_dir.d_name, strlen(name)); 360 else 361 #endif 362 no_match = WildCaseCmp(name, node->d_dir.d_name); 363 364 return !no_match; 365 } 366 367 368 static int 369 devfs_dev_open(struct dev_open_args *ap) 370 { 371 /* 372 * Only allow read-write access. 373 */ 374 if (((ap->a_oflags & FWRITE) == 0) || ((ap->a_oflags & FREAD) == 0)) 375 return(EPERM); 376 377 /* 378 * We don't allow nonblocking access. 379 */ 380 if ((ap->a_oflags & O_NONBLOCK) != 0) { 381 devfs_debug(DEVFS_DEBUG_SHOW, "devfs_dev: can't do nonblocking access\n"); 382 return(ENODEV); 383 } 384 385 return 0; 386 } 387 388 389 static int 390 devfs_dev_close(struct dev_close_args *ap) 391 { 392 return 0; 393 } 394 395 396 static int 397 devfs_dev_ioctl(struct dev_ioctl_args *ap) 398 { 399 int error; 400 struct devfs_rule_ioctl *rule; 401 402 error = 0; 403 rule = (struct devfs_rule_ioctl *)ap->a_data; 404 405 switch(ap->a_cmd) { 406 case DEVFS_RULE_ADD: 407 devfs_rule_insert(rule); 408 break; 409 410 case DEVFS_RULE_APPLY: 411 devfs_apply_rules(rule->mntpoint); 412 break; 413 414 case DEVFS_RULE_CLEAR: 415 devfs_rule_clear(rule); 416 break; 417 418 case DEVFS_RULE_RESET: 419 devfs_reset_rules(rule->mntpoint); 420 break; 421 422 default: 423 error = ENOTTY; /* Inappropriate ioctl for device */ 424 break; 425 } 426 427 return(error); 428 } 429 430 431 static void 432 devfs_dev_init(void *unused) 433 { 434 lockinit(&devfs_rule_lock, "devfs_rule lock", 0, 0); 435 436 devfs_rule_cache = objcache_create("devfs-rule-cache", 0, 0, 437 NULL, NULL, NULL, 438 objcache_malloc_alloc, 439 objcache_malloc_free, 440 &devfs_rule_malloc_args ); 441 442 devfs_dev = make_dev(&devfs_dev_ops, 443 0, 444 UID_ROOT, 445 GID_WHEEL, 446 0600, 447 "devfs"); 448 } 449 450 451 static void 452 devfs_dev_uninit(void *unused) 453 { 454 /* XXX: destroy all rules first */ 455 destroy_dev(devfs_dev); 456 objcache_destroy(devfs_rule_cache); 457 } 458 459 460 SYSINIT(devfsdev,SI_SUB_DRIVERS,SI_ORDER_FIRST,devfs_dev_init,NULL) 461 SYSUNINIT(devfsdev, SI_SUB_DRIVERS,SI_ORDER_FIRST,devfs_dev_uninit, NULL); 462 463 #if 0 464 465 static int 466 WildCmp(const char *w, const char *s) 467 { 468 int i; 469 int c; 470 int slen = strlen(s); 471 const char **mary; 472 473 for (i = c = 0; w[i]; ++i) { 474 if (w[i] == '*') 475 ++c; 476 } 477 mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK); 478 for (i = 0; i < c; ++i) 479 mary[i] = s + slen; 480 i = wildCmp(mary, 0, w, s); 481 kfree(mary, M_DEVFS); 482 return(i); 483 } 484 485 #endif 486 487 static int 488 WildCaseCmp(const char *w, const char *s) 489 { 490 int i; 491 int c; 492 int slen = strlen(s); 493 const char **mary; 494 495 for (i = c = 0; w[i]; ++i) { 496 if (w[i] == '*') 497 ++c; 498 } 499 mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK); 500 for (i = 0; i < c; ++i) 501 mary[i] = s + slen; 502 i = wildCaseCmp(mary, 0, w, s); 503 kfree(mary, M_DEVFS); 504 return(i); 505 } 506 507 /* 508 * WildCmp() - compare wild string to sane string 509 * 510 * Returns 0 on success, -1 on failure. 511 */ 512 static int 513 wildCmp(const char **mary, int d, const char *w, const char *s) 514 { 515 int i; 516 517 /* 518 * skip fixed portion 519 */ 520 for (;;) { 521 switch(*w) { 522 case '*': 523 /* 524 * optimize terminator 525 */ 526 if (w[1] == 0) 527 return(0); 528 if (w[1] != '?' && w[1] != '*') { 529 /* 530 * optimize * followed by non-wild 531 */ 532 for (i = 0; s + i < mary[d]; ++i) { 533 if (s[i] == w[1] && wildCmp(mary, d + 1, w + 1, s + i) == 0) 534 return(0); 535 } 536 } else { 537 /* 538 * less-optimal 539 */ 540 for (i = 0; s + i < mary[d]; ++i) { 541 if (wildCmp(mary, d + 1, w + 1, s + i) == 0) 542 return(0); 543 } 544 } 545 mary[d] = s; 546 return(-1); 547 case '?': 548 if (*s == 0) 549 return(-1); 550 ++w; 551 ++s; 552 break; 553 default: 554 if (*w != *s) 555 return(-1); 556 if (*w == 0) /* terminator */ 557 return(0); 558 ++w; 559 ++s; 560 break; 561 } 562 } 563 /* not reached */ 564 return(-1); 565 } 566 567 568 /* 569 * WildCaseCmp() - compare wild string to sane string, case insensitive 570 * 571 * Returns 0 on success, -1 on failure. 572 */ 573 static int 574 wildCaseCmp(const char **mary, int d, const char *w, const char *s) 575 { 576 int i; 577 578 /* 579 * skip fixed portion 580 */ 581 for (;;) { 582 switch(*w) { 583 case '*': 584 /* 585 * optimize terminator 586 */ 587 if (w[1] == 0) 588 return(0); 589 if (w[1] != '?' && w[1] != '*') { 590 /* 591 * optimize * followed by non-wild 592 */ 593 for (i = 0; s + i < mary[d]; ++i) { 594 if (s[i] == w[1] && wildCaseCmp(mary, d + 1, w + 1, s + i) == 0) 595 return(0); 596 } 597 } else { 598 /* 599 * less-optimal 600 */ 601 for (i = 0; s + i < mary[d]; ++i) { 602 if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0) 603 return(0); 604 } 605 } 606 mary[d] = s; 607 return(-1); 608 case '?': 609 if (*s == 0) 610 return(-1); 611 ++w; 612 ++s; 613 break; 614 default: 615 if (*w != *s) { 616 #define tolower(x) ((x >= 'A' && x <= 'Z')?(x+('a'-'A')):(x)) 617 if (tolower(*w) != tolower(*s)) 618 return(-1); 619 } 620 if (*w == 0) /* terminator */ 621 return(0); 622 ++w; 623 ++s; 624 break; 625 } 626 } 627 /* not reached */ 628 return(-1); 629 } 630