The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/zcommon/zfs_namecheck.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 /*
   22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   23  * Use is subject to license terms.
   24  */
   25 /*
   26  * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
   27  */
   28 
   29 /*
   30  * Common name validation routines for ZFS.  These routines are shared by the
   31  * userland code as well as the ioctl() layer to ensure that we don't
   32  * inadvertently expose a hole through direct ioctl()s that never gets tested.
   33  * In userland, however, we want significantly more information about _why_ the
   34  * name is invalid.  In the kernel, we only care whether it's valid or not.
   35  * Each routine therefore takes a 'namecheck_err_t' which describes exactly why
   36  * the name failed to validate.
   37  */
   38 
   39 #if !defined(_KERNEL)
   40 #include <string.h>
   41 #endif
   42 
   43 #include <sys/dsl_dir.h>
   44 #include <sys/param.h>
   45 #include <sys/nvpair.h>
   46 #include "zfs_namecheck.h"
   47 #include "zfs_deleg.h"
   48 
   49 /*
   50  * Deeply nested datasets can overflow the stack, so we put a limit
   51  * in the amount of nesting a path can have. zfs_max_dataset_nesting
   52  * can be tuned temporarily to fix existing datasets that exceed our
   53  * predefined limit.
   54  */
   55 int zfs_max_dataset_nesting = 50;
   56 
   57 static int
   58 valid_char(char c)
   59 {
   60         return ((c >= 'a' && c <= 'z') ||
   61             (c >= 'A' && c <= 'Z') ||
   62             (c >= '' && c <= '9') ||
   63             c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
   64 }
   65 
   66 /*
   67  * Looks at a path and returns its level of nesting (depth).
   68  */
   69 int
   70 get_dataset_depth(const char *path)
   71 {
   72         const char *loc = path;
   73         int nesting = 0;
   74 
   75         /*
   76          * Keep track of nesting until you hit the end of the
   77          * path or found the snapshot/bookmark separator.
   78          */
   79         for (int i = 0; loc[i] != '\0' &&
   80             loc[i] != '@' &&
   81             loc[i] != '#'; i++) {
   82                 if (loc[i] == '/')
   83                         nesting++;
   84         }
   85 
   86         return (nesting);
   87 }
   88 
   89 /*
   90  * Snapshot names must be made up of alphanumeric characters plus the following
   91  * characters:
   92  *
   93  *      [-_.: ]
   94  *
   95  * Returns 0 on success, -1 on error.
   96  */
   97 int
   98 zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
   99 {
  100         const char *loc;
  101 
  102         if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
  103                 if (why)
  104                         *why = NAME_ERR_TOOLONG;
  105                 return (-1);
  106         }
  107 
  108         if (path[0] == '\0') {
  109                 if (why)
  110                         *why = NAME_ERR_EMPTY_COMPONENT;
  111                 return (-1);
  112         }
  113 
  114         for (loc = path; *loc; loc++) {
  115                 if (!valid_char(*loc)) {
  116                         if (why) {
  117                                 *why = NAME_ERR_INVALCHAR;
  118                                 *what = *loc;
  119                         }
  120                         return (-1);
  121                 }
  122         }
  123         return (0);
  124 }
  125 
  126 
  127 /*
  128  * Permissions set name must start with the letter '@' followed by the
  129  * same character restrictions as snapshot names, except that the name
  130  * cannot exceed 64 characters.
  131  *
  132  * Returns 0 on success, -1 on error.
  133  */
  134 int
  135 permset_namecheck(const char *path, namecheck_err_t *why, char *what)
  136 {
  137         if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
  138                 if (why)
  139                         *why = NAME_ERR_TOOLONG;
  140                 return (-1);
  141         }
  142 
  143         if (path[0] != '@') {
  144                 if (why) {
  145                         *why = NAME_ERR_NO_AT;
  146                         *what = path[0];
  147                 }
  148                 return (-1);
  149         }
  150 
  151         return (zfs_component_namecheck(&path[1], why, what));
  152 }
  153 
  154 /*
  155  * Dataset paths should not be deeper than zfs_max_dataset_nesting
  156  * in terms of nesting.
  157  *
  158  * Returns 0 on success, -1 on error.
  159  */
  160 int
  161 dataset_nestcheck(const char *path)
  162 {
  163         return ((get_dataset_depth(path) < zfs_max_dataset_nesting) ? 0 : -1);
  164 }
  165 
  166 /*
  167  * Entity names must be of the following form:
  168  *
  169  *      [component/]*[component][(@|#)component]?
  170  *
  171  * Where each component is made up of alphanumeric characters plus the following
  172  * characters:
  173  *
  174  *      [-_.: %]
  175  *
  176  * We allow '%' here as we use that character internally to create unique
  177  * names for temporary clones (for online recv).
  178  *
  179  * Returns 0 on success, -1 on error.
  180  */
  181 int
  182 entity_namecheck(const char *path, namecheck_err_t *why, char *what)
  183 {
  184         const char *end;
  185 
  186         EQUIV(why == NULL, what == NULL);
  187 
  188         /*
  189          * Make sure the name is not too long.
  190          */
  191         if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
  192                 if (why)
  193                         *why = NAME_ERR_TOOLONG;
  194                 return (-1);
  195         }
  196 
  197         /* Explicitly check for a leading slash.  */
  198         if (path[0] == '/') {
  199                 if (why)
  200                         *why = NAME_ERR_LEADING_SLASH;
  201                 return (-1);
  202         }
  203 
  204         if (path[0] == '\0') {
  205                 if (why)
  206                         *why = NAME_ERR_EMPTY_COMPONENT;
  207                 return (-1);
  208         }
  209 
  210         const char *start = path;
  211         boolean_t found_delim = B_FALSE;
  212         for (;;) {
  213                 /* Find the end of this component */
  214                 end = start;
  215                 while (*end != '/' && *end != '@' && *end != '#' &&
  216                     *end != '\0')
  217                         end++;
  218 
  219                 if (*end == '\0' && end[-1] == '/') {
  220                         /* trailing slashes are not allowed */
  221                         if (why)
  222                                 *why = NAME_ERR_TRAILING_SLASH;
  223                         return (-1);
  224                 }
  225 
  226                 /* Validate the contents of this component */
  227                 for (const char *loc = start; loc != end; loc++) {
  228                         if (!valid_char(*loc) && *loc != '%') {
  229                                 if (why) {
  230                                         *why = NAME_ERR_INVALCHAR;
  231                                         *what = *loc;
  232                                 }
  233                                 return (-1);
  234                         }
  235                 }
  236 
  237                 if (*end == '\0' || *end == '/') {
  238                         int component_length = end - start;
  239                         /* Validate the contents of this component is not '.' */
  240                         if (component_length == 1) {
  241                                 if (start[0] == '.') {
  242                                         if (why)
  243                                                 *why = NAME_ERR_SELF_REF;
  244                                         return (-1);
  245                                 }
  246                         }
  247 
  248                         /* Validate the content of this component is not '..' */
  249                         if (component_length == 2) {
  250                                 if (start[0] == '.' && start[1] == '.') {
  251                                         if (why)
  252                                                 *why = NAME_ERR_PARENT_REF;
  253                                         return (-1);
  254                                 }
  255                         }
  256                 }
  257 
  258                 /* Snapshot or bookmark delimiter found */
  259                 if (*end == '@' || *end == '#') {
  260                         /* Multiple delimiters are not allowed */
  261                         if (found_delim != 0) {
  262                                 if (why)
  263                                         *why = NAME_ERR_MULTIPLE_DELIMITERS;
  264                                 return (-1);
  265                         }
  266 
  267                         found_delim = B_TRUE;
  268                 }
  269 
  270                 /* Zero-length components are not allowed */
  271                 if (start == end) {
  272                         if (why)
  273                                 *why = NAME_ERR_EMPTY_COMPONENT;
  274                         return (-1);
  275                 }
  276 
  277                 /* If we've reached the end of the string, we're OK */
  278                 if (*end == '\0')
  279                         return (0);
  280 
  281                 /*
  282                  * If there is a '/' in a snapshot or bookmark name
  283                  * then report an error
  284                  */
  285                 if (*end == '/' && found_delim != 0) {
  286                         if (why)
  287                                 *why = NAME_ERR_TRAILING_SLASH;
  288                         return (-1);
  289                 }
  290 
  291                 /* Update to the next component */
  292                 start = end + 1;
  293         }
  294 }
  295 
  296 /*
  297  * Dataset is any entity, except bookmark
  298  */
  299 int
  300 dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
  301 {
  302         int ret = entity_namecheck(path, why, what);
  303 
  304         if (ret == 0 && strchr(path, '#') != NULL) {
  305                 if (why != NULL) {
  306                         *why = NAME_ERR_INVALCHAR;
  307                         *what = '#';
  308                 }
  309                 return (-1);
  310         }
  311 
  312         return (ret);
  313 }
  314 
  315 /*
  316  * Assert path is a valid bookmark name
  317  */
  318 int
  319 bookmark_namecheck(const char *path, namecheck_err_t *why, char *what)
  320 {
  321         int ret = entity_namecheck(path, why, what);
  322 
  323         if (ret == 0 && strchr(path, '#') == NULL) {
  324                 if (why != NULL) {
  325                         *why = NAME_ERR_NO_POUND;
  326                         *what = '#';
  327                 }
  328                 return (-1);
  329         }
  330 
  331         return (ret);
  332 }
  333 
  334 /*
  335  * Assert path is a valid snapshot name
  336  */
  337 int
  338 snapshot_namecheck(const char *path, namecheck_err_t *why, char *what)
  339 {
  340         int ret = entity_namecheck(path, why, what);
  341 
  342         if (ret == 0 && strchr(path, '@') == NULL) {
  343                 if (why != NULL) {
  344                         *why = NAME_ERR_NO_AT;
  345                         *what = '@';
  346                 }
  347                 return (-1);
  348         }
  349 
  350         return (ret);
  351 }
  352 
  353 /*
  354  * mountpoint names must be of the following form:
  355  *
  356  *      /[component][/]*[component][/]
  357  *
  358  * Returns 0 on success, -1 on error.
  359  */
  360 int
  361 mountpoint_namecheck(const char *path, namecheck_err_t *why)
  362 {
  363         const char *start, *end;
  364 
  365         /*
  366          * Make sure none of the mountpoint component names are too long.
  367          * If a component name is too long then the mkdir of the mountpoint
  368          * will fail but then the mountpoint property will be set to a value
  369          * that can never be mounted.  Better to fail before setting the prop.
  370          * Extra slashes are OK, they will be tossed by the mountpoint mkdir.
  371          */
  372 
  373         if (path == NULL || *path != '/') {
  374                 if (why)
  375                         *why = NAME_ERR_LEADING_SLASH;
  376                 return (-1);
  377         }
  378 
  379         /* Skip leading slash  */
  380         start = &path[1];
  381         do {
  382                 end = start;
  383                 while (*end != '/' && *end != '\0')
  384                         end++;
  385 
  386                 if (end - start >= ZFS_MAX_DATASET_NAME_LEN) {
  387                         if (why)
  388                                 *why = NAME_ERR_TOOLONG;
  389                         return (-1);
  390                 }
  391                 start = end + 1;
  392 
  393         } while (*end != '\0');
  394 
  395         return (0);
  396 }
  397 
  398 /*
  399  * For pool names, we have the same set of valid characters as described in
  400  * dataset names, with the additional restriction that the pool name must begin
  401  * with a letter.  The pool names 'raidz' and 'mirror' are also reserved names
  402  * that cannot be used.
  403  *
  404  * Returns 0 on success, -1 on error.
  405  */
  406 int
  407 pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
  408 {
  409         const char *c;
  410 
  411         /*
  412          * Make sure the name is not too long.
  413          * If we're creating a pool with version >= SPA_VERSION_DSL_SCRUB (v11)
  414          * we need to account for additional space needed by the origin ds which
  415          * will also be snapshotted: "poolname"+"/"+"$ORIGIN"+"@"+"$ORIGIN".
  416          * Play it safe and enforce this limit even if the pool version is < 11
  417          * so it can be upgraded without issues.
  418          */
  419         if (strlen(pool) >= (ZFS_MAX_DATASET_NAME_LEN - 2 -
  420             strlen(ORIGIN_DIR_NAME) * 2)) {
  421                 if (why)
  422                         *why = NAME_ERR_TOOLONG;
  423                 return (-1);
  424         }
  425 
  426         c = pool;
  427         while (*c != '\0') {
  428                 if (!valid_char(*c)) {
  429                         if (why) {
  430                                 *why = NAME_ERR_INVALCHAR;
  431                                 *what = *c;
  432                         }
  433                         return (-1);
  434                 }
  435                 c++;
  436         }
  437 
  438         if (!(*pool >= 'a' && *pool <= 'z') &&
  439             !(*pool >= 'A' && *pool <= 'Z')) {
  440                 if (why)
  441                         *why = NAME_ERR_NOLETTER;
  442                 return (-1);
  443         }
  444 
  445         if (strcmp(pool, "mirror") == 0 ||
  446             strcmp(pool, "raidz") == 0 ||
  447             strcmp(pool, "draid") == 0) {
  448                 if (why)
  449                         *why = NAME_ERR_RESERVED;
  450                 return (-1);
  451         }
  452 
  453         return (0);
  454 }
  455 
  456 EXPORT_SYMBOL(entity_namecheck);
  457 EXPORT_SYMBOL(pool_namecheck);
  458 EXPORT_SYMBOL(dataset_namecheck);
  459 EXPORT_SYMBOL(bookmark_namecheck);
  460 EXPORT_SYMBOL(snapshot_namecheck);
  461 EXPORT_SYMBOL(zfs_component_namecheck);
  462 EXPORT_SYMBOL(dataset_nestcheck);
  463 EXPORT_SYMBOL(get_dataset_depth);
  464 EXPORT_SYMBOL(zfs_max_dataset_nesting);
  465 
  466 ZFS_MODULE_PARAM(zfs, zfs_, max_dataset_nesting, INT, ZMOD_RW,
  467         "Limit to the amount of nesting a path can have. Defaults to 50.");

Cache object: f323cac40f82c052dd838b164ad747b6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.