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>
