libfuse
fusermount.c
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPLv2.
6 See the file GPL2.txt.
7*/
8/* This program does the mounting and unmounting of FUSE filesystems */
9
10#define _GNU_SOURCE /* for clone,strchrnul and close_range */
11#include "fuse_config.h"
12#include "mount_util.h"
13#include "util.h"
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <ctype.h>
19#include <unistd.h>
20#include <getopt.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <pwd.h>
24#include <paths.h>
25#include <mntent.h>
26#include <sys/wait.h>
27#include <sys/stat.h>
28#include <sys/param.h>
29
30#include "fuse_mount_compat.h"
31
32#include <sys/fsuid.h>
33#include <sys/socket.h>
34#include <sys/utsname.h>
35#include <sched.h>
36#include <stdbool.h>
37#include <sys/vfs.h>
38
39#if defined HAVE_CLOSE_RANGE && defined linux
40#include <linux/close_range.h>
41#endif
42
43#if defined HAVE_LISTMOUNT
44#include <linux/mount.h>
45#include <syscall.h>
46#include <stdint.h>
47#endif
48
49#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
50#define FUSE_KERN_DEVICE_ENV "FUSE_KERN_DEVICE"
51
52#define FUSE_DEV "/dev/fuse"
53
54static const char *progname;
55
56static int user_allow_other = 0;
57static int mount_max = 1000;
58
59static int auto_unmount = 0;
60
61#ifdef GETMNTENT_NEEDS_UNESCAPING
62// Older versions of musl libc don't unescape entries in /etc/mtab
63
64// unescapes octal sequences like \040 in-place
65// That's ok, because unescaping can not extend the length of the string.
66static void unescape(char *buf) {
67 char *src = buf;
68 char *dest = buf;
69 while (1) {
70 char *next_src = strchrnul(src, '\\');
71 int offset = next_src - src;
72 memmove(dest, src, offset);
73 src = next_src;
74 dest += offset;
75
76 if(*src == '\0') {
77 *dest = *src;
78 return;
79 }
80 src++;
81
82 if('0' <= src[0] && src[0] < '2' &&
83 '0' <= src[1] && src[1] < '8' &&
84 '0' <= src[2] && src[2] < '8') {
85 *dest++ = (src[0] - '0') << 6
86 | (src[1] - '0') << 3
87 | (src[2] - '0') << 0;
88 src += 3;
89 } else if (src[0] == '\\') {
90 *dest++ = '\\';
91 src += 1;
92 } else {
93 *dest++ = '\\';
94 }
95 }
96}
97
98static struct mntent *GETMNTENT(FILE *stream)
99{
100 struct mntent *entp = getmntent(stream);
101 if(entp != NULL) {
102 unescape(entp->mnt_fsname);
103 unescape(entp->mnt_dir);
104 unescape(entp->mnt_type);
105 unescape(entp->mnt_opts);
106 }
107 return entp;
108}
109#else
110#define GETMNTENT getmntent
111#endif // GETMNTENT_NEEDS_UNESCAPING
112
113/*
114 * Take a ',' separated option string and extract "x-" options
115 */
116static int extract_x_options(const char *original, char **non_x_opts,
117 char **x_opts)
118{
119 size_t orig_len;
120 const char *opt, *opt_end;
121
122 orig_len = strlen(original) + 1;
123
124 *non_x_opts = calloc(1, orig_len);
125 *x_opts = calloc(1, orig_len);
126
127 size_t non_x_opts_len = orig_len;
128 size_t x_opts_len = orig_len;
129
130 if (*non_x_opts == NULL || *x_opts == NULL) {
131 fprintf(stderr, "%s: Failed to allocate %zuB.\n",
132 __func__, orig_len);
133 return -ENOMEM;
134 }
135
136 for (opt = original; opt < original + orig_len; opt = opt_end + 1) {
137 char *opt_buf;
138
139 opt_end = strchr(opt, ',');
140 if (opt_end == NULL)
141 opt_end = original + orig_len;
142
143 size_t opt_len = opt_end - opt;
144 size_t opt_len_left = orig_len - (opt - original);
145 size_t buf_len;
146 bool is_x_opts;
147
148 if (strncmp(opt, "x-", MIN(2, opt_len_left)) == 0) {
149 buf_len = x_opts_len;
150 is_x_opts = true;
151 opt_buf = *x_opts;
152 } else {
153 buf_len = non_x_opts_len;
154 is_x_opts = false;
155 opt_buf = *non_x_opts;
156 }
157
158 if (buf_len < orig_len) {
159 strncat(opt_buf, ",", 2);
160 buf_len -= 1;
161 }
162
163 /* omits ',' */
164 if ((ssize_t)(buf_len - opt_len) < 0) {
165 /* This would be a bug */
166 fprintf(stderr, "%s: no buf space left in copy, orig='%s'\n",
167 __func__, original);
168 return -EIO;
169 }
170
171 strncat(opt_buf, opt, opt_end - opt);
172 buf_len -= opt_len;
173
174 if (is_x_opts)
175 x_opts_len = buf_len;
176 else
177 non_x_opts_len = buf_len;
178 }
179
180 return 0;
181}
182
183static const char *get_user_name(void)
184{
185 struct passwd *pw = getpwuid(getuid());
186 if (pw != NULL && pw->pw_name != NULL)
187 return pw->pw_name;
188 else {
189 fprintf(stderr, "%s: could not determine username\n", progname);
190 return NULL;
191 }
192}
193
194static uid_t oldfsuid;
195static gid_t oldfsgid;
196
197static void drop_privs(void)
198{
199 if (getuid() != 0) {
200 oldfsuid = setfsuid(getuid());
201 oldfsgid = setfsgid(getgid());
202 }
203}
204
205static void restore_privs(void)
206{
207 if (getuid() != 0) {
208 setfsuid(oldfsuid);
209 setfsgid(oldfsgid);
210 }
211}
212
213#ifndef IGNORE_MTAB
214/*
215 * Make sure that /etc/mtab is checked and updated atomically
216 */
217static int lock_umount(void)
218{
219 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
220 int mtablock;
221 int res;
222 struct stat mtab_stat;
223
224 /* /etc/mtab could be a symlink to /proc/mounts */
225 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
226 return -1;
227
228 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
229 if (mtablock == -1) {
230 fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
231 progname, strerror(errno));
232 return -1;
233 }
234 res = lockf(mtablock, F_LOCK, 0);
235 if (res < 0) {
236 fprintf(stderr, "%s: error getting lock: %s\n", progname,
237 strerror(errno));
238 close(mtablock);
239 return -1;
240 }
241
242 return mtablock;
243}
244
245static void unlock_umount(int mtablock)
246{
247 if (mtablock >= 0) {
248 int res;
249
250 res = lockf(mtablock, F_ULOCK, 0);
251 if (res < 0) {
252 fprintf(stderr, "%s: error releasing lock: %s\n",
253 progname, strerror(errno));
254 }
255 close(mtablock);
256 }
257}
258
259static int add_mount(const char *source, const char *mnt, const char *type,
260 const char *opts)
261{
262 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
263}
264
265static int may_unmount(const char *mnt, int quiet)
266{
267 struct mntent *entp;
268 FILE *fp;
269 const char *user = NULL;
270 char uidstr[32];
271 unsigned uidlen = 0;
272 int found;
273 const char *mtab = _PATH_MOUNTED;
274
275 user = get_user_name();
276 if (user == NULL)
277 return -1;
278
279 fp = setmntent(mtab, "r");
280 if (fp == NULL) {
281 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
282 strerror(errno));
283 return -1;
284 }
285
286 uidlen = sprintf(uidstr, "%u", getuid());
287
288 found = 0;
289 while ((entp = GETMNTENT(fp)) != NULL) {
290 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
291 (strcmp(entp->mnt_type, "fuse") == 0 ||
292 strcmp(entp->mnt_type, "fuseblk") == 0 ||
293 strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
294 strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
295 char *p = strstr(entp->mnt_opts, "user=");
296 if (p &&
297 (p == entp->mnt_opts || *(p-1) == ',') &&
298 strcmp(p + 5, user) == 0) {
299 found = 1;
300 break;
301 }
302 /* /etc/mtab is a link pointing to
303 /proc/mounts: */
304 else if ((p =
305 strstr(entp->mnt_opts, "user_id=")) &&
306 (p == entp->mnt_opts ||
307 *(p-1) == ',') &&
308 strncmp(p + 8, uidstr, uidlen) == 0 &&
309 (*(p+8+uidlen) == ',' ||
310 *(p+8+uidlen) == '\0')) {
311 found = 1;
312 break;
313 }
314 }
315 }
316 endmntent(fp);
317
318 if (!found) {
319 if (!quiet)
320 fprintf(stderr,
321 "%s: entry for %s not found in %s\n",
322 progname, mnt, mtab);
323 return -1;
324 }
325
326 return 0;
327}
328#endif
329
330/*
331 * Check whether the file specified in "fusermount3 -u" is really a
332 * mountpoint and not a symlink. This is necessary otherwise the user
333 * could move the mountpoint away and replace it with a symlink
334 * pointing to an arbitrary mount, thereby tricking fusermount3 into
335 * unmounting that (umount(2) will follow symlinks).
336 *
337 * This is the child process running in a separate mount namespace, so
338 * we don't mess with the global namespace and if the process is
339 * killed for any reason, mounts are automatically cleaned up.
340 *
341 * First make sure nothing is propagated back into the parent
342 * namespace by marking all mounts "private".
343 *
344 * Then bind mount parent onto a stable base where the user can't move
345 * it around.
346 *
347 * Finally check /proc/mounts for an entry matching the requested
348 * mountpoint. If it's found then we are OK, and the user can't move
349 * it around within the parent directory as rename() will return
350 * EBUSY. Be careful to ignore any mounts that existed before the
351 * bind.
352 */
353static int check_is_mount_child(void *p)
354{
355 const char **a = p;
356 const char *last = a[0];
357 const char *mnt = a[1];
358 const char *type = a[2];
359 int res;
360 const char *procmounts = "/proc/mounts";
361 int found;
362 FILE *fp;
363 struct mntent *entp;
364 int count;
365
366 res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
367 if (res == -1) {
368 fprintf(stderr, "%s: failed to mark mounts private: %s\n",
369 progname, strerror(errno));
370 return 1;
371 }
372
373 fp = setmntent(procmounts, "r");
374 if (fp == NULL) {
375 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
376 procmounts, strerror(errno));
377 return 1;
378 }
379
380 count = 0;
381 while (GETMNTENT(fp) != NULL)
382 count++;
383 endmntent(fp);
384
385 fp = setmntent(procmounts, "r");
386 if (fp == NULL) {
387 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
388 procmounts, strerror(errno));
389 return 1;
390 }
391
392 res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
393 if (res == -1) {
394 fprintf(stderr, "%s: failed to bind parent to /: %s\n",
395 progname, strerror(errno));
396 return 1;
397 }
398
399 found = 0;
400 while ((entp = GETMNTENT(fp)) != NULL) {
401 if (count > 0) {
402 count--;
403 continue;
404 }
405 if (entp->mnt_dir[0] == '/' &&
406 strcmp(entp->mnt_dir + 1, last) == 0 &&
407 (!type || strcmp(entp->mnt_type, type) == 0)) {
408 found = 1;
409 break;
410 }
411 }
412 endmntent(fp);
413
414 if (!found) {
415 fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
416 return 1;
417 }
418
419 return 0;
420}
421
422static pid_t clone_newns(void *a)
423{
424 char buf[131072];
425 char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
426
427#ifdef __ia64__
428 extern int __clone2(int (*fn)(void *),
429 void *child_stack_base, size_t stack_size,
430 int flags, void *arg, pid_t *ptid,
431 void *tls, pid_t *ctid);
432
433 return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
434 CLONE_NEWNS, a, NULL, NULL, NULL);
435#else
436 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
437#endif
438}
439
440static int check_is_mount(const char *last, const char *mnt, const char *type)
441{
442 pid_t pid, p;
443 int status;
444 const char *a[3] = { last, mnt, type };
445
446 pid = clone_newns((void *) a);
447 if (pid == (pid_t) -1) {
448 fprintf(stderr, "%s: failed to clone namespace: %s\n",
449 progname, strerror(errno));
450 return -1;
451 }
452 p = waitpid(pid, &status, __WCLONE);
453 if (p == (pid_t) -1) {
454 fprintf(stderr, "%s: waitpid failed: %s\n",
455 progname, strerror(errno));
456 return -1;
457 }
458 if (!WIFEXITED(status)) {
459 fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
460 progname, status);
461 return -1;
462 }
463 if (WEXITSTATUS(status) != 0)
464 return -1;
465
466 return 0;
467}
468
469static int chdir_to_parent(char *copy, const char **lastp)
470{
471 char *tmp;
472 const char *parent;
473 char buf[65536];
474 int res;
475
476 tmp = strrchr(copy, '/');
477 if (tmp == NULL || tmp[1] == '\0') {
478 fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
479 progname, copy);
480 return -1;
481 }
482 if (tmp != copy) {
483 *tmp = '\0';
484 parent = copy;
485 *lastp = tmp + 1;
486 } else if (tmp[1] != '\0') {
487 *lastp = tmp + 1;
488 parent = "/";
489 } else {
490 *lastp = ".";
491 parent = "/";
492 }
493
494 res = chdir(parent);
495 if (res == -1) {
496 fprintf(stderr, "%s: failed to chdir to %s: %s\n",
497 progname, parent, strerror(errno));
498 return -1;
499 }
500
501 if (getcwd(buf, sizeof(buf)) == NULL) {
502 fprintf(stderr, "%s: failed to obtain current directory: %s\n",
503 progname, strerror(errno));
504 return -1;
505 }
506 if (strcmp(buf, parent) != 0) {
507 fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
508 parent, buf);
509 return -1;
510
511 }
512
513 return 0;
514}
515
516#ifndef IGNORE_MTAB
517static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
518{
519 int res;
520 char *copy;
521 const char *last;
522 int umount_flags = (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW;
523
524 if (getuid() != 0) {
525 res = may_unmount(mnt, quiet);
526 if (res == -1)
527 return -1;
528 }
529
530 copy = strdup(mnt);
531 if (copy == NULL) {
532 fprintf(stderr, "%s: failed to allocate memory\n", progname);
533 return -1;
534 }
535
536 drop_privs();
537 res = chdir_to_parent(copy, &last);
538 if (res == -1) {
539 restore_privs();
540 goto out;
541 }
542
543 res = umount2(last, umount_flags);
544 restore_privs();
545 if (res == -1 && !quiet) {
546 fprintf(stderr, "%s: failed to unmount %s: %s\n",
547 progname, mnt, strerror(errno));
548 }
549
550out:
551 free(copy);
552 if (res == -1)
553 return -1;
554
555 res = chdir("/");
556 if (res == -1) {
557 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
558 return -1;
559 }
560
561 return fuse_mnt_remove_mount(progname, mnt);
562}
563
564static int unmount_fuse(const char *mnt, int quiet, int lazy)
565{
566 int res;
567 int mtablock = lock_umount();
568
569 res = unmount_fuse_locked(mnt, quiet, lazy);
570 unlock_umount(mtablock);
571
572 return res;
573}
574
575static int count_fuse_fs_mtab(void)
576{
577 struct mntent *entp;
578 int count = 0;
579 const char *mtab = _PATH_MOUNTED;
580 FILE *fp = setmntent(mtab, "r");
581 if (fp == NULL) {
582 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
583 strerror(errno));
584 return -1;
585 }
586 while ((entp = GETMNTENT(fp)) != NULL) {
587 if (strcmp(entp->mnt_type, "fuse") == 0 ||
588 strncmp(entp->mnt_type, "fuse.", 5) == 0)
589 count ++;
590 }
591 endmntent(fp);
592 return count;
593}
594
595#ifdef HAVE_LISTMOUNT
596static int count_fuse_fs_ls_mnt(void)
597{
598 #define SMBUF_SIZE 1024
599 #define MNT_ID_LEN 128
600
601 int fuse_count = 0;
602 int n_mounts = 0;
603 int ret = 0;
604 uint64_t mnt_ids[MNT_ID_LEN];
605 unsigned char smbuf[SMBUF_SIZE];
606 struct mnt_id_req req = {
607 .size = sizeof(struct mnt_id_req),
608 };
609 struct statmount *sm;
610
611 for (;;) {
612 req.mnt_id = LSMT_ROOT;
613
614 n_mounts = syscall(SYS_listmount, &req, &mnt_ids, MNT_ID_LEN, 0);
615 if (n_mounts == -1) {
616 if (errno != ENOSYS) {
617 fprintf(stderr, "%s: failed to list mounts: %s\n", progname,
618 strerror(errno));
619 }
620 return -1;
621 }
622
623 for (int i = 0; i < n_mounts; i++) {
624 req.mnt_id = mnt_ids[i];
625 req.param = STATMOUNT_FS_TYPE;
626 ret = syscall(SYS_statmount, &req, &smbuf, SMBUF_SIZE, 0);
627 if (ret) {
628 if (errno == ENOENT)
629 continue;
630
631 fprintf(stderr, "%s: failed to stat mount %lld: %s\n", progname,
632 req.mnt_id, strerror(errno));
633 return -1;
634 }
635
636 sm = (struct statmount *)smbuf;
637 if (sm->mask & STATMOUNT_FS_TYPE &&
638 strcmp(&sm->str[sm->fs_type], "fuse") == 0)
639 fuse_count++;
640 }
641
642 if (n_mounts < MNT_ID_LEN)
643 break;
644 req.param = mnt_ids[MNT_ID_LEN - 1];
645 }
646 return fuse_count;
647}
648
649static int count_fuse_fs(void)
650{
651 int count = count_fuse_fs_ls_mnt();
652
653 return count >= 0 ? count : count_fuse_fs_mtab();
654}
655#else
656static int count_fuse_fs(void)
657{
658 return count_fuse_fs_mtab();
659}
660#endif
661
662#else /* IGNORE_MTAB */
663static int count_fuse_fs(void)
664{
665 return 0;
666}
667
668static int add_mount(const char *source, const char *mnt, const char *type,
669 const char *opts)
670{
671 (void) source;
672 (void) mnt;
673 (void) type;
674 (void) opts;
675 return 0;
676}
677
678static int unmount_fuse(const char *mnt, int quiet, int lazy)
679{
680 (void) quiet;
681 return fuse_mnt_umount(progname, mnt, mnt, lazy);
682}
683#endif /* IGNORE_MTAB */
684
685static void strip_line(char *line)
686{
687 char *s = strchr(line, '#');
688 size_t len;
689
690 if (s != NULL)
691 s[0] = '\0';
692 /*
693 * Count down rather than walk a pointer back: an empty or all-blank
694 * line would form line - 1, which is undefined behaviour even though
695 * the store that follows lands inside the buffer.
696 */
697 len = strlen(line);
698 while (len > 0 && isspace((unsigned char) line[len - 1]))
699 len--;
700 line[len] = '\0';
701 for (s = line; isspace((unsigned char) *s); s++);
702 if (s != line)
703 memmove(line, s, strlen(s)+1);
704}
705
706static void parse_line(char *line, int linenum)
707{
708 int tmp;
709 if (strcmp(line, "user_allow_other") == 0)
710 user_allow_other = 1;
711 else if (sscanf(line, "mount_max = %i", &tmp) == 1) {
712 if (tmp < -1)
713 fprintf(stderr,
714 "%s: invalid mount_max = %i in %s at line %i\n",
715 progname, tmp, FUSE_CONF, linenum);
716 else
717 mount_max = tmp;
718 }
719 else if(line[0])
720 fprintf(stderr,
721 "%s: unknown parameter in %s at line %i: '%s'\n",
722 progname, FUSE_CONF, linenum, line);
723}
724
725static void read_conf(void)
726{
727 FILE *fp = fopen(FUSE_CONF, "r");
728 if (fp != NULL) {
729 int linenum = 1;
730 char line[256];
731 int isnewline = 1;
732 while (fgets(line, sizeof(line), fp) != NULL) {
733 if (isnewline) {
734 if (line[strlen(line)-1] == '\n') {
735 strip_line(line);
736 parse_line(line, linenum);
737 } else {
738 isnewline = 0;
739 }
740 } else if(line[strlen(line)-1] == '\n') {
741 fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
742
743 isnewline = 1;
744 }
745 if (isnewline)
746 linenum ++;
747 }
748 if (!isnewline) {
749 fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
750
751 }
752 if (ferror(fp)) {
753 fprintf(stderr, "%s: reading %s: read failed\n", progname, FUSE_CONF);
754 exit(1);
755 }
756 fclose(fp);
757 } else if (errno != ENOENT) {
758 bool fatal = (errno != EACCES && errno != ELOOP &&
759 errno != ENAMETOOLONG && errno != ENOTDIR &&
760 errno != EOVERFLOW);
761 fprintf(stderr, "%s: failed to open %s: %s\n",
762 progname, FUSE_CONF, strerror(errno));
763 if (fatal)
764 exit(1);
765 }
766}
767
768static int begins_with(const char *s, const char *beg)
769{
770 if (strncmp(s, beg, strlen(beg)) == 0)
771 return 1;
772 else
773 return 0;
774}
775
776struct mount_flags {
777 const char *opt;
778 unsigned long flag;
779 int on;
780 int safe;
781};
782
783static struct mount_flags mount_flags[] = {
784 {"rw", MS_RDONLY, 0, 1},
785 {"ro", MS_RDONLY, 1, 1},
786 {"suid", MS_NOSUID, 0, 0},
787 {"nosuid", MS_NOSUID, 1, 1},
788 {"dev", MS_NODEV, 0, 0},
789 {"nodev", MS_NODEV, 1, 1},
790 {"exec", MS_NOEXEC, 0, 1},
791 {"noexec", MS_NOEXEC, 1, 1},
792 {"async", MS_SYNCHRONOUS, 0, 1},
793 {"sync", MS_SYNCHRONOUS, 1, 1},
794 {"atime", MS_NOATIME, 0, 1},
795 {"noatime", MS_NOATIME, 1, 1},
796 {"diratime", MS_NODIRATIME, 0, 1},
797 {"nodiratime", MS_NODIRATIME, 1, 1},
798 {"lazytime", MS_LAZYTIME, 1, 1},
799 {"nolazytime", MS_LAZYTIME, 0, 1},
800 {"relatime", MS_RELATIME, 1, 1},
801 {"norelatime", MS_RELATIME, 0, 1},
802 {"strictatime", MS_STRICTATIME, 1, 1},
803 {"nostrictatime", MS_STRICTATIME, 0, 1},
804 {"dirsync", MS_DIRSYNC, 1, 1},
805 {"symfollow", MS_NOSYMFOLLOW, 0, 1},
806 {"nosymfollow", MS_NOSYMFOLLOW, 1, 1},
807 {NULL, 0, 0, 0}
808};
809
810static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
811{
812 int i;
813
814 for (i = 0; mount_flags[i].opt != NULL; i++) {
815 const char *opt = mount_flags[i].opt;
816 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
817 *on = mount_flags[i].on;
818 *flag = mount_flags[i].flag;
819 if (!mount_flags[i].safe && getuid() != 0) {
820 *flag = 0;
821 fprintf(stderr,
822 "%s: unsafe option %s ignored\n",
823 progname, opt);
824 }
825 return 1;
826 }
827 }
828 return 0;
829}
830
831static int add_option(char **optsp, const char *opt, unsigned expand)
832{
833 char *newopts;
834 if (*optsp == NULL)
835 newopts = strdup(opt);
836 else {
837 unsigned oldsize = strlen(*optsp);
838 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
839 newopts = (char *) realloc(*optsp, newsize);
840 if (newopts)
841 sprintf(newopts + oldsize, ",%s", opt);
842 }
843 if (newopts == NULL) {
844 fprintf(stderr, "%s: failed to allocate memory\n", progname);
845 return -1;
846 }
847 *optsp = newopts;
848 return 0;
849}
850
851static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
852{
853 int i;
854 int l;
855
856 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
857 return -1;
858
859 for (i = 0; mount_flags[i].opt != NULL; i++) {
860 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
861 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
862 return -1;
863 }
864
865 if (add_option(mnt_optsp, opts, 0) == -1)
866 return -1;
867 /* remove comma from end of opts*/
868 l = strlen(*mnt_optsp);
869 if (l > 0 && (*mnt_optsp)[l-1] == ',')
870 (*mnt_optsp)[l-1] = '\0';
871 if (getuid() != 0) {
872 const char *user = get_user_name();
873 if (user == NULL)
874 return -1;
875
876 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
877 return -1;
878 strcat(*mnt_optsp, user);
879 }
880 return 0;
881}
882
883static int opt_eq(const char *s, unsigned len, const char *opt)
884{
885 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
886 return 1;
887 else
888 return 0;
889}
890
891static int get_string_opt(const char *s, unsigned len, const char *opt,
892 char **val)
893{
894 int i;
895 unsigned opt_len = strlen(opt);
896 char *d;
897
898 if (*val)
899 free(*val);
900 *val = (char *) malloc(len - opt_len + 1);
901 if (!*val) {
902 fprintf(stderr, "%s: failed to allocate memory\n", progname);
903 return 0;
904 }
905
906 d = *val;
907 s += opt_len;
908 len -= opt_len;
909 for (i = 0; i < len; i++) {
910 if (s[i] == '\\' && i + 1 < len)
911 i++;
912 *d++ = s[i];
913 }
914 *d = '\0';
915 return 1;
916}
917
918/* The kernel silently truncates the "data" argument to PAGE_SIZE-1 characters.
919 * This can be dangerous if it e.g. truncates the option "group_id=1000" to
920 * "group_id=1".
921 * This wrapper detects this case and bails out with an error.
922 */
923static int mount_notrunc(const char *source, const char *target,
924 const char *filesystemtype, unsigned long mountflags,
925 const char *data) {
926 if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
927 fprintf(stderr, "%s: mount options too long\n", progname);
928 errno = EINVAL;
929 return -1;
930 }
931 return mount(source, target, filesystemtype, mountflags, data);
932}
933
934
935static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
936 int fd, const char *opts, const char *dev, char **sourcep,
937 char **mnt_optsp)
938{
939 int res;
940 int flags = MS_NOSUID | MS_NODEV;
941 char *optbuf;
942 char *mnt_opts = NULL;
943 const char *s;
944 char *d;
945 char *fsname = NULL;
946 char *subtype = NULL;
947 char *source = NULL;
948 char *type = NULL;
949 int blkdev = 0;
950
951 optbuf = (char *) malloc(strlen(opts) + 128);
952 if (!optbuf) {
953 fprintf(stderr, "%s: failed to allocate memory\n", progname);
954 return -1;
955 }
956
957 for (s = opts, d = optbuf; *s;) {
958 unsigned len;
959 const char *fsname_str = "fsname=";
960 const char *subtype_str = "subtype=";
961 bool escape_ok = begins_with(s, fsname_str) ||
962 begins_with(s, subtype_str);
963 for (len = 0; s[len]; len++) {
964 if (escape_ok && s[len] == '\\' && s[len + 1])
965 len++;
966 else if (s[len] == ',')
967 break;
968 }
969 if (begins_with(s, fsname_str)) {
970 if (!get_string_opt(s, len, fsname_str, &fsname))
971 goto err;
972 } else if (begins_with(s, subtype_str)) {
973 if (!get_string_opt(s, len, subtype_str, &subtype))
974 goto err;
975 } else if (opt_eq(s, len, "blkdev")) {
976 if (getuid() != 0) {
977 fprintf(stderr,
978 "%s: option blkdev is privileged\n",
979 progname);
980 goto err;
981 }
982 blkdev = 1;
983 } else if (opt_eq(s, len, "auto_unmount")) {
984 auto_unmount = 1;
985 } else if (!opt_eq(s, len, "nonempty") &&
986 !begins_with(s, "fd=") &&
987 !begins_with(s, "rootmode=") &&
988 !begins_with(s, "user_id=") &&
989 !begins_with(s, "group_id=")) {
990 int on;
991 int flag;
992 int skip_option = 0;
993 if (opt_eq(s, len, "large_read")) {
994 struct utsname utsname;
995 unsigned kmaj, kmin;
996 res = uname(&utsname);
997 if (res == 0 &&
998 sscanf(utsname.release, "%u.%u",
999 &kmaj, &kmin) == 2 &&
1000 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
1001 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
1002 skip_option = 1;
1003 }
1004 }
1005 if (getuid() != 0 && !user_allow_other &&
1006 (opt_eq(s, len, "allow_other") ||
1007 opt_eq(s, len, "allow_root"))) {
1008 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
1009 goto err;
1010 }
1011 if (!skip_option) {
1012 if (find_mount_flag(s, len, &on, &flag)) {
1013 if (on)
1014 flags |= flag;
1015 else
1016 flags &= ~flag;
1017 } else if (opt_eq(s, len, "default_permissions") ||
1018 opt_eq(s, len, "allow_other") ||
1019 begins_with(s, "max_read=") ||
1020 begins_with(s, "blksize=")) {
1021 memcpy(d, s, len);
1022 d += len;
1023 *d++ = ',';
1024 } else {
1025 fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, s);
1026 exit(1);
1027 }
1028 }
1029 }
1030 s += len;
1031 if (*s)
1032 s++;
1033 }
1034 *d = '\0';
1035 res = get_mnt_opts(flags, optbuf, &mnt_opts);
1036 if (res == -1)
1037 goto err;
1038
1039 sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
1040 fd, rootmode, getuid(), getgid());
1041
1042 source = malloc((fsname ? strlen(fsname) : 0) +
1043 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
1044
1045 type = malloc((subtype ? strlen(subtype) : 0) + 32);
1046 if (!type || !source) {
1047 fprintf(stderr, "%s: failed to allocate memory\n", progname);
1048 goto err;
1049 }
1050
1051 if (subtype)
1052 sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
1053 else
1054 strcpy(type, blkdev ? "fuseblk" : "fuse");
1055
1056 if (fsname)
1057 strcpy(source, fsname);
1058 else
1059 strcpy(source, subtype ? subtype : dev);
1060
1061 res = mount_notrunc(source, mnt, type, flags, optbuf);
1062 if (res == -1 && errno == ENODEV && subtype) {
1063 /* Probably missing subtype support */
1064 strcpy(type, blkdev ? "fuseblk" : "fuse");
1065 if (fsname) {
1066 if (!blkdev)
1067 sprintf(source, "%s#%s", subtype, fsname);
1068 } else {
1069 strcpy(source, type);
1070 }
1071
1072 res = mount_notrunc(source, mnt, type, flags, optbuf);
1073 }
1074 if (res == -1 && errno == EINVAL) {
1075 /* It could be an old version not supporting group_id */
1076 sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
1077 fd, rootmode, getuid());
1078 res = mount_notrunc(source, mnt, type, flags, optbuf);
1079 }
1080 if (res == -1) {
1081 int errno_save = errno;
1082 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
1083 fprintf(stderr, "%s: 'fuseblk' support missing\n",
1084 progname);
1085 else
1086 fprintf(stderr, "%s: mount failed: %s\n", progname,
1087 strerror(errno_save));
1088 goto err;
1089 }
1090 *sourcep = source;
1091 *typep = type;
1092 *mnt_optsp = mnt_opts;
1093 free(fsname);
1094 free(optbuf);
1095
1096 return 0;
1097
1098err:
1099 free(fsname);
1100 free(subtype);
1101 free(source);
1102 free(type);
1103 free(mnt_opts);
1104 free(optbuf);
1105 return -1;
1106}
1107
1108/*
1109 * Resolve the caller-supplied mountpoint exactly once and hand back a
1110 * descriptor for the inode it named. O_NOFOLLOW refuses a symlink outright for
1111 * an unprivileged caller; root keeps following them, as it always has.
1112 */
1113static int pin_mountpoint(const char *mnt, bool is_root, struct stat *stbuf)
1114{
1115 int open_flags = O_PATH | O_CLOEXEC;
1116 int fd;
1117
1118 if (!is_root)
1119 open_flags |= O_NOFOLLOW;
1120
1121 fd = open(mnt, open_flags);
1122 if (fd == -1) {
1123 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
1124 progname, mnt, strerror(errno));
1125 return -1;
1126 }
1127
1128 if (fstat(fd, stbuf) == -1) {
1129 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
1130 progname, mnt, strerror(errno));
1131 close(fd);
1132 return -1;
1133 }
1134
1135 return fd;
1136}
1137
1138static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
1139{
1140 int res;
1141 int fd;
1142 const char *mnt = *mntp;
1143 const bool is_root = getuid() == 0;
1144 struct statfs fs_buf;
1145 size_t i;
1146
1147 fd = pin_mountpoint(mnt, is_root, stbuf);
1148 if (fd == -1)
1149 return -1;
1150
1151 /* No permission checking is done for root */
1152 if (is_root) {
1153 *mountpoint_fd = fd;
1154 return 0;
1155 }
1156
1157 if (S_ISDIR(stbuf->st_mode)) {
1158 res = fchdir(fd);
1159 if (res == -1) {
1160 fprintf(stderr,
1161 "%s: failed to chdir to mountpoint: %s\n",
1162 progname, strerror(errno));
1163 goto out_close;
1164 }
1165 /*
1166 * The pinned directory is the CWD, so "." names it without
1167 * going through the caller-supplied path a second time.
1168 */
1169 *mntp = ".";
1170
1171 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
1172 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
1173 progname, mnt);
1174 res = -1;
1175 goto out_close;
1176 }
1177
1178 res = access(*mntp, W_OK);
1179 if (res == -1) {
1180 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
1181 progname, mnt);
1182 goto out_close;
1183 }
1184 } else if (S_ISREG(stbuf->st_mode)) {
1185 static char procfile[256];
1186 int wfd;
1187
1188 snprintf(procfile, sizeof(procfile), "/proc/self/fd/%i", fd);
1189
1190 /*
1191 * Reopening the pinned inode through its magic link both tests
1192 * write access and yields the descriptor mount(2) is pointed
1193 * at, so the caller's path is never resolved again.
1194 */
1195 wfd = open(procfile, O_WRONLY);
1196 if (wfd == -1) {
1197 fprintf(stderr, "%s: failed to open %s: %s\n",
1198 progname, mnt, strerror(errno));
1199 res = -1;
1200 goto out_close;
1201 }
1202 close(fd);
1203 fd = wfd;
1204
1205 snprintf(procfile, sizeof(procfile), "/proc/self/fd/%i", fd);
1206 *mntp = procfile;
1207 } else {
1208 fprintf(stderr,
1209 "%s: mountpoint %s is not a directory or a regular file\n",
1210 progname, mnt);
1211 res = -1;
1212 goto out_close;
1213 }
1214
1215 /* Do not permit mounting over anything in procfs - it has a couple
1216 * places to which we have "write access" without being supposed to be
1217 * able to just put anything we want there.
1218 * Luckily, without allow_other, we can't get other users to actually
1219 * use any fake information we try to put there anyway.
1220 * Use a whitelist to be safe. */
1221 if (statfs(*mntp, &fs_buf)) {
1222 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
1223 progname, mnt, strerror(errno));
1224 res = -1;
1225 goto out_close;
1226 }
1227
1228 /* Define permitted filesystems for the mount target. This was
1229 * originally the same list as used by the ecryptfs mount helper
1230 * (https://bazaar.launchpad.net/~ecryptfs/ecryptfs/trunk/view/head:/src/utils/mount.ecryptfs_private.c#L225)
1231 * but got expanded as we found more filesystems that needed to be
1232 * overlaid. */
1233 typeof(fs_buf.f_type) f_type_whitelist[] = {
1234 0x61756673 /* AUFS_SUPER_MAGIC */,
1235 0x00000187 /* AUTOFS_SUPER_MAGIC */,
1236 0xCA451A4E /* BCACHEFS_STATFS_MAGIC */,
1237 0x9123683E /* BTRFS_SUPER_MAGIC */,
1238 0x00C36400 /* CEPH_SUPER_MAGIC */,
1239 0xFF534D42 /* CIFS_MAGIC_NUMBER */,
1240 0x0000F15F /* ECRYPTFS_SUPER_MAGIC */,
1241 0X2011BAB0 /* EXFAT_SUPER_MAGIC */,
1242 0x0000EF53 /* EXT[234]_SUPER_MAGIC */,
1243 0xF2F52010 /* F2FS_SUPER_MAGIC */,
1244 0x65735546 /* FUSE_SUPER_MAGIC */,
1245 0x01161970 /* GFS2_MAGIC */,
1246 0x47504653 /* GPFS_SUPER_MAGIC */,
1247 0x0000482b /* HFSPLUS_SUPER_MAGIC */,
1248 0x000072B6 /* JFFS2_SUPER_MAGIC */,
1249 0x3153464A /* JFS_SUPER_MAGIC */,
1250 0x0BD00BD0 /* LL_SUPER_MAGIC */,
1251 0X00004D44 /* MSDOS_SUPER_MAGIC */,
1252 0x0000564C /* NCP_SUPER_MAGIC */,
1253 0x00006969 /* NFS_SUPER_MAGIC */,
1254 0x00003434 /* NILFS_SUPER_MAGIC */,
1255 0x5346544E /* NTFS_SB_MAGIC */,
1256 0x7366746E /* NTFS3_SUPER_MAGIC */,
1257 0x5346414f /* OPENAFS_SUPER_MAGIC */,
1258 0x794C7630 /* OVERLAYFS_SUPER_MAGIC */,
1259 0xAAD7AAEA /* PANFS_SUPER_MAGIC */,
1260 0x52654973 /* REISERFS_SUPER_MAGIC */,
1261 0xFE534D42 /* SMB2_SUPER_MAGIC */,
1262 0x73717368 /* SQUASHFS_MAGIC */,
1263 0x01021994 /* TMPFS_MAGIC */,
1264 0x24051905 /* UBIFS_SUPER_MAGIC */,
1265 0x18031977 /* WEKAFS_SUPER_MAGIC */,
1266#if __SIZEOF_LONG__ > 4
1267 0x736675005346544e /* UFSD */,
1268#endif
1269 0x58465342 /* XFS_SB_MAGIC */,
1270 0x2FC12FC1 /* ZFS_SUPER_MAGIC */,
1271 0x858458f6 /* RAMFS_MAGIC */,
1272 };
1273 for (i = 0; i < sizeof(f_type_whitelist)/sizeof(f_type_whitelist[0]); i++) {
1274 if (f_type_whitelist[i] == fs_buf.f_type) {
1275 *mountpoint_fd = fd;
1276 return 0;
1277 }
1278 }
1279
1280 fprintf(stderr, "%s: mounting over filesystem type %#010lx is forbidden\n",
1281 progname, (unsigned long)fs_buf.f_type);
1282 res = -1;
1283
1284out_close:
1285 close(fd);
1286 return res;
1287}
1288
1289static int open_fuse_device(const char *dev)
1290{
1291 int fd;
1292
1293 drop_privs();
1294 fd = open(dev, O_RDWR);
1295 if (fd == -1) {
1296 if (errno == ENODEV || errno == ENOENT)/* check for ENOENT too, for the udev case */
1297 fprintf(stderr,
1298 "%s: fuse device %s not found. Kernel module not loaded?\n",
1299 progname, dev);
1300 else
1301 fprintf(stderr,
1302 "%s: failed to open %s: %s\n", progname, dev, strerror(errno));
1303 }
1304 restore_privs();
1305 return fd;
1306}
1307
1308static int mount_fuse(const char *mnt, const char *opts, const char **type)
1309{
1310 int res;
1311 int fd;
1312 const char *dev = getenv(FUSE_KERN_DEVICE_ENV) ?: FUSE_DEV;
1313 struct stat stbuf;
1314 char *source = NULL;
1315 char *mnt_opts = NULL;
1316 const char *real_mnt = mnt;
1317 int mountpoint_fd = -1;
1318 char *do_mount_opts = NULL;
1319 char *x_opts = NULL;
1320
1321 fd = open_fuse_device(dev);
1322 if (fd == -1)
1323 return -1;
1324
1325 drop_privs();
1326 read_conf();
1327
1328 if (getuid() != 0 && mount_max != -1) {
1329 int mount_count = count_fuse_fs();
1330 if (mount_count >= mount_max) {
1331 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1332 goto fail_close_fd;
1333 }
1334 }
1335
1336 // Extract any options starting with "x-"
1337 res= extract_x_options(opts, &do_mount_opts, &x_opts);
1338 if (res)
1339 goto fail_close_fd;
1340
1341 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1342 restore_privs();
1343 if (res != -1)
1344 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT,
1345 fd, do_mount_opts, dev, &source, &mnt_opts);
1346
1347 if (mountpoint_fd != -1)
1348 close(mountpoint_fd);
1349
1350 if (res == -1)
1351 goto fail_close_fd;
1352
1353 res = chdir("/");
1354 if (res == -1) {
1355 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1356 goto fail_close_fd;
1357 }
1358
1359 if (geteuid() == 0) {
1360 if (x_opts && strlen(x_opts) > 0) {
1361 /*
1362 * Add back the options starting with "x-" to opts from
1363 * do_mount. +2 for ',' and '\0'
1364 */
1365 size_t mnt_opts_len = strlen(mnt_opts);
1366 size_t x_mnt_opts_len = mnt_opts_len+
1367 strlen(x_opts) + 2;
1368 char *x_mnt_opts = calloc(1, x_mnt_opts_len);
1369
1370 if (mnt_opts_len) {
1371 strcpy(x_mnt_opts, mnt_opts);
1372 strncat(x_mnt_opts, ",", 2);
1373 }
1374
1375 strncat(x_mnt_opts, x_opts,
1376 x_mnt_opts_len - mnt_opts_len - 2);
1377
1378 free(mnt_opts);
1379 mnt_opts = x_mnt_opts;
1380 }
1381
1382 res = add_mount(source, mnt, *type, mnt_opts);
1383 if (res == -1) {
1384 /* Can't clean up mount in a non-racy way */
1385 goto fail_close_fd;
1386 }
1387 }
1388
1389out_free:
1390 free(source);
1391 free(mnt_opts);
1392 free(x_opts);
1393 free(do_mount_opts);
1394
1395 return fd;
1396
1397fail_close_fd:
1398 close(fd);
1399 fd = -1;
1400 goto out_free;
1401}
1402
1403static int send_fd(int sock_fd, int fd)
1404{
1405 int retval;
1406 struct msghdr msg;
1407 struct cmsghdr *p_cmsg;
1408 struct iovec vec;
1409 size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1410 int *p_fds;
1411 char sendchar = 0;
1412
1413 msg.msg_control = cmsgbuf;
1414 msg.msg_controllen = sizeof(cmsgbuf);
1415 p_cmsg = CMSG_FIRSTHDR(&msg);
1416 p_cmsg->cmsg_level = SOL_SOCKET;
1417 p_cmsg->cmsg_type = SCM_RIGHTS;
1418 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1419 p_fds = (int *) CMSG_DATA(p_cmsg);
1420 *p_fds = fd;
1421 msg.msg_controllen = p_cmsg->cmsg_len;
1422 msg.msg_name = NULL;
1423 msg.msg_namelen = 0;
1424 msg.msg_iov = &vec;
1425 msg.msg_iovlen = 1;
1426 msg.msg_flags = 0;
1427 /* "To pass file descriptors or credentials you need to send/read at
1428 * least one byte" (man 7 unix) */
1429 vec.iov_base = &sendchar;
1430 vec.iov_len = sizeof(sendchar);
1431 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1432 if (retval != 1) {
1433 perror("sending file descriptor");
1434 return -1;
1435 }
1436 return 0;
1437}
1438
1439/* Helper for should_auto_unmount
1440 *
1441 * Try opening `mnt` with uid and gid of the calling process.
1442 */
1443static int check_ENOTCONN_as_owner(const char *mnt)
1444{
1445 int pid = fork();
1446 if(pid == -1) {
1447 perror("fuse: recheck_ENOTCONN_as_owner can't fork");
1448 _exit(EXIT_FAILURE);
1449 } else if(pid == 0) {
1450 uid_t uid = getuid();
1451 gid_t gid = getgid();
1452 if(setresgid(gid, gid, gid) == -1) {
1453 perror("fuse: can't set resgid");
1454 _exit(EXIT_FAILURE);
1455 }
1456 if(setresuid(uid, uid, uid) == -1) {
1457 perror("fuse: can't set resuid");
1458 _exit(EXIT_FAILURE);
1459 }
1460
1461 int fd = open(mnt, O_RDONLY);
1462 if (fd == -1 && (errno == ENOTCONN || errno == ECONNABORTED))
1463 _exit(EXIT_SUCCESS);
1464 else
1465 _exit(EXIT_FAILURE);
1466 } else {
1467 int status;
1468 int res = waitpid(pid, &status, 0);
1469 if (res == -1) {
1470 perror("fuse: waiting for child failed");
1471 _exit(EXIT_FAILURE);
1472 }
1473 return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
1474 }
1475}
1476
1477/* The parent fuse process has died: decide whether to auto_unmount.
1478 *
1479 * In the normal case (umount or fusermount -u), the filesystem
1480 * has already been unmounted. If we simply unmount again we can
1481 * cause problems with stacked mounts (e.g. autofs).
1482 *
1483 * So we unmount here only in abnormal case where fuse process has
1484 * died without unmount happening. To detect this, we first look in
1485 * the mount table to make sure the mountpoint is still mounted and
1486 * has proper type. If so, we then see if opening the mount dir is
1487 * returning 'Transport endpoint is not connected'.
1488 *
1489 * The order of these is important, because if autofs is in use,
1490 * opening the dir to check for ENOTCONN will cause a new mount
1491 * in the normal case where filesystem has been unmounted cleanly.
1492 */
1493static int should_auto_unmount(const char *mnt, const char *type)
1494{
1495 char *copy;
1496 const char *last;
1497 int result = 0;
1498
1499 copy = strdup(mnt);
1500 if (copy == NULL) {
1501 fprintf(stderr, "%s: failed to allocate memory\n", progname);
1502 return 0;
1503 }
1504
1505 if (chdir_to_parent(copy, &last) == -1)
1506 goto out;
1507 if (check_is_mount(last, mnt, type) == -1)
1508 goto out;
1509
1510 result = check_ENOTCONN_as_owner(mnt);
1511out:
1512 free(copy);
1513 return result;
1514}
1515
1516static void usage(void)
1517{
1518 printf("%s: [options] mountpoint\n"
1519 "Options:\n"
1520 " -h print help\n"
1521 " -V print version\n"
1522 " -o opt[,opt...] mount options\n"
1523 " -u unmount\n"
1524 " -q quiet\n"
1525 " -z lazy unmount\n",
1526 progname);
1527 exit(1);
1528}
1529
1530static void show_version(void)
1531{
1532 printf("fusermount3 version: %s\n", PACKAGE_VERSION);
1533 exit(0);
1534}
1535
1536static void close_range_loop(int min_fd, int max_fd, int cfd)
1537{
1538 for (int fd = min_fd; fd <= max_fd; fd++)
1539 if (fd != cfd)
1540 close(fd);
1541}
1542
1543/*
1544 * Close all inherited fds that are not needed
1545 * Ideally these wouldn't come up at all, applications should better
1546 * use FD_CLOEXEC / O_CLOEXEC
1547 */
1548static int close_inherited_fds(int cfd)
1549{
1550 int rc = -1;
1551 int nullfd;
1552
1553 /* We can't even report an error */
1554 if (cfd <= STDERR_FILENO)
1555 return -EINVAL;
1556
1557#ifdef HAVE_CLOSE_RANGE
1558 if (cfd < STDERR_FILENO + 2) {
1559 close_range_loop(STDERR_FILENO + 1, cfd - 1, cfd);
1560 } else {
1561 rc = close_range(STDERR_FILENO + 1, cfd - 1, 0);
1562 if (rc < 0)
1563 goto fallback;
1564 }
1565
1566 /* Close high range */
1567 rc = close_range(cfd + 1, ~0U, 0);
1568#else
1569 goto fallback; /* make use of fallback to avoid compiler warnings */
1570#endif
1571
1572fallback:
1573 if (rc < 0) {
1574 int max_fd = sysconf(_SC_OPEN_MAX) - 1;
1575
1576 close_range_loop(STDERR_FILENO + 1, max_fd, cfd);
1577 }
1578
1579 nullfd = open("/dev/null", O_RDWR);
1580 if (nullfd < 0) {
1581 perror("fusermount: cannot open /dev/null");
1582 return -errno;
1583 }
1584
1585 /* Redirect stdin, stdout, stderr to /dev/null */
1586 dup2(nullfd, STDIN_FILENO);
1587 dup2(nullfd, STDOUT_FILENO);
1588 dup2(nullfd, STDERR_FILENO);
1589 if (nullfd > STDERR_FILENO)
1590 close(nullfd);
1591
1592 return 0;
1593}
1594
1595int main(int argc, char *argv[])
1596{
1597 sigset_t sigset;
1598 int ch;
1599 int fd;
1600 int res;
1601 char *origmnt;
1602 char *mnt;
1603 static int unmount = 0;
1604 static int lazy = 0;
1605 static int quiet = 0;
1606 char *commfd = NULL;
1607 long cfd;
1608 const char *opts = "";
1609 const char *type = NULL;
1610 int setup_auto_unmount_only = 0;
1611
1612 static const struct option long_opts[] = {
1613 {"unmount", no_argument, NULL, 'u'},
1614 {"lazy", no_argument, NULL, 'z'},
1615 {"quiet", no_argument, NULL, 'q'},
1616 {"help", no_argument, NULL, 'h'},
1617 {"version", no_argument, NULL, 'V'},
1618 {"options", required_argument, NULL, 'o'},
1619 // Note: auto-unmount and comm-fd don't have short versions.
1620 // They'ne meant for internal use by mount.c
1621 {"auto-unmount", no_argument, NULL, 'U'},
1622 {"comm-fd", required_argument, NULL, 'c'},
1623 {0, 0, 0, 0}};
1624
1625 progname = strdup(argc > 0 ? argv[0] : "fusermount");
1626 if (progname == NULL) {
1627 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1628 exit(1);
1629 }
1630
1631 while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1632 NULL)) != -1) {
1633 switch (ch) {
1634 case 'h':
1635 usage();
1636 break;
1637
1638 case 'V':
1639 show_version();
1640 break;
1641
1642 case 'o':
1643 opts = optarg;
1644 break;
1645
1646 case 'u':
1647 unmount = 1;
1648 break;
1649 case 'U':
1650 unmount = 1;
1651 auto_unmount = 1;
1652 setup_auto_unmount_only = 1;
1653 break;
1654 case 'c':
1655 commfd = optarg;
1656 break;
1657 case 'z':
1658 lazy = 1;
1659 break;
1660
1661 case 'q':
1662 quiet = 1;
1663 break;
1664
1665 default:
1666 exit(1);
1667 }
1668 }
1669
1670 if (lazy && !unmount) {
1671 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1672 exit(1);
1673 }
1674
1675 if (optind >= argc) {
1676 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1677 exit(1);
1678 } else if (argc > optind + 1) {
1679 fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1680 progname);
1681 exit(1);
1682 }
1683
1684 origmnt = argv[optind];
1685
1686 drop_privs();
1687 mnt = fuse_mnt_resolve_path(progname, origmnt);
1688 if (mnt != NULL) {
1689 res = chdir("/");
1690 if (res == -1) {
1691 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1692 goto err_out;
1693 }
1694 }
1695 restore_privs();
1696 if (mnt == NULL)
1697 exit(1);
1698
1699 umask(033);
1700 if (!setup_auto_unmount_only && unmount)
1701 goto do_unmount;
1702
1703 if(commfd == NULL)
1704 commfd = getenv(FUSE_COMMFD_ENV);
1705 if (commfd == NULL) {
1706 fprintf(stderr, "%s: old style mounting not supported\n",
1707 progname);
1708 goto err_out;
1709 }
1710
1711 res = libfuse_strtol(commfd, &cfd);
1712 if (res) {
1713 fprintf(stderr,
1714 "%s: invalid _FUSE_COMMFD: %s\n",
1715 progname, commfd);
1716 goto err_out;
1717
1718 }
1719
1720 {
1721 struct stat statbuf;
1722 if (fstat(cfd, &statbuf) == -1) {
1723 fprintf(stderr,
1724 "%s: fstat of comm fd %li failed: %s\n",
1725 progname, cfd, strerror(errno));
1726 goto err_out;
1727 }
1728 if(!S_ISSOCK(statbuf.st_mode)) {
1729 fprintf(stderr,
1730 "%s: file descriptor %li is not a socket, can't send fuse fd\n",
1731 progname, cfd);
1732 goto err_out;
1733 }
1734 }
1735
1736 if (setup_auto_unmount_only)
1737 goto wait_for_auto_unmount;
1738
1739 fd = mount_fuse(mnt, opts, &type);
1740 if (fd == -1)
1741 goto err_out;
1742
1743 res = send_fd(cfd, fd);
1744 if (res != 0) {
1745 unmount_fuse(mnt, 1, 1); /* lazy umount */
1746 goto err_out;
1747 }
1748 close(fd);
1749
1750 if (!auto_unmount) {
1751 free(mnt);
1752 free((void*) type);
1753 return 0;
1754 }
1755
1756wait_for_auto_unmount:
1757 /* Become a daemon and wait for the parent to exit or die.
1758 ie For the control socket to get closed.
1759 Btw, we don't want to use daemon() function here because
1760 it forks and messes with the file descriptors. */
1761
1762 res = close_inherited_fds(cfd);
1763 if (res < 0)
1764 exit(EXIT_FAILURE);
1765
1766 setsid();
1767 res = chdir("/");
1768 if (res == -1) {
1769 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1770 goto err_out;
1771 }
1772
1773 sigfillset(&sigset);
1774 sigprocmask(SIG_BLOCK, &sigset, NULL);
1775
1776 lazy = 1;
1777 quiet = 1;
1778
1779 while (1) {
1780 unsigned char buf[16];
1781 int n = recv(cfd, buf, sizeof(buf), 0);
1782 if (!n)
1783 break;
1784
1785 if (n < 0) {
1786 if (errno == EINTR)
1787 continue;
1788 break;
1789 }
1790 }
1791
1792 if (!should_auto_unmount(mnt, type)) {
1793 goto success_out;
1794 }
1795
1796do_unmount:
1797 if (geteuid() == 0)
1798 res = unmount_fuse(mnt, quiet, lazy);
1799 else {
1800 res = umount2(mnt, (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW);
1801 if (res == -1 && !quiet)
1802 fprintf(stderr,
1803 "%s: failed to unmount %s: %s\n",
1804 progname, mnt, strerror(errno));
1805 }
1806 if (res == -1)
1807 goto err_out;
1808
1809success_out:
1810 free((void*) type);
1811 free(mnt);
1812 return 0;
1813
1814err_out:
1815 free((void*) type);
1816 free(mnt);
1817 exit(1);
1818}