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 GPL.
6  See the file COPYING.
7 */
8 /* This program does the mounting and unmounting of FUSE filesystems */
9 
10 #define _GNU_SOURCE /* for clone */
11 #include <config.h>
12 
13 #include "mount_util.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <getopt.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <pwd.h>
23 #include <paths.h>
24 #include <mntent.h>
25 #include <sys/wait.h>
26 #include <sys/stat.h>
27 #include <sys/mount.h>
28 #include <sys/fsuid.h>
29 #include <sys/socket.h>
30 #include <sys/utsname.h>
31 #include <sched.h>
32 #include <stdbool.h>
33 #include <sys/vfs.h>
34 
35 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
36 
37 #define FUSE_DEV "/dev/fuse"
38 #define FUSE_CONF "/etc/fuse.conf"
39 
40 #ifndef MS_DIRSYNC
41 #define MS_DIRSYNC 128
42 #endif
43 #ifndef MS_REC
44 #define MS_REC 16384
45 #endif
46 #ifndef MS_PRIVATE
47 #define MS_PRIVATE (1<<18)
48 #endif
49 
50 #ifndef UMOUNT_DETACH
51 #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
52 #endif
53 #ifndef UMOUNT_NOFOLLOW
54 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
55 #endif
56 #ifndef UMOUNT_UNUSED
57 #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
58 #endif
59 
60 static const char *progname;
61 
62 static int user_allow_other = 0;
63 static int mount_max = 1000;
64 
65 static int auto_unmount = 0;
66 
67 static const char *get_user_name(void)
68 {
69  struct passwd *pw = getpwuid(getuid());
70  if (pw != NULL && pw->pw_name != NULL)
71  return pw->pw_name;
72  else {
73  fprintf(stderr, "%s: could not determine username\n", progname);
74  return NULL;
75  }
76 }
77 
78 static uid_t oldfsuid;
79 static gid_t oldfsgid;
80 
81 static void drop_privs(void)
82 {
83  if (getuid() != 0) {
84  oldfsuid = setfsuid(getuid());
85  oldfsgid = setfsgid(getgid());
86  }
87 }
88 
89 static void restore_privs(void)
90 {
91  if (getuid() != 0) {
92  setfsuid(oldfsuid);
93  setfsgid(oldfsgid);
94  }
95 }
96 
97 #ifndef IGNORE_MTAB
98 /*
99  * Make sure that /etc/mtab is checked and updated atomically
100  */
101 static int lock_umount(void)
102 {
103  const char *mtab_lock = _PATH_MOUNTED ".fuselock";
104  int mtablock;
105  int res;
106  struct stat mtab_stat;
107 
108  /* /etc/mtab could be a symlink to /proc/mounts */
109  if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
110  return -1;
111 
112  mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
113  if (mtablock == -1) {
114  fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
115  progname, strerror(errno));
116  return -1;
117  }
118  res = lockf(mtablock, F_LOCK, 0);
119  if (res < 0) {
120  fprintf(stderr, "%s: error getting lock: %s\n", progname,
121  strerror(errno));
122  close(mtablock);
123  return -1;
124  }
125 
126  return mtablock;
127 }
128 
129 static void unlock_umount(int mtablock)
130 {
131  if (mtablock >= 0) {
132  int res;
133 
134  res = lockf(mtablock, F_ULOCK, 0);
135  if (res < 0) {
136  fprintf(stderr, "%s: error releasing lock: %s\n",
137  progname, strerror(errno));
138  }
139  close(mtablock);
140  }
141 }
142 
143 static int add_mount(const char *source, const char *mnt, const char *type,
144  const char *opts)
145 {
146  return fuse_mnt_add_mount(progname, source, mnt, type, opts);
147 }
148 
149 static int may_unmount(const char *mnt, int quiet)
150 {
151  struct mntent *entp;
152  FILE *fp;
153  const char *user = NULL;
154  char uidstr[32];
155  unsigned uidlen = 0;
156  int found;
157  const char *mtab = _PATH_MOUNTED;
158 
159  user = get_user_name();
160  if (user == NULL)
161  return -1;
162 
163  fp = setmntent(mtab, "r");
164  if (fp == NULL) {
165  fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
166  strerror(errno));
167  return -1;
168  }
169 
170  uidlen = sprintf(uidstr, "%u", getuid());
171 
172  found = 0;
173  while ((entp = getmntent(fp)) != NULL) {
174  if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
175  (strcmp(entp->mnt_type, "fuse") == 0 ||
176  strcmp(entp->mnt_type, "fuseblk") == 0 ||
177  strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
178  strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
179  char *p = strstr(entp->mnt_opts, "user=");
180  if (p &&
181  (p == entp->mnt_opts || *(p-1) == ',') &&
182  strcmp(p + 5, user) == 0) {
183  found = 1;
184  break;
185  }
186  /* /etc/mtab is a link pointing to
187  /proc/mounts: */
188  else if ((p =
189  strstr(entp->mnt_opts, "user_id=")) &&
190  (p == entp->mnt_opts ||
191  *(p-1) == ',') &&
192  strncmp(p + 8, uidstr, uidlen) == 0 &&
193  (*(p+8+uidlen) == ',' ||
194  *(p+8+uidlen) == '\0')) {
195  found = 1;
196  break;
197  }
198  }
199  }
200  endmntent(fp);
201 
202  if (!found) {
203  if (!quiet)
204  fprintf(stderr,
205  "%s: entry for %s not found in %s\n",
206  progname, mnt, mtab);
207  return -1;
208  }
209 
210  return 0;
211 }
212 
213 /*
214  * Check whether the file specified in "fusermount3 -u" is really a
215  * mountpoint and not a symlink. This is necessary otherwise the user
216  * could move the mountpoint away and replace it with a symlink
217  * pointing to an arbitrary mount, thereby tricking fusermount3 into
218  * unmounting that (umount(2) will follow symlinks).
219  *
220  * This is the child process running in a separate mount namespace, so
221  * we don't mess with the global namespace and if the process is
222  * killed for any reason, mounts are automatically cleaned up.
223  *
224  * First make sure nothing is propagated back into the parent
225  * namespace by marking all mounts "private".
226  *
227  * Then bind mount parent onto a stable base where the user can't move
228  * it around.
229  *
230  * Finally check /proc/mounts for an entry matching the requested
231  * mountpoint. If it's found then we are OK, and the user can't move
232  * it around within the parent directory as rename() will return
233  * EBUSY. Be careful to ignore any mounts that existed before the
234  * bind.
235  */
236 static int check_is_mount_child(void *p)
237 {
238  const char **a = p;
239  const char *last = a[0];
240  const char *mnt = a[1];
241  int res;
242  const char *procmounts = "/proc/mounts";
243  int found;
244  FILE *fp;
245  struct mntent *entp;
246  int count;
247 
248  res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
249  if (res == -1) {
250  fprintf(stderr, "%s: failed to mark mounts private: %s\n",
251  progname, strerror(errno));
252  return 1;
253  }
254 
255  fp = setmntent(procmounts, "r");
256  if (fp == NULL) {
257  fprintf(stderr, "%s: failed to open %s: %s\n", progname,
258  procmounts, strerror(errno));
259  return 1;
260  }
261 
262  count = 0;
263  while (getmntent(fp) != NULL)
264  count++;
265  endmntent(fp);
266 
267  fp = setmntent(procmounts, "r");
268  if (fp == NULL) {
269  fprintf(stderr, "%s: failed to open %s: %s\n", progname,
270  procmounts, strerror(errno));
271  return 1;
272  }
273 
274  res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
275  if (res == -1) {
276  fprintf(stderr, "%s: failed to bind parent to /: %s\n",
277  progname, strerror(errno));
278  return 1;
279  }
280 
281  found = 0;
282  while ((entp = getmntent(fp)) != NULL) {
283  if (count > 0) {
284  count--;
285  continue;
286  }
287  if (entp->mnt_dir[0] == '/' &&
288  strcmp(entp->mnt_dir + 1, last) == 0) {
289  found = 1;
290  break;
291  }
292  }
293  endmntent(fp);
294 
295  if (!found) {
296  fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
297  return 1;
298  }
299 
300  return 0;
301 }
302 
303 static pid_t clone_newns(void *a)
304 {
305  char buf[131072];
306  char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
307 
308 #ifdef __ia64__
309  extern int __clone2(int (*fn)(void *),
310  void *child_stack_base, size_t stack_size,
311  int flags, void *arg, pid_t *ptid,
312  void *tls, pid_t *ctid);
313 
314  return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
315  CLONE_NEWNS, a, NULL, NULL, NULL);
316 #else
317  return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
318 #endif
319 }
320 
321 static int check_is_mount(const char *last, const char *mnt)
322 {
323  pid_t pid, p;
324  int status;
325  const char *a[2] = { last, mnt };
326 
327  pid = clone_newns((void *) a);
328  if (pid == (pid_t) -1) {
329  fprintf(stderr, "%s: failed to clone namespace: %s\n",
330  progname, strerror(errno));
331  return -1;
332  }
333  p = waitpid(pid, &status, __WCLONE);
334  if (p == (pid_t) -1) {
335  fprintf(stderr, "%s: waitpid failed: %s\n",
336  progname, strerror(errno));
337  return -1;
338  }
339  if (!WIFEXITED(status)) {
340  fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
341  progname, status);
342  return -1;
343  }
344  if (WEXITSTATUS(status) != 0)
345  return -1;
346 
347  return 0;
348 }
349 
350 static int chdir_to_parent(char *copy, const char **lastp)
351 {
352  char *tmp;
353  const char *parent;
354  char buf[65536];
355  int res;
356 
357  tmp = strrchr(copy, '/');
358  if (tmp == NULL || tmp[1] == '\0') {
359  fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
360  progname, copy);
361  return -1;
362  }
363  if (tmp != copy) {
364  *tmp = '\0';
365  parent = copy;
366  *lastp = tmp + 1;
367  } else if (tmp[1] != '\0') {
368  *lastp = tmp + 1;
369  parent = "/";
370  } else {
371  *lastp = ".";
372  parent = "/";
373  }
374 
375  res = chdir(parent);
376  if (res == -1) {
377  fprintf(stderr, "%s: failed to chdir to %s: %s\n",
378  progname, parent, strerror(errno));
379  return -1;
380  }
381 
382  if (getcwd(buf, sizeof(buf)) == NULL) {
383  fprintf(stderr, "%s: failed to obtain current directory: %s\n",
384  progname, strerror(errno));
385  return -1;
386  }
387  if (strcmp(buf, parent) != 0) {
388  fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
389  parent, buf);
390  return -1;
391 
392  }
393 
394  return 0;
395 }
396 
397 /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
398 static int umount_nofollow_support(void)
399 {
400  int res = umount2("", UMOUNT_UNUSED);
401  if (res != -1 || errno != EINVAL)
402  return 0;
403 
404  res = umount2("", UMOUNT_NOFOLLOW);
405  if (res != -1 || errno != ENOENT)
406  return 0;
407 
408  return 1;
409 }
410 
411 static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
412 {
413  int res;
414  char *copy;
415  const char *last;
416  int umount_flags = lazy ? UMOUNT_DETACH : 0;
417 
418  if (getuid() != 0) {
419  res = may_unmount(mnt, quiet);
420  if (res == -1)
421  return -1;
422  }
423 
424  copy = strdup(mnt);
425  if (copy == NULL) {
426  fprintf(stderr, "%s: failed to allocate memory\n", progname);
427  return -1;
428  }
429 
430  res = chdir_to_parent(copy, &last);
431  if (res == -1)
432  goto out;
433 
434  if (umount_nofollow_support()) {
435  umount_flags |= UMOUNT_NOFOLLOW;
436  } else {
437  res = check_is_mount(last, mnt);
438  if (res == -1)
439  goto out;
440  }
441 
442  res = umount2(last, umount_flags);
443  if (res == -1 && !quiet) {
444  fprintf(stderr, "%s: failed to unmount %s: %s\n",
445  progname, mnt, strerror(errno));
446  }
447 
448 out:
449  free(copy);
450  if (res == -1)
451  return -1;
452 
453  res = chdir("/");
454  if (res == -1) {
455  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
456  return -1;
457  }
458 
459  return fuse_mnt_remove_mount(progname, mnt);
460 }
461 
462 static int unmount_fuse(const char *mnt, int quiet, int lazy)
463 {
464  int res;
465  int mtablock = lock_umount();
466 
467  res = unmount_fuse_locked(mnt, quiet, lazy);
468  unlock_umount(mtablock);
469 
470  return res;
471 }
472 
473 static int count_fuse_fs(void)
474 {
475  struct mntent *entp;
476  int count = 0;
477  const char *mtab = _PATH_MOUNTED;
478  FILE *fp = setmntent(mtab, "r");
479  if (fp == NULL) {
480  fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
481  strerror(errno));
482  return -1;
483  }
484  while ((entp = getmntent(fp)) != NULL) {
485  if (strcmp(entp->mnt_type, "fuse") == 0 ||
486  strncmp(entp->mnt_type, "fuse.", 5) == 0)
487  count ++;
488  }
489  endmntent(fp);
490  return count;
491 }
492 
493 
494 #else /* IGNORE_MTAB */
495 static int count_fuse_fs(void)
496 {
497  return 0;
498 }
499 
500 static int add_mount(const char *source, const char *mnt, const char *type,
501  const char *opts)
502 {
503  (void) source;
504  (void) mnt;
505  (void) type;
506  (void) opts;
507  return 0;
508 }
509 
510 static int unmount_fuse(const char *mnt, int quiet, int lazy)
511 {
512  (void) quiet;
513  return fuse_mnt_umount(progname, mnt, mnt, lazy);
514 }
515 #endif /* IGNORE_MTAB */
516 
517 static void strip_line(char *line)
518 {
519  char *s = strchr(line, '#');
520  if (s != NULL)
521  s[0] = '\0';
522  for (s = line + strlen(line) - 1;
523  s >= line && isspace((unsigned char) *s); s--);
524  s[1] = '\0';
525  for (s = line; isspace((unsigned char) *s); s++);
526  if (s != line)
527  memmove(line, s, strlen(s)+1);
528 }
529 
530 static void parse_line(char *line, int linenum)
531 {
532  int tmp;
533  if (strcmp(line, "user_allow_other") == 0)
534  user_allow_other = 1;
535  else if (sscanf(line, "mount_max = %i", &tmp) == 1)
536  mount_max = tmp;
537  else if(line[0])
538  fprintf(stderr,
539  "%s: unknown parameter in %s at line %i: '%s'\n",
540  progname, FUSE_CONF, linenum, line);
541 }
542 
543 static void read_conf(void)
544 {
545  FILE *fp = fopen(FUSE_CONF, "r");
546  if (fp != NULL) {
547  int linenum = 1;
548  char line[256];
549  int isnewline = 1;
550  while (fgets(line, sizeof(line), fp) != NULL) {
551  if (isnewline) {
552  if (line[strlen(line)-1] == '\n') {
553  strip_line(line);
554  parse_line(line, linenum);
555  } else {
556  isnewline = 0;
557  }
558  } else if(line[strlen(line)-1] == '\n') {
559  fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
560 
561  isnewline = 1;
562  }
563  if (isnewline)
564  linenum ++;
565  }
566  if (!isnewline) {
567  fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
568 
569  }
570  if (ferror(fp)) {
571  fprintf(stderr, "%s: reading %s: read failed\n", progname, FUSE_CONF);
572  exit(1);
573  }
574  fclose(fp);
575  } else if (errno != ENOENT) {
576  bool fatal = (errno != EACCES && errno != ELOOP &&
577  errno != ENAMETOOLONG && errno != ENOTDIR &&
578  errno != EOVERFLOW);
579  fprintf(stderr, "%s: failed to open %s: %s\n",
580  progname, FUSE_CONF, strerror(errno));
581  if (fatal)
582  exit(1);
583  }
584 }
585 
586 static int begins_with(const char *s, const char *beg)
587 {
588  if (strncmp(s, beg, strlen(beg)) == 0)
589  return 1;
590  else
591  return 0;
592 }
593 
594 struct mount_flags {
595  const char *opt;
596  unsigned long flag;
597  int on;
598  int safe;
599 };
600 
601 static struct mount_flags mount_flags[] = {
602  {"rw", MS_RDONLY, 0, 1},
603  {"ro", MS_RDONLY, 1, 1},
604  {"suid", MS_NOSUID, 0, 0},
605  {"nosuid", MS_NOSUID, 1, 1},
606  {"dev", MS_NODEV, 0, 0},
607  {"nodev", MS_NODEV, 1, 1},
608  {"exec", MS_NOEXEC, 0, 1},
609  {"noexec", MS_NOEXEC, 1, 1},
610  {"async", MS_SYNCHRONOUS, 0, 1},
611  {"sync", MS_SYNCHRONOUS, 1, 1},
612  {"atime", MS_NOATIME, 0, 1},
613  {"noatime", MS_NOATIME, 1, 1},
614  {"dirsync", MS_DIRSYNC, 1, 1},
615  {NULL, 0, 0, 0}
616 };
617 
618 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
619 {
620  int i;
621 
622  for (i = 0; mount_flags[i].opt != NULL; i++) {
623  const char *opt = mount_flags[i].opt;
624  if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
625  *on = mount_flags[i].on;
626  *flag = mount_flags[i].flag;
627  if (!mount_flags[i].safe && getuid() != 0) {
628  *flag = 0;
629  fprintf(stderr,
630  "%s: unsafe option %s ignored\n",
631  progname, opt);
632  }
633  return 1;
634  }
635  }
636  return 0;
637 }
638 
639 static int add_option(char **optsp, const char *opt, unsigned expand)
640 {
641  char *newopts;
642  if (*optsp == NULL)
643  newopts = strdup(opt);
644  else {
645  unsigned oldsize = strlen(*optsp);
646  unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
647  newopts = (char *) realloc(*optsp, newsize);
648  if (newopts)
649  sprintf(newopts + oldsize, ",%s", opt);
650  }
651  if (newopts == NULL) {
652  fprintf(stderr, "%s: failed to allocate memory\n", progname);
653  return -1;
654  }
655  *optsp = newopts;
656  return 0;
657 }
658 
659 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
660 {
661  int i;
662  int l;
663 
664  if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
665  return -1;
666 
667  for (i = 0; mount_flags[i].opt != NULL; i++) {
668  if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
669  add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
670  return -1;
671  }
672 
673  if (add_option(mnt_optsp, opts, 0) == -1)
674  return -1;
675  /* remove comma from end of opts*/
676  l = strlen(*mnt_optsp);
677  if ((*mnt_optsp)[l-1] == ',')
678  (*mnt_optsp)[l-1] = '\0';
679  if (getuid() != 0) {
680  const char *user = get_user_name();
681  if (user == NULL)
682  return -1;
683 
684  if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
685  return -1;
686  strcat(*mnt_optsp, user);
687  }
688  return 0;
689 }
690 
691 static int opt_eq(const char *s, unsigned len, const char *opt)
692 {
693  if(strlen(opt) == len && strncmp(s, opt, len) == 0)
694  return 1;
695  else
696  return 0;
697 }
698 
699 static int get_string_opt(const char *s, unsigned len, const char *opt,
700  char **val)
701 {
702  int i;
703  unsigned opt_len = strlen(opt);
704  char *d;
705 
706  if (*val)
707  free(*val);
708  *val = (char *) malloc(len - opt_len + 1);
709  if (!*val) {
710  fprintf(stderr, "%s: failed to allocate memory\n", progname);
711  return 0;
712  }
713 
714  d = *val;
715  s += opt_len;
716  len -= opt_len;
717  for (i = 0; i < len; i++) {
718  if (s[i] == '\\' && i + 1 < len)
719  i++;
720  *d++ = s[i];
721  }
722  *d = '\0';
723  return 1;
724 }
725 
726 /* The kernel silently truncates the "data" argument to PAGE_SIZE-1 characters.
727  * This can be dangerous if it e.g. truncates the option "group_id=1000" to
728  * "group_id=1".
729  * This wrapper detects this case and bails out with an error.
730  */
731 static int mount_notrunc(const char *source, const char *target,
732  const char *filesystemtype, unsigned long mountflags,
733  const char *data) {
734  if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
735  fprintf(stderr, "%s: mount options too long\n", progname);
736  errno = EINVAL;
737  return -1;
738  }
739  return mount(source, target, filesystemtype, mountflags, data);
740 }
741 
742 
743 static int do_mount(const char *mnt, char **typep, mode_t rootmode,
744  int fd, const char *opts, const char *dev, char **sourcep,
745  char **mnt_optsp)
746 {
747  int res;
748  int flags = MS_NOSUID | MS_NODEV;
749  char *optbuf;
750  char *mnt_opts = NULL;
751  const char *s;
752  char *d;
753  char *fsname = NULL;
754  char *subtype = NULL;
755  char *source = NULL;
756  char *type = NULL;
757  int blkdev = 0;
758 
759  optbuf = (char *) malloc(strlen(opts) + 128);
760  if (!optbuf) {
761  fprintf(stderr, "%s: failed to allocate memory\n", progname);
762  return -1;
763  }
764 
765  for (s = opts, d = optbuf; *s;) {
766  unsigned len;
767  const char *fsname_str = "fsname=";
768  const char *subtype_str = "subtype=";
769  bool escape_ok = begins_with(s, fsname_str) ||
770  begins_with(s, subtype_str);
771  for (len = 0; s[len]; len++) {
772  if (escape_ok && s[len] == '\\' && s[len + 1])
773  len++;
774  else if (s[len] == ',')
775  break;
776  }
777  if (begins_with(s, fsname_str)) {
778  if (!get_string_opt(s, len, fsname_str, &fsname))
779  goto err;
780  } else if (begins_with(s, subtype_str)) {
781  if (!get_string_opt(s, len, subtype_str, &subtype))
782  goto err;
783  } else if (opt_eq(s, len, "blkdev")) {
784  if (getuid() != 0) {
785  fprintf(stderr,
786  "%s: option blkdev is privileged\n",
787  progname);
788  goto err;
789  }
790  blkdev = 1;
791  } else if (opt_eq(s, len, "auto_unmount")) {
792  auto_unmount = 1;
793  } else if (!begins_with(s, "fd=") &&
794  !begins_with(s, "rootmode=") &&
795  !begins_with(s, "user_id=") &&
796  !begins_with(s, "group_id=")) {
797  int on;
798  int flag;
799  int skip_option = 0;
800  if (opt_eq(s, len, "large_read")) {
801  struct utsname utsname;
802  unsigned kmaj, kmin;
803  res = uname(&utsname);
804  if (res == 0 &&
805  sscanf(utsname.release, "%u.%u",
806  &kmaj, &kmin) == 2 &&
807  (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
808  fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
809  skip_option = 1;
810  }
811  }
812  if (getuid() != 0 && !user_allow_other &&
813  (opt_eq(s, len, "allow_other") ||
814  opt_eq(s, len, "allow_root"))) {
815  fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
816  goto err;
817  }
818  if (!skip_option) {
819  if (find_mount_flag(s, len, &on, &flag)) {
820  if (on)
821  flags |= flag;
822  else
823  flags &= ~flag;
824  } else if (opt_eq(s, len, "default_permissions") ||
825  opt_eq(s, len, "allow_other") ||
826  begins_with(s, "max_read=") ||
827  begins_with(s, "blksize=")) {
828  memcpy(d, s, len);
829  d += len;
830  *d++ = ',';
831  } else {
832  fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, s);
833  exit(1);
834  }
835  }
836  }
837  s += len;
838  if (*s)
839  s++;
840  }
841  *d = '\0';
842  res = get_mnt_opts(flags, optbuf, &mnt_opts);
843  if (res == -1)
844  goto err;
845 
846  sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
847  fd, rootmode, getuid(), getgid());
848 
849  source = malloc((fsname ? strlen(fsname) : 0) +
850  (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
851 
852  type = malloc((subtype ? strlen(subtype) : 0) + 32);
853  if (!type || !source) {
854  fprintf(stderr, "%s: failed to allocate memory\n", progname);
855  goto err;
856  }
857 
858  if (subtype)
859  sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
860  else
861  strcpy(type, blkdev ? "fuseblk" : "fuse");
862 
863  if (fsname)
864  strcpy(source, fsname);
865  else
866  strcpy(source, subtype ? subtype : dev);
867 
868  res = mount_notrunc(source, mnt, type, flags, optbuf);
869  if (res == -1 && errno == ENODEV && subtype) {
870  /* Probably missing subtype support */
871  strcpy(type, blkdev ? "fuseblk" : "fuse");
872  if (fsname) {
873  if (!blkdev)
874  sprintf(source, "%s#%s", subtype, fsname);
875  } else {
876  strcpy(source, type);
877  }
878 
879  res = mount_notrunc(source, mnt, type, flags, optbuf);
880  }
881  if (res == -1 && errno == EINVAL) {
882  /* It could be an old version not supporting group_id */
883  sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
884  fd, rootmode, getuid());
885  res = mount_notrunc(source, mnt, type, flags, optbuf);
886  }
887  if (res == -1) {
888  int errno_save = errno;
889  if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
890  fprintf(stderr, "%s: 'fuseblk' support missing\n",
891  progname);
892  else
893  fprintf(stderr, "%s: mount failed: %s\n", progname,
894  strerror(errno_save));
895  goto err;
896  }
897  *sourcep = source;
898  *typep = type;
899  *mnt_optsp = mnt_opts;
900  free(fsname);
901  free(optbuf);
902 
903  return 0;
904 
905 err:
906  free(fsname);
907  free(subtype);
908  free(source);
909  free(type);
910  free(mnt_opts);
911  free(optbuf);
912  return -1;
913 }
914 
915 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
916 {
917  int res;
918  const char *mnt = *mntp;
919  const char *origmnt = mnt;
920  struct statfs fs_buf;
921  size_t i;
922 
923  res = lstat(mnt, stbuf);
924  if (res == -1) {
925  fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
926  progname, mnt, strerror(errno));
927  return -1;
928  }
929 
930  /* No permission checking is done for root */
931  if (getuid() == 0)
932  return 0;
933 
934  if (S_ISDIR(stbuf->st_mode)) {
935  res = chdir(mnt);
936  if (res == -1) {
937  fprintf(stderr,
938  "%s: failed to chdir to mountpoint: %s\n",
939  progname, strerror(errno));
940  return -1;
941  }
942  mnt = *mntp = ".";
943  res = lstat(mnt, stbuf);
944  if (res == -1) {
945  fprintf(stderr,
946  "%s: failed to access mountpoint %s: %s\n",
947  progname, origmnt, strerror(errno));
948  return -1;
949  }
950 
951  if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
952  fprintf(stderr, "%s: mountpoint %s not owned by user\n",
953  progname, origmnt);
954  return -1;
955  }
956 
957  res = access(mnt, W_OK);
958  if (res == -1) {
959  fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
960  progname, origmnt);
961  return -1;
962  }
963  } else if (S_ISREG(stbuf->st_mode)) {
964  static char procfile[256];
965  *mountpoint_fd = open(mnt, O_WRONLY);
966  if (*mountpoint_fd == -1) {
967  fprintf(stderr, "%s: failed to open %s: %s\n",
968  progname, mnt, strerror(errno));
969  return -1;
970  }
971  res = fstat(*mountpoint_fd, stbuf);
972  if (res == -1) {
973  fprintf(stderr,
974  "%s: failed to access mountpoint %s: %s\n",
975  progname, mnt, strerror(errno));
976  return -1;
977  }
978  if (!S_ISREG(stbuf->st_mode)) {
979  fprintf(stderr,
980  "%s: mountpoint %s is no longer a regular file\n",
981  progname, mnt);
982  return -1;
983  }
984 
985  sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
986  *mntp = procfile;
987  } else {
988  fprintf(stderr,
989  "%s: mountpoint %s is not a directory or a regular file\n",
990  progname, mnt);
991  return -1;
992  }
993 
994  /* Do not permit mounting over anything in procfs - it has a couple
995  * places to which we have "write access" without being supposed to be
996  * able to just put anything we want there.
997  * Luckily, without allow_other, we can't get other users to actually
998  * use any fake information we try to put there anyway.
999  * Use a whitelist to be safe. */
1000  if (statfs(*mntp, &fs_buf)) {
1001  fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
1002  progname, mnt, strerror(errno));
1003  return -1;
1004  }
1005 
1006  /* Use the same list of permitted filesystems for the mount target as
1007  * the ecryptfs mount helper
1008  * (https://bazaar.launchpad.net/~ecryptfs/ecryptfs/trunk/view/head:/src/utils/mount.ecryptfs_private.c#L225). */
1009  typeof(fs_buf.f_type) f_type_whitelist[] = {
1010  0x61756673 /* AUFS_SUPER_MAGIC */,
1011  0x9123683E /* BTRFS_SUPER_MAGIC */,
1012  0x00C36400 /* CEPH_SUPER_MAGIC */,
1013  0xFF534D42 /* CIFS_MAGIC_NUMBER */,
1014  0x0000F15F /* ECRYPTFS_SUPER_MAGIC */,
1015  0x0000EF53 /* EXT[234]_SUPER_MAGIC */,
1016  0xF2F52010 /* F2FS_SUPER_MAGIC */,
1017  0x65735546 /* FUSE_SUPER_MAGIC */,
1018  0x01161970 /* GFS2_MAGIC */,
1019  0x3153464A /* JFS_SUPER_MAGIC */,
1020  0x000072B6 /* JFFS2_SUPER_MAGIC */,
1021  0x0000564C /* NCP_SUPER_MAGIC */,
1022  0x00006969 /* NFS_SUPER_MAGIC */,
1023  0x00003434 /* NILFS_SUPER_MAGIC */,
1024  0x5346544E /* NTFS_SB_MAGIC */,
1025  0x794C7630 /* OVERLAYFS_SUPER_MAGIC */,
1026  0x52654973 /* REISERFS_SUPER_MAGIC */,
1027  0x73717368 /* SQUASHFS_MAGIC */,
1028  0x01021994 /* TMPFS_MAGIC */,
1029  0x24051905 /* UBIFS_SUPER_MAGIC */,
1030  0x58465342 /* XFS_SB_MAGIC */,
1031  0x2FC12FC1 /* ZFS_SUPER_MAGIC */,
1032  };
1033  for (i = 0; i < sizeof(f_type_whitelist)/sizeof(f_type_whitelist[0]); i++) {
1034  if (f_type_whitelist[i] == fs_buf.f_type)
1035  return 0;
1036  }
1037 
1038  fprintf(stderr, "%s: mounting over filesystem type %#010lx is forbidden\n",
1039  progname, (unsigned long)fs_buf.f_type);
1040  return -1;
1041 }
1042 
1043 static int try_open(const char *dev, char **devp, int silent)
1044 {
1045  int fd = open(dev, O_RDWR);
1046  if (fd != -1) {
1047  *devp = strdup(dev);
1048  if (*devp == NULL) {
1049  fprintf(stderr, "%s: failed to allocate memory\n",
1050  progname);
1051  close(fd);
1052  fd = -1;
1053  }
1054  } else if (errno == ENODEV ||
1055  errno == ENOENT)/* check for ENOENT too, for the udev case */
1056  return -2;
1057  else if (!silent) {
1058  fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
1059  strerror(errno));
1060  }
1061  return fd;
1062 }
1063 
1064 static int try_open_fuse_device(char **devp)
1065 {
1066  int fd;
1067 
1068  drop_privs();
1069  fd = try_open(FUSE_DEV, devp, 0);
1070  restore_privs();
1071  return fd;
1072 }
1073 
1074 static int open_fuse_device(char **devp)
1075 {
1076  int fd = try_open_fuse_device(devp);
1077  if (fd >= -1)
1078  return fd;
1079 
1080  fprintf(stderr,
1081  "%s: fuse device not found, try 'modprobe fuse' first\n",
1082  progname);
1083 
1084  return -1;
1085 }
1086 
1087 
1088 static int mount_fuse(const char *mnt, const char *opts)
1089 {
1090  int res;
1091  int fd;
1092  char *dev;
1093  struct stat stbuf;
1094  char *type = NULL;
1095  char *source = NULL;
1096  char *mnt_opts = NULL;
1097  const char *real_mnt = mnt;
1098  int mountpoint_fd = -1;
1099 
1100  fd = open_fuse_device(&dev);
1101  if (fd == -1)
1102  return -1;
1103 
1104  drop_privs();
1105  read_conf();
1106 
1107  if (getuid() != 0 && mount_max != -1) {
1108  int mount_count = count_fuse_fs();
1109  if (mount_count >= mount_max) {
1110  fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1111  goto fail_close_fd;
1112  }
1113  }
1114 
1115  res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1116  restore_privs();
1117  if (res != -1)
1118  res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
1119  fd, opts, dev, &source, &mnt_opts);
1120 
1121  if (mountpoint_fd != -1)
1122  close(mountpoint_fd);
1123 
1124  if (res == -1)
1125  goto fail_close_fd;
1126 
1127  res = chdir("/");
1128  if (res == -1) {
1129  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1130  goto fail_close_fd;
1131  }
1132 
1133  if (geteuid() == 0) {
1134  res = add_mount(source, mnt, type, mnt_opts);
1135  if (res == -1) {
1136  /* Can't clean up mount in a non-racy way */
1137  goto fail_close_fd;
1138  }
1139  }
1140 
1141 out_free:
1142  free(source);
1143  free(type);
1144  free(mnt_opts);
1145  free(dev);
1146 
1147  return fd;
1148 
1149 fail_close_fd:
1150  close(fd);
1151  fd = -1;
1152  goto out_free;
1153 }
1154 
1155 static int send_fd(int sock_fd, int fd)
1156 {
1157  int retval;
1158  struct msghdr msg;
1159  struct cmsghdr *p_cmsg;
1160  struct iovec vec;
1161  size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1162  int *p_fds;
1163  char sendchar = 0;
1164 
1165  msg.msg_control = cmsgbuf;
1166  msg.msg_controllen = sizeof(cmsgbuf);
1167  p_cmsg = CMSG_FIRSTHDR(&msg);
1168  p_cmsg->cmsg_level = SOL_SOCKET;
1169  p_cmsg->cmsg_type = SCM_RIGHTS;
1170  p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1171  p_fds = (int *) CMSG_DATA(p_cmsg);
1172  *p_fds = fd;
1173  msg.msg_controllen = p_cmsg->cmsg_len;
1174  msg.msg_name = NULL;
1175  msg.msg_namelen = 0;
1176  msg.msg_iov = &vec;
1177  msg.msg_iovlen = 1;
1178  msg.msg_flags = 0;
1179  /* "To pass file descriptors or credentials you need to send/read at
1180  * least one byte" (man 7 unix) */
1181  vec.iov_base = &sendchar;
1182  vec.iov_len = sizeof(sendchar);
1183  while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1184  if (retval != 1) {
1185  perror("sending file descriptor");
1186  return -1;
1187  }
1188  return 0;
1189 }
1190 
1191 static void usage(void)
1192 {
1193  printf("%s: [options] mountpoint\n"
1194  "Options:\n"
1195  " -h print help\n"
1196  " -V print version\n"
1197  " -o opt[,opt...] mount options\n"
1198  " -u unmount\n"
1199  " -q quiet\n"
1200  " -z lazy unmount\n",
1201  progname);
1202  exit(1);
1203 }
1204 
1205 static void show_version(void)
1206 {
1207  printf("fusermount3 version: %s\n", PACKAGE_VERSION);
1208  exit(0);
1209 }
1210 
1211 int main(int argc, char *argv[])
1212 {
1213  sigset_t sigset;
1214  int ch;
1215  int fd;
1216  int res;
1217  char *origmnt;
1218  char *mnt;
1219  static int unmount = 0;
1220  static int lazy = 0;
1221  static int quiet = 0;
1222  char *commfd;
1223  int cfd;
1224  const char *opts = "";
1225 
1226  static const struct option long_opts[] = {
1227  {"unmount", no_argument, NULL, 'u'},
1228  {"lazy", no_argument, NULL, 'z'},
1229  {"quiet", no_argument, NULL, 'q'},
1230  {"help", no_argument, NULL, 'h'},
1231  {"version", no_argument, NULL, 'V'},
1232  {0, 0, 0, 0}};
1233 
1234  progname = strdup(argv[0]);
1235  if (progname == NULL) {
1236  fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1237  exit(1);
1238  }
1239 
1240  while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1241  NULL)) != -1) {
1242  switch (ch) {
1243  case 'h':
1244  usage();
1245  break;
1246 
1247  case 'V':
1248  show_version();
1249  break;
1250 
1251  case 'o':
1252  opts = optarg;
1253  break;
1254 
1255  case 'u':
1256  unmount = 1;
1257  break;
1258 
1259  case 'z':
1260  lazy = 1;
1261  break;
1262 
1263  case 'q':
1264  quiet = 1;
1265  break;
1266 
1267  default:
1268  exit(1);
1269  }
1270  }
1271 
1272  if (lazy && !unmount) {
1273  fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1274  exit(1);
1275  }
1276 
1277  if (optind >= argc) {
1278  fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1279  exit(1);
1280  } else if (argc > optind + 1) {
1281  fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1282  progname);
1283  exit(1);
1284  }
1285 
1286  origmnt = argv[optind];
1287 
1288  drop_privs();
1289  mnt = fuse_mnt_resolve_path(progname, origmnt);
1290  if (mnt != NULL) {
1291  res = chdir("/");
1292  if (res == -1) {
1293  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1294  goto err_out;
1295  }
1296  }
1297  restore_privs();
1298  if (mnt == NULL)
1299  exit(1);
1300 
1301  umask(033);
1302  if (unmount)
1303  goto do_unmount;
1304 
1305  commfd = getenv(FUSE_COMMFD_ENV);
1306  if (commfd == NULL) {
1307  fprintf(stderr, "%s: old style mounting not supported\n",
1308  progname);
1309  goto err_out;
1310  }
1311 
1312  fd = mount_fuse(mnt, opts);
1313  if (fd == -1)
1314  goto err_out;
1315 
1316  cfd = atoi(commfd);
1317  res = send_fd(cfd, fd);
1318  if (res == -1)
1319  goto err_out;
1320  close(fd);
1321 
1322  if (!auto_unmount) {
1323  free(mnt);
1324  return 0;
1325  }
1326 
1327  /* Become a daemon and wait for the parent to exit or die.
1328  ie For the control socket to get closed.
1329  btw We don't want to use daemon() function here because
1330  it forks and messes with the file descriptors. */
1331  setsid();
1332  res = chdir("/");
1333  if (res == -1) {
1334  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1335  goto err_out;
1336  }
1337 
1338  sigfillset(&sigset);
1339  sigprocmask(SIG_BLOCK, &sigset, NULL);
1340 
1341  lazy = 1;
1342  quiet = 1;
1343 
1344  while (1) {
1345  unsigned char buf[16];
1346  int n = recv(cfd, buf, sizeof(buf), 0);
1347  if (!n)
1348  break;
1349 
1350  if (n < 0) {
1351  if (errno == EINTR)
1352  continue;
1353  break;
1354  }
1355  }
1356 
1357 do_unmount:
1358  if (geteuid() == 0)
1359  res = unmount_fuse(mnt, quiet, lazy);
1360  else {
1361  res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1362  if (res == -1 && !quiet)
1363  fprintf(stderr,
1364  "%s: failed to unmount %s: %s\n",
1365  progname, mnt, strerror(errno));
1366  }
1367  if (res == -1)
1368  goto err_out;
1369  free(mnt);
1370  return 0;
1371 
1372 err_out:
1373  free(mnt);
1374  exit(1);
1375 }