Skip site navigation (1)Skip section navigation (2)
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>