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 static d_open_t devfs_dev_open; 51 static d_close_t devfs_dev_close; 52 static d_ioctl_t devfs_dev_ioctl; 53 54 static struct devfs_rule *devfs_rule_alloc(struct devfs_rule_ioctl *); 55 static void devfs_rule_free(struct devfs_rule *); 56 static int devfs_rule_insert(struct devfs_rule_ioctl *); 57 static void devfs_rule_remove(struct devfs_rule *); 58 static int devfs_rule_clear(struct devfs_rule_ioctl *); 59 static void devfs_rule_create_link(struct devfs_node *, struct devfs_rule *); 60 static int devfs_rule_checkname(struct devfs_rule *, struct devfs_node *); 61 62 static struct objcache *devfs_rule_cache; 63 static struct lock devfs_rule_lock; 64 65 static struct objcache_malloc_args devfs_rule_malloc_args = { 66 sizeof(struct devfs_rule), M_DEVFS }; 67 68 static cdev_t devfs_dev; 69 static struct devfs_rule_head devfs_rule_list = 70 TAILQ_HEAD_INITIALIZER(devfs_rule_list); 71 72 static struct dev_ops devfs_dev_ops = { 73 { "devfs", 0, 0 }, 74 .d_open = devfs_dev_open, 75 .d_close = devfs_dev_close, 76 .d_ioctl = devfs_dev_ioctl 77 }; 78 79 80 static struct devfs_rule * 81 devfs_rule_alloc(struct devfs_rule_ioctl *templ) 82 { 83 struct devfs_rule *rule; 84 size_t len; 85 86 rule = objcache_get(devfs_rule_cache, M_WAITOK); 87 memset(rule, 0, sizeof(struct devfs_rule)); 88 89 if (templ->mntpoint == NULL) 90 goto error_out; 91 /* NOTREACHED */ 92 93 len = strlen(templ->mntpoint); 94 if (len == 0) 95 goto error_out; 96 /* NOTREACHED */ 97 98 rule->mntpoint = kstrdup(templ->mntpoint, M_DEVFS); 99 rule->mntpointlen = len; 100 101 if (templ->rule_type & DEVFS_RULE_NAME) { 102 if (templ->name == NULL) 103 goto error_out; 104 /* NOTREACHED */ 105 106 len = strlen(templ->name); 107 if (len == 0) 108 goto error_out; 109 /* NOTREACHED */ 110 111 rule->name = kstrdup(templ->name, M_DEVFS); 112 rule->namlen = len; 113 } 114 115 if (templ->rule_cmd & DEVFS_RULE_LINK) { 116 if (templ->linkname == NULL) 117 goto error_out; 118 /* NOTREACHED */ 119 120 len = strlen(templ->linkname); 121 if (len == 0) 122 goto error_out; 123 /* NOTREACHED */ 124 125 rule->linkname = kstrdup(templ->linkname, M_DEVFS); 126 rule->linknamlen = len; 127 } 128 129 rule->rule_type = templ->rule_type; 130 rule->rule_cmd = templ->rule_cmd; 131 rule->dev_type = templ->dev_type; 132 rule->mode = templ->mode; 133 rule->uid = templ->uid; 134 rule->gid = templ->gid; 135 136 return rule; 137 138 error_out: 139 devfs_rule_free(rule); 140 return NULL; 141 } 142 143 144 static void 145 devfs_rule_free(struct devfs_rule *rule) 146 { 147 if (rule->mntpoint != NULL) { 148 kfree(rule->mntpoint, M_DEVFS); 149 } 150 151 if (rule->name != NULL) { 152 kfree(rule->name, M_DEVFS); 153 } 154 155 if (rule->linkname != NULL) { 156 kfree(rule->linkname, M_DEVFS); 157 } 158 objcache_put(devfs_rule_cache, rule); 159 } 160 161 162 static int 163 devfs_rule_insert(struct devfs_rule_ioctl *templ) 164 { 165 struct devfs_rule *rule; 166 167 rule = devfs_rule_alloc(templ); 168 if (rule == NULL) 169 return EINVAL; 170 171 lockmgr(&devfs_rule_lock, LK_EXCLUSIVE); 172 TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link); 173 lockmgr(&devfs_rule_lock, LK_RELEASE); 174 175 return 0; 176 } 177 178 179 static void 180 devfs_rule_remove(struct devfs_rule *rule) 181 { 182 TAILQ_REMOVE(&devfs_rule_list, rule, link); 183 devfs_rule_free(rule); 184 } 185 186 187 static int 188 devfs_rule_clear(struct devfs_rule_ioctl *templ) 189 { 190 struct devfs_rule *rule1, *rule2; 191 size_t mntpointlen; 192 193 if (templ->mntpoint == NULL) 194 return EINVAL; 195 196 mntpointlen = strlen(templ->mntpoint); 197 if (mntpointlen == 0) 198 return EINVAL; 199 200 lockmgr(&devfs_rule_lock, LK_EXCLUSIVE); 201 TAILQ_FOREACH_MUTABLE(rule1, &devfs_rule_list, link, rule2) { 202 if ((templ->mntpoint[0] == '*') || 203 ( (mntpointlen == rule1->mntpointlen) && 204 (!memcmp(templ->mntpoint, rule1->mntpoint, mntpointlen)) )) { 205 devfs_rule_remove(rule1); 206 } 207 } 208 lockmgr(&devfs_rule_lock, LK_RELEASE); 209 210 return 0; 211 } 212 213 214 void * 215 devfs_rule_reset_node(struct devfs_node *node, void *unused) 216 { 217 /* 218 * Don't blindly unhide all devices, some, like unix98 pty masters, 219 * haven't been hidden by a rule. 220 */ 221 if (node->flags & DEVFS_RULE_HIDDEN) 222 node->flags &= ~(DEVFS_HIDDEN | DEVFS_RULE_HIDDEN); 223 224 if ((node->node_type == Plink) && (node->flags & DEVFS_RULE_CREATED)) { 225 KKASSERT(node->link_target); 226 node->flags &= ~DEVFS_RULE_CREATED; 227 --node->link_target->nlinks; 228 devfs_gc(node); 229 } else if ((node->node_type == Pdev) && (node->d_dev)) { 230 node->uid = node->d_dev->si_uid; 231 node->gid = node->d_dev->si_gid; 232 node->mode = node->d_dev->si_perms; 233 } 234 235 return NULL; 236 } 237 238 static void 239 devfs_rule_create_link(struct devfs_node *node, struct devfs_rule *rule) 240 { 241 size_t len = 0; 242 char *path = NULL; 243 char *name, name_buf[PATH_MAX], buf[PATH_MAX]; 244 245 if (rule->name[rule->namlen-1] == '*') { 246 devfs_resolve_name_path(rule->name, name_buf, &path, &name); 247 len = strlen(name); 248 --len; 249 ksnprintf(buf, sizeof(buf), "%s%s", 250 rule->linkname, node->d_dir.d_name+len); 251 devfs_alias_create(buf, node, 1); 252 } else { 253 devfs_alias_create(rule->linkname, node, 1); 254 } 255 } 256 257 void * 258 devfs_rule_check_apply(struct devfs_node *node, void *unused) 259 { 260 struct devfs_rule *rule; 261 struct mount *mp = node->mp; 262 int locked = 0; 263 264 /* Check if it is locked already. if not, we acquire the devfs lock */ 265 if (!(lockstatus(&devfs_rule_lock, curthread)) == LK_EXCLUSIVE) { 266 lockmgr(&devfs_rule_lock, LK_EXCLUSIVE); 267 locked = 1; 268 } 269 270 TAILQ_FOREACH(rule, &devfs_rule_list, link) { 271 /* 272 * Skip this rule if it is only intended for jailed mount points 273 * and the current mount point isn't jailed 274 */ 275 if ((rule->rule_type & DEVFS_RULE_JAIL) && 276 (!(DEVFS_MNTDATA(mp)->jailed)) ) 277 continue; 278 279 /* 280 * Skip this rule if it is not intended for jailed mount points 281 * and the current mount point is jailed. 282 */ 283 if (!(rule->rule_type & DEVFS_RULE_JAIL) && 284 (DEVFS_MNTDATA(mp)->jailed)) 285 continue; 286 287 /* 288 * Skip this rule if the mount point specified in the rule doesn't 289 * match the mount point of the node 290 */ 291 if ((rule->mntpoint[0] != '*') && 292 (strcmp(rule->mntpoint, mp->mnt_stat.f_mntonname))) 293 continue; 294 295 /* 296 * Skip this rule if this is a by-type rule and the device flags 297 * don't match the specified device type in the rule 298 */ 299 if ((rule->rule_type & DEVFS_RULE_TYPE) && 300 ( (rule->dev_type == 0) || (!dev_is_good(node->d_dev)) || 301 (!(dev_dflags(node->d_dev) & rule->dev_type))) ) 302 continue; 303 304 /* 305 * Skip this rule if this is a by-name rule and the node name 306 * doesn't match the wildcard string in the rule 307 */ 308 if ((rule->rule_type & DEVFS_RULE_NAME) && 309 (!devfs_rule_checkname(rule, node)) ) 310 continue; 311 312 if (rule->rule_cmd & DEVFS_RULE_HIDE) { 313 /* 314 * If we should hide the device, we just apply the relevant 315 * hide flag to the node and let devfs do the rest in the 316 * vnops 317 */ 318 if ((node->d_dir.d_namlen == 5) && 319 (!memcmp(node->d_dir.d_name, "devfs", 5))) { 320 /* 321 * Magically avoid /dev/devfs from being hidden, so that one 322 * can still use the rule system even after a "* hide". 323 */ 324 continue; 325 } 326 node->flags |= (DEVFS_HIDDEN | DEVFS_RULE_HIDDEN); 327 } else if (rule->rule_cmd & DEVFS_RULE_SHOW) { 328 /* 329 * Show rule just means that the node should not be hidden, so 330 * what we do is clear the hide flag from the node. 331 */ 332 node->flags &= ~DEVFS_HIDDEN; 333 } else if (rule->rule_cmd & DEVFS_RULE_LINK) { 334 /* 335 * This is a LINK rule, so we tell devfs to create 336 * a link with the correct name to this node. 337 */ 338 devfs_rule_create_link(node, rule); 339 #if 0 340 devfs_alias_create(rule->linkname, node, 1); 341 #endif 342 } else if (rule->rule_cmd & DEVFS_RULE_PERM) { 343 /* 344 * This is a normal ownership/permission rule. We 345 * just apply the permissions and ownership and 346 * we are done. 347 */ 348 node->mode = rule->mode; 349 node->uid = rule->uid; 350 node->gid = rule->gid; 351 } 352 } 353 354 /* If we acquired the lock, we also get rid of it */ 355 if (locked) 356 lockmgr(&devfs_rule_lock, LK_RELEASE); 357 358 return NULL; 359 } 360 361 362 static int 363 devfs_rule_checkname(struct devfs_rule *rule, struct devfs_node *node) 364 { 365 struct devfs_node *parent = DEVFS_MNTDATA(node->mp)->root_node; 366 char *path = NULL; 367 char *name, name_buf[PATH_MAX]; 368 int no_match = 0; 369 370 devfs_resolve_name_path(rule->name, name_buf, &path, &name); 371 parent = devfs_resolve_or_create_path(parent, path, 0); 372 373 if (parent == NULL) 374 return 0; /* no match */ 375 376 /* Check if node is a child of the parent we found */ 377 if (node->parent != parent) 378 return 0; /* no match */ 379 380 #if 0 381 if (rule->rule_type & DEVFS_RULE_LINK) 382 no_match = memcmp(name, node->d_dir.d_name, strlen(name)); 383 else 384 #endif 385 no_match = devfs_WildCaseCmp(name, node->d_dir.d_name); 386 387 return !no_match; 388 } 389 390 391 static int 392 devfs_dev_open(struct dev_open_args *ap) 393 { 394 /* 395 * Only allow read-write access. 396 */ 397 if (((ap->a_oflags & FWRITE) == 0) || ((ap->a_oflags & FREAD) == 0)) 398 return(EPERM); 399 400 /* 401 * We don't allow nonblocking access. 402 */ 403 if ((ap->a_oflags & O_NONBLOCK) != 0) { 404 devfs_debug(DEVFS_DEBUG_SHOW, "devfs_dev: can't do nonblocking access\n"); 405 return(ENODEV); 406 } 407 408 return 0; 409 } 410 411 412 static int 413 devfs_dev_close(struct dev_close_args *ap) 414 { 415 return 0; 416 } 417 418 419 static int 420 devfs_dev_ioctl(struct dev_ioctl_args *ap) 421 { 422 int error; 423 struct devfs_rule_ioctl *rule; 424 425 error = 0; 426 rule = (struct devfs_rule_ioctl *)ap->a_data; 427 428 switch(ap->a_cmd) { 429 case DEVFS_RULE_ADD: 430 error = devfs_rule_insert(rule); 431 break; 432 433 case DEVFS_RULE_APPLY: 434 if (rule->mntpoint == NULL) 435 error = EINVAL; 436 else 437 devfs_apply_rules(rule->mntpoint); 438 break; 439 440 case DEVFS_RULE_CLEAR: 441 error = devfs_rule_clear(rule); 442 break; 443 444 case DEVFS_RULE_RESET: 445 if (rule->mntpoint == NULL) 446 error = EINVAL; 447 else 448 devfs_reset_rules(rule->mntpoint); 449 break; 450 451 default: 452 error = ENOTTY; /* Inappropriate ioctl for device */ 453 break; 454 } 455 456 return(error); 457 } 458 459 460 static void 461 devfs_dev_init(void *unused) 462 { 463 lockinit(&devfs_rule_lock, "devfs_rule lock", 0, 0); 464 465 devfs_rule_cache = objcache_create("devfs-rule-cache", 0, 0, 466 NULL, NULL, NULL, 467 objcache_malloc_alloc, 468 objcache_malloc_free, 469 &devfs_rule_malloc_args ); 470 471 devfs_dev = make_dev(&devfs_dev_ops, 472 0, 473 UID_ROOT, 474 GID_WHEEL, 475 0600, 476 "devfs"); 477 } 478 479 480 static void 481 devfs_dev_uninit(void *unused) 482 { 483 /* XXX: destroy all rules first */ 484 destroy_dev(devfs_dev); 485 objcache_destroy(devfs_rule_cache); 486 } 487 488 489 SYSINIT(devfsdev,SI_SUB_DRIVERS,SI_ORDER_FIRST,devfs_dev_init,NULL) 490 SYSUNINIT(devfsdev, SI_SUB_DRIVERS,SI_ORDER_FIRST,devfs_dev_uninit, NULL); 491 492