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