Date: Wed, 9 Sep 98 22:43:03 +0100 (BST) From: iedowse@maths.tcd.ie To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: bin/7872: mountd(8) can apply flags to wrong filesystem Message-ID: <9809092243.aa07005@walton.maths.tcd.ie>
next in thread | raw e-mail | index | archive | help
>Number: 7872 >Category: bin >Synopsis: mountd(8) can apply flags to wrong filesystem >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Sep 9 14:50:01 PDT 1998 >Last-Modified: >Originator: Ian Dowse >Organization: School of Mathematics, Trinity College Dublin >Release: FreeBSD 3.0-CURRENT i386 >Environment: FreeBSD 3.0-current and -stable (patches below are for -current) >Description: When mountd(8) receives a HUP signal, it stops all NFS exporting of filesystems, and then passes the export rules from /etc/exports via a number of mount(2) invocations. In order to handle cases where the path listed in /etc/exports is not the real mount point, mountd repeatedly removes the last path component until the mount call succeeds. Due to insuffient error checking, mountd can miss the real mount point, and apply the flags from a mounted filesystem to the underlying one. In the case we have seen, a forgotten entry in /etc/exports resulted in mountd setting the nodev flag on / every time mountd was sent a HUP signal. >How-To-Repeat: Using two machines, A and B, running -stable or -current: /etc/fstab on machine A: /dev/sd0s1h /home ufs rw 1 1 /etc/exports on machine A: /home -maproot=0:0 B.my.domain /etc/fstab on machine B: A:/home /home nfs rw,nodev 0 0 /etc/exports on machine B (entry accidentally left behind): /home -maproot=0:0 A.my.domain Here, A is exporting /home to B, but B also has an entry for /home in /etc/exports. The nodev option is important for this example. B# mount /dev/sd0s1a on / (local) A:/home on /home (nodev) B# kill -HUP `cat /var/run/mountd.pid` #('mount -u /' works too) B# w w: /dev/mem: Device not configured B# mount /dev/sd0s1a on / (NFS exported, local, nodev) A:/home on /home (nodev) What happens here is that mountd reads the MNT_NODEV flag from /home. It then attempts to update the /home flags to MNT_NODEV | MNT_EXPORTED but the mount() call fails. The code logic assumes that /home is just a subdirectory of / and reapplies the flags to /. >Fix: The simplest 'workaround' fix is: --- mountd.c.old Wed Sep 9 20:21:43 1998 +++ mountd.c Wed Sep 9 20:34:21 1998 @@ -1733,7 +1733,7 @@ *cp-- = savedc; else cp = dirp + dirplen - 1; - if (errno == EPERM) { + if (errno != EINVAL) { syslog(LOG_ERR, "can't change attributes for %s", dirp); return (1); A much more complete solution is to use the f_mntonname path as suggested in the XXX comment. The following patch does that and also stops mountd from attempting to export nfs and other unsupported filesystem types. *** mountd.c.old Wed Sep 9 20:21:43 1998 --- mountd.c Wed Sep 9 21:57:08 1998 *************** *** 1639,1648 **** int dirplen; struct statfs *fsb; { - char *cp = (char *)NULL; u_long **addrp; int done; - char savedc = '\0'; struct sockaddr_in sin, imask; union { struct ufs_args ua; --- 1639,1646 ---- *************** *** 1715,1761 **** break; default: syslog(LOG_ERR, "bad grouptype"); - if (cp) - *cp = savedc; return (1); }; /* * XXX: ! * Maybe I should just use the fsb->f_mntonname path instead ! * of looping back up the dirp to the mount point?? ! * Also, needs to know how to export all types of local * exportable file systems and not just "ufs". */ ! while (mount(fsb->f_fstypename, dirp, ! fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { ! if (cp) ! *cp-- = savedc; ! else ! cp = dirp + dirplen - 1; ! if (errno == EPERM) { syslog(LOG_ERR, ! "can't change attributes for %s", dirp); return (1); } ! if (opt_flags & OP_ALLDIRS) { ! syslog(LOG_ERR, "could not remount %s: %m", ! dirp); ! return (1); ! } ! /* back up over the last component */ ! while (*cp == '/' && cp > dirp) ! cp--; ! while (*(cp - 1) != '/' && cp > dirp) ! cp--; ! if (cp == dirp) { ! if (debug) ! warnx("mnt unsucc"); ! syslog(LOG_ERR, "can't export %s", dirp); ! return (1); ! } ! savedc = *cp; ! *cp = '\0'; } if (addrp) { ++addrp; --- 1713,1751 ---- break; default: syslog(LOG_ERR, "bad grouptype"); return (1); }; /* * XXX: ! * Needs to know how to export all types of local * exportable file systems and not just "ufs". */ ! if (strcmp(fsb->f_fstypename, "mfs") && ! strcmp(fsb->f_fstypename, "ufs") && ! strcmp(fsb->f_fstypename, "msdos") && ! strcmp(fsb->f_fstypename, "cd9660")) { ! syslog(LOG_ERR, "can't export %s filesystem %s", ! fsb->f_fstypename, dirp); ! return(1); ! } ! ! /* ! * With OP_ALLDIRS, the path must be a mount point. Otherwise ! * get the mount point from the statfs f_mntonname field. ! */ ! if (opt_flags & OP_ALLDIRS) { ! if (mount(fsb->f_fstypename, dirp, ! fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { syslog(LOG_ERR, ! "could not remount %s: %m", dirp); return (1); } ! } else if (mount(fsb->f_fstypename, fsb->f_mntonname, ! fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { ! syslog(LOG_ERR, ! "can't change attributes for %s: %m", dirp); ! return (1); } if (addrp) { ++addrp; *************** *** 1764,1771 **** } else done = TRUE; } - if (cp) - *cp = savedc; return (0); } --- 1754,1759 ---- >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9809092243.aa07005>