zfs: merge OpenZFS master-9305ff2ed
[freebsd.git] / sys / contrib / openzfs / lib / libzfs / os / linux / libzfs_mount_os.c
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 http://www.opensolaris.org/os/licensing.
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 /*
23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
25  * Copyright (c) 2014, 2021 by Delphix. All rights reserved.
26  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
27  * Copyright 2017 RackTop Systems.
28  * Copyright (c) 2018 Datto Inc.
29  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
30  */
31
32 #include <dirent.h>
33 #include <dlfcn.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <libgen.h>
37 #include <libintl.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <strings.h>
41 #include <unistd.h>
42 #include <zone.h>
43 #include <sys/mntent.h>
44 #include <sys/mount.h>
45 #include <sys/stat.h>
46 #include <sys/vfs.h>
47 #include <sys/dsl_crypt.h>
48 #include <libzfs.h>
49
50 #include "libzfs_impl.h"
51 #include <thread_pool.h>
52
53 #define ZS_COMMENT      0x00000000      /* comment */
54 #define ZS_ZFSUTIL      0x00000001      /* caller is zfs(8) */
55
56 typedef struct option_map {
57         const char *name;
58         unsigned long mntmask;
59         unsigned long zfsmask;
60 } option_map_t;
61
62 static const option_map_t option_map[] = {
63         /* Canonicalized filesystem independent options from mount(8) */
64         { MNTOPT_NOAUTO,        MS_COMMENT,     ZS_COMMENT      },
65         { MNTOPT_DEFAULTS,      MS_COMMENT,     ZS_COMMENT      },
66         { MNTOPT_NODEVICES,     MS_NODEV,       ZS_COMMENT      },
67         { MNTOPT_DEVICES,       MS_COMMENT,     ZS_COMMENT      },
68         { MNTOPT_DIRSYNC,       MS_DIRSYNC,     ZS_COMMENT      },
69         { MNTOPT_NOEXEC,        MS_NOEXEC,      ZS_COMMENT      },
70         { MNTOPT_EXEC,          MS_COMMENT,     ZS_COMMENT      },
71         { MNTOPT_GROUP,         MS_GROUP,       ZS_COMMENT      },
72         { MNTOPT_NETDEV,        MS_COMMENT,     ZS_COMMENT      },
73         { MNTOPT_NOFAIL,        MS_COMMENT,     ZS_COMMENT      },
74         { MNTOPT_NOSUID,        MS_NOSUID,      ZS_COMMENT      },
75         { MNTOPT_SUID,          MS_COMMENT,     ZS_COMMENT      },
76         { MNTOPT_OWNER,         MS_OWNER,       ZS_COMMENT      },
77         { MNTOPT_REMOUNT,       MS_REMOUNT,     ZS_COMMENT      },
78         { MNTOPT_RO,            MS_RDONLY,      ZS_COMMENT      },
79         { MNTOPT_RW,            MS_COMMENT,     ZS_COMMENT      },
80         { MNTOPT_SYNC,          MS_SYNCHRONOUS, ZS_COMMENT      },
81         { MNTOPT_USER,          MS_USERS,       ZS_COMMENT      },
82         { MNTOPT_USERS,         MS_USERS,       ZS_COMMENT      },
83         /* acl flags passed with util-linux-2.24 mount command */
84         { MNTOPT_ACL,           MS_POSIXACL,    ZS_COMMENT      },
85         { MNTOPT_NOACL,         MS_COMMENT,     ZS_COMMENT      },
86         { MNTOPT_POSIXACL,      MS_POSIXACL,    ZS_COMMENT      },
87 #ifdef MS_NOATIME
88         { MNTOPT_NOATIME,       MS_NOATIME,     ZS_COMMENT      },
89         { MNTOPT_ATIME,         MS_COMMENT,     ZS_COMMENT      },
90 #endif
91 #ifdef MS_NODIRATIME
92         { MNTOPT_NODIRATIME,    MS_NODIRATIME,  ZS_COMMENT      },
93         { MNTOPT_DIRATIME,      MS_COMMENT,     ZS_COMMENT      },
94 #endif
95 #ifdef MS_RELATIME
96         { MNTOPT_RELATIME,      MS_RELATIME,    ZS_COMMENT      },
97         { MNTOPT_NORELATIME,    MS_COMMENT,     ZS_COMMENT      },
98 #endif
99 #ifdef MS_STRICTATIME
100         { MNTOPT_STRICTATIME,   MS_STRICTATIME, ZS_COMMENT      },
101         { MNTOPT_NOSTRICTATIME, MS_COMMENT,     ZS_COMMENT      },
102 #endif
103 #ifdef MS_LAZYTIME
104         { MNTOPT_LAZYTIME,      MS_LAZYTIME,    ZS_COMMENT      },
105 #endif
106         { MNTOPT_CONTEXT,       MS_COMMENT,     ZS_COMMENT      },
107         { MNTOPT_FSCONTEXT,     MS_COMMENT,     ZS_COMMENT      },
108         { MNTOPT_DEFCONTEXT,    MS_COMMENT,     ZS_COMMENT      },
109         { MNTOPT_ROOTCONTEXT,   MS_COMMENT,     ZS_COMMENT      },
110 #ifdef MS_I_VERSION
111         { MNTOPT_IVERSION,      MS_I_VERSION,   ZS_COMMENT      },
112 #endif
113 #ifdef MS_MANDLOCK
114         { MNTOPT_NBMAND,        MS_MANDLOCK,    ZS_COMMENT      },
115         { MNTOPT_NONBMAND,      MS_COMMENT,     ZS_COMMENT      },
116 #endif
117         /* Valid options not found in mount(8) */
118         { MNTOPT_BIND,          MS_BIND,        ZS_COMMENT      },
119 #ifdef MS_REC
120         { MNTOPT_RBIND,         MS_BIND|MS_REC, ZS_COMMENT      },
121 #endif
122         { MNTOPT_COMMENT,       MS_COMMENT,     ZS_COMMENT      },
123 #ifdef MS_NOSUB
124         { MNTOPT_NOSUB,         MS_NOSUB,       ZS_COMMENT      },
125 #endif
126 #ifdef MS_SILENT
127         { MNTOPT_QUIET,         MS_SILENT,      ZS_COMMENT      },
128 #endif
129         /* Custom zfs options */
130         { MNTOPT_XATTR,         MS_COMMENT,     ZS_COMMENT      },
131         { MNTOPT_NOXATTR,       MS_COMMENT,     ZS_COMMENT      },
132         { MNTOPT_ZFSUTIL,       MS_COMMENT,     ZS_ZFSUTIL      },
133         { NULL,                 0,              0               } };
134
135 /*
136  * Break the mount option in to a name/value pair.  The name is
137  * validated against the option map and mount flags set accordingly.
138  */
139 static int
140 parse_option(char *mntopt, unsigned long *mntflags,
141     unsigned long *zfsflags, int sloppy)
142 {
143         const option_map_t *opt;
144         char *ptr, *name, *value = NULL;
145         int error = 0;
146
147         name = strdup(mntopt);
148         if (name == NULL)
149                 return (ENOMEM);
150
151         for (ptr = name; ptr && *ptr; ptr++) {
152                 if (*ptr == '=') {
153                         *ptr = '\0';
154                         value = ptr+1;
155                         VERIFY3P(value, !=, NULL);
156                         break;
157                 }
158         }
159
160         for (opt = option_map; opt->name != NULL; opt++) {
161                 if (strncmp(name, opt->name, strlen(name)) == 0) {
162                         *mntflags |= opt->mntmask;
163                         *zfsflags |= opt->zfsmask;
164                         error = 0;
165                         goto out;
166                 }
167         }
168
169         if (!sloppy)
170                 error = ENOENT;
171 out:
172         /* If required further process on the value may be done here */
173         free(name);
174         return (error);
175 }
176
177 /*
178  * Translate the mount option string in to MS_* mount flags for the
179  * kernel vfs.  When sloppy is non-zero unknown options will be ignored
180  * otherwise they are considered fatal are copied in to badopt.
181  */
182 int
183 zfs_parse_mount_options(char *mntopts, unsigned long *mntflags,
184     unsigned long *zfsflags, int sloppy, char *badopt, char *mtabopt)
185 {
186         int error = 0, quote = 0, flag = 0, count = 0;
187         char *ptr, *opt, *opts;
188
189         opts = strdup(mntopts);
190         if (opts == NULL)
191                 return (ENOMEM);
192
193         *mntflags = 0;
194         opt = NULL;
195
196         /*
197          * Scan through all mount options which must be comma delimited.
198          * We must be careful to notice regions which are double quoted
199          * and skip commas in these regions.  Each option is then checked
200          * to determine if it is a known option.
201          */
202         for (ptr = opts; ptr && !flag; ptr++) {
203                 if (opt == NULL)
204                         opt = ptr;
205
206                 if (*ptr == '"')
207                         quote = !quote;
208
209                 if (quote)
210                         continue;
211
212                 if (*ptr == '\0')
213                         flag = 1;
214
215                 if ((*ptr == ',') || (*ptr == '\0')) {
216                         *ptr = '\0';
217
218                         error = parse_option(opt, mntflags, zfsflags, sloppy);
219                         if (error) {
220                                 strcpy(badopt, opt);
221                                 goto out;
222
223                         }
224
225                         if (!(*mntflags & MS_REMOUNT) &&
226                             !(*zfsflags & ZS_ZFSUTIL) &&
227                             mtabopt != NULL) {
228                                 if (count > 0)
229                                         strlcat(mtabopt, ",", MNT_LINE_MAX);
230
231                                 strlcat(mtabopt, opt, MNT_LINE_MAX);
232                                 count++;
233                         }
234
235                         opt = NULL;
236                 }
237         }
238
239 out:
240         free(opts);
241         return (error);
242 }
243
244 static void
245 append_mntopt(const char *name, const char *val, char *mntopts,
246     char *mtabopt, boolean_t quote)
247 {
248         char tmp[MNT_LINE_MAX];
249
250         snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val);
251
252         if (mntopts)
253                 strlcat(mntopts, tmp, MNT_LINE_MAX);
254
255         if (mtabopt)
256                 strlcat(mtabopt, tmp, MNT_LINE_MAX);
257 }
258
259 static void
260 zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name,
261     char *mntopts, char *mtabopt)
262 {
263         char context[ZFS_MAXPROPLEN];
264
265         if (zfs_prop_get(zhp, zpt, context, sizeof (context),
266             NULL, NULL, 0, B_FALSE) == 0) {
267                 if (strcmp(context, "none") != 0)
268                         append_mntopt(name, context, mntopts, mtabopt, B_TRUE);
269         }
270 }
271
272 void
273 zfs_adjust_mount_options(zfs_handle_t *zhp, const char *mntpoint,
274     char *mntopts, char *mtabopt)
275 {
276         char prop[ZFS_MAXPROPLEN];
277
278         /*
279          * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists
280          * if it does, create a tmp variable in case it's needed
281          * checks to see if the selinux context is set to the default
282          * if it is, allow the setting of the other context properties
283          * this is needed because the 'context' property overrides others
284          * if it is not the default, set the 'context' property
285          */
286         if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop),
287             NULL, NULL, 0, B_FALSE) == 0) {
288                 if (strcmp(prop, "none") == 0) {
289                         zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT,
290                             MNTOPT_FSCONTEXT, mntopts, mtabopt);
291                         zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT,
292                             MNTOPT_DEFCONTEXT, mntopts, mtabopt);
293                         zfs_selinux_setcontext(zhp,
294                             ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT,
295                             mntopts, mtabopt);
296                 } else {
297                         append_mntopt(MNTOPT_CONTEXT, prop,
298                             mntopts, mtabopt, B_TRUE);
299                 }
300         }
301
302         /* A hint used to determine an auto-mounted snapshot mount point */
303         append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE);
304 }
305
306 /*
307  * By default the filesystem by preparing the mount options (i.e. parsing
308  * some flags from the "opts" parameter into the "flags" parameter) and then
309  * directly calling the system call mount(2). We don't need the mount utility
310  * or update /etc/mtab, because this is a symlink on all modern systems.
311  *
312  * If the environment variable ZFS_MOUNT_HELPER is set, we fall back to the
313  * previous behavior:
314  * The filesystem is mounted by invoking the system mount utility rather
315  * than by the system call mount(2).  This ensures that the /etc/mtab
316  * file is correctly locked for the update.  Performing our own locking
317  * and /etc/mtab update requires making an unsafe assumption about how
318  * the mount utility performs its locking.  Unfortunately, this also means
319  * in the case of a mount failure we do not have the exact errno.  We must
320  * make due with return value from the mount process.
321  */
322 int
323 do_mount(zfs_handle_t *zhp, const char *mntpt, char *opts, int flags)
324 {
325         const char *src = zfs_get_name(zhp);
326         int error = 0;
327
328         if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
329                 char badopt[MNT_LINE_MAX] = {0};
330                 unsigned long mntflags = flags, zfsflags;
331                 char myopts[MNT_LINE_MAX] = {0};
332
333                 if (zfs_parse_mount_options(opts, &mntflags,
334                     &zfsflags, 0, badopt, NULL)) {
335                         return (EINVAL);
336                 }
337                 strlcat(myopts, opts, MNT_LINE_MAX);
338                 zfs_adjust_mount_options(zhp, mntpt, myopts, NULL);
339                 if (mount(src, mntpt, MNTTYPE_ZFS, mntflags, myopts)) {
340                         return (errno);
341                 }
342         } else {
343                 char *argv[9] = {
344                     "/bin/mount",
345                     "--no-canonicalize",
346                     "-t", MNTTYPE_ZFS,
347                     "-o", opts,
348                     (char *)src,
349                     (char *)mntpt,
350                     (char *)NULL };
351
352                 /* Return only the most critical mount error */
353                 error = libzfs_run_process(argv[0], argv,
354                     STDOUT_VERBOSE|STDERR_VERBOSE);
355                 if (error) {
356                         if (error & MOUNT_FILEIO) {
357                                 error = EIO;
358                         } else if (error & MOUNT_USER) {
359                                 error = EINTR;
360                         } else if (error & MOUNT_SOFTWARE) {
361                                 error = EPIPE;
362                         } else if (error & MOUNT_BUSY) {
363                                 error = EBUSY;
364                         } else if (error & MOUNT_SYSERR) {
365                                 error = EAGAIN;
366                         } else if (error & MOUNT_USAGE) {
367                                 error = EINVAL;
368                         } else
369                                 error = ENXIO; /* Generic error */
370                 }
371         }
372
373         return (error);
374 }
375
376 int
377 do_unmount(const char *mntpt, int flags)
378 {
379         if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
380                 int rv = umount2(mntpt, flags);
381
382                 return (rv < 0 ? errno : 0);
383         }
384
385         char force_opt[] = "-f";
386         char lazy_opt[] = "-l";
387         char *argv[7] = {
388             "/bin/umount",
389             "-t", MNTTYPE_ZFS,
390             NULL, NULL, NULL, NULL };
391         int rc, count = 3;
392
393         if (flags & MS_FORCE) {
394                 argv[count] = force_opt;
395                 count++;
396         }
397
398         if (flags & MS_DETACH) {
399                 argv[count] = lazy_opt;
400                 count++;
401         }
402
403         argv[count] = (char *)mntpt;
404         rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
405
406         return (rc ? EINVAL : 0);
407 }
408
409 int
410 zfs_mount_delegation_check(void)
411 {
412         return ((geteuid() != 0) ? EACCES : 0);
413 }