From nobody@FreeBSD.org  Thu Feb  9 16:22:35 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 08A09106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Thu,  9 Feb 2012 16:22:35 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id E731B8FC0C
	for <freebsd-gnats-submit@FreeBSD.org>; Thu,  9 Feb 2012 16:22:34 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q19GMYvt091566
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 9 Feb 2012 16:22:34 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id q19GMY3h091558;
	Thu, 9 Feb 2012 16:22:34 GMT
	(envelope-from nobody)
Message-Id: <201202091622.q19GMY3h091558@red.freebsd.org>
Date: Thu, 9 Feb 2012 16:22:34 GMT
From: Attila Bogr <attila.bogar@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [nfs] [patch] mountd(8) drops mixed security flavors for multiple lines per same share
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         164933
>Category:       bin
>Synopsis:       [nfs] [patch] mountd(8) drops mixed security flavors for multiple lines per same share
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Feb 09 16:30:09 UTC 2012
>Closed-Date:    Sun Oct 14 13:06:54 UTC 2012
>Last-Modified:  Sun Oct 14 13:06:54 UTC 2012
>Originator:     Attila Bogr
>Release:        8.2-STABLE
>Organization:
Linguamatics
>Environment:
FreeBSD topaz.linguamatics.com 8.2-RELEASE-p6 FreeBSD 8.2-RELEASE-p6 #1: Wed Feb  8 14:21:11 GMT 2012     system@topaz.linguamatics.com:/usr/obj/usr/src/sys/LINGUAMATICS  amd64

>Description:
When multiple lines per share are present with different security flavors, the last line's security flavour is preserved for mountd(8) and the ones from previous linues are dropped from mountd.  However the exports are pushed correctly into the kernel line-by-line with the correct security flavor.

When trying to mount the nfs share from a client machine, mountd responds with a list of possible security flavors from the share's last line only.


>How-To-Repeat:
Compile a kernel:
- deselect NFSSERVER option
- select NFSD, KGSSAPI options
- add devices: crypto, cryptodev

Add to /etc/rc.conf:
  nfs_server_enable="YES"
  nfsv4_server_enable="NO"
  nfsuserd_enable="YES"
  nfsuserd_flags="16"
  mountd_enable="YES"
  rpc_lockd_enable="YES"
  rpc_statd_enable="YES"
  rpcbind_enable="YES"
  gssd_enable="YES"

Add nfs/fqdn@REALM keytab to /etc/krb5.keytab.
Set up /etc/krb5.conf

Create sample /etc/exports:
  /export/share -sec=sys host1.example.com
  /export/share -sec=krb5i host2.example.com

Try mounting /export/share from host1 using sec=sys. Mount will fail.

>Fix:
My proposed patch takes an union of the used security flavours per filesystem handle.  Although this is not the perfect solution as clients still can mount a share with a flavour they had not been exported to.  If doing such, they get permission denied from nfsd or error message saying the (nfs) server requires stronger authentication.

struct exportlist contains the security flavours per filesystem handle.

It would be more thorough if the security flavours were registered on a per host/network/default entry, similar to as they are pushed into the kernel with do_mount() function.


Patch attached with submission follows:

--- ./usr.sbin/mountd/mountd.c.orig	2011-04-20 22:00:24.000000000 +0100
+++ ./usr.sbin/mountd/mountd.c	2012-02-09 11:54:50.000000000 +0000
@@ -1170,6 +1170,7 @@
 	struct xucred anon;
 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
 	int len, has_host, exflags, got_nondir, dirplen, netgrp;
+	int xx_numsecflavors, xx_secflavors[MAXSECFLAVORS];
 
 	v4root_phase = 0;
 	dirhead = (struct dirlist *)NULL;
@@ -1191,6 +1192,7 @@
 		opt_flags = 0;
 		ep = (struct exportlist *)NULL;
 		dirp = NULL;
+		xx_numsecflavors = 0;
 
 		/*
 		 * Handle the V4 root dir.
@@ -1299,10 +1301,13 @@
 						  "making new ep fs=0x%x,0x%x",
 						  fsb.f_fsid.val[0],
 						  fsb.f_fsid.val[1]);
-					} else if (debug)
+					} else { if (debug)
 					    warnx("found ep fs=0x%x,0x%x",
 						fsb.f_fsid.val[0],
 						fsb.f_fsid.val[1]);
+					    xx_numsecflavors = ep->ex_numsecflavors;
+					    bcopy(ep->ex_secflavors, &xx_secflavors, sizeof(int)*xx_numsecflavors);
+					}
 				    }
 
 				    /*
@@ -1429,6 +1434,19 @@
 		}
 
 		/*
+		 * Merge security flavours
+		 */
+
+		int ci, cj;
+
+		for(ci=0;ci<xx_numsecflavors;ci++) {
+			for(cj = 0; cj<ep->ex_numsecflavors && xx_secflavors[ci]!=ep->ex_secflavors[cj];cj++);
+			if (cj==ep->ex_numsecflavors) {
+				ep->ex_secflavors[ep->ex_numsecflavors++] = xx_secflavors[ci];
+			}
+		}
+
+		/*
 		 * Success. Update the data structures.
 		 */
 		if (has_host) {


>Release-Note:
>Audit-Trail:

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/164933: commit references a PR
Date: Mon, 24 Sep 2012 23:57:33 +0000 (UTC)

 Author: rmacklem
 Date: Mon Sep 24 23:57:16 2012
 New Revision: 240902
 URL: http://svn.freebsd.org/changeset/base/240902
 
 Log:
   Attila Bogar reported a bug in mountd when multiple export
   entries with different security flavors are in the exports(5)
   file. For that case, mountd replies with the security flavors
   of the last entry and not the correct one for the client host.
   This patch fixes that by storing separate copies of the flavors
   for each host/net case, plus a default one for the case where
   no hosts/nets are specified on an entry in the exports(5) file.
   Unlike the patch in the PR, it replies with the security flavors
   for the entry instead of merging the security flavors for all
   the entries and replying with that.
   
   Tested by:	attila.bogar at linguamatics.com
   PR:		kern/164933
   MFC after:	2 weeks
 
 Modified:
   head/usr.sbin/mountd/mountd.c
 
 Modified: head/usr.sbin/mountd/mountd.c
 ==============================================================================
 --- head/usr.sbin/mountd/mountd.c	Mon Sep 24 21:45:41 2012	(r240901)
 +++ head/usr.sbin/mountd/mountd.c	Mon Sep 24 23:57:16 2012	(r240902)
 @@ -117,6 +117,8 @@ struct exportlist {
  	char		*ex_indexfile;
  	int		ex_numsecflavors;
  	int		ex_secflavors[MAXSECFLAVORS];
 +	int		ex_defnumsecflavors;
 +	int		ex_defsecflavors[MAXSECFLAVORS];
  };
  /* ex_flag bits */
  #define	EX_LINKED	0x1
 @@ -136,6 +138,8 @@ struct grouplist {
  	int gr_type;
  	union grouptypes gr_ptr;
  	struct grouplist *gr_next;
 +	int gr_numsecflavors;
 +	int gr_secflavors[MAXSECFLAVORS];
  };
  /* Group types */
  #define	GT_NULL		0x0
 @@ -163,12 +167,13 @@ struct fhreturn {
  /* Global defs */
  char	*add_expdir(struct dirlist **, char *, int);
  void	add_dlist(struct dirlist **, struct dirlist *,
 -				struct grouplist *, int);
 +				struct grouplist *, int, struct exportlist *);
  void	add_mlist(char *, char *);
  int	check_dirpath(char *);
  int	check_options(struct dirlist *);
  int	checkmask(struct sockaddr *sa);
 -int	chk_host(struct dirlist *, struct sockaddr *, int *, int *);
 +int	chk_host(struct dirlist *, struct sockaddr *, int *, int *, int *,
 +				 int **);
  static int	create_service(struct netconfig *nconf);
  static void	complete_service(struct netconfig *nconf, char *port_str);
  static void	clearout_service(void);
 @@ -938,6 +943,7 @@ mntsrv(struct svc_req *rqstp, SVCXPRT *t
  	char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN];
  	int bad = 0, defset, hostset;
  	sigset_t sighup_mask;
 +	int numsecflavors, *secflavorsp;
  
  	sigemptyset(&sighup_mask);
  	sigaddset(&sighup_mask, SIGHUP);
 @@ -1000,9 +1006,11 @@ mntsrv(struct svc_req *rqstp, SVCXPRT *t
  		sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
  		ep = ex_search(&fsb.f_fsid);
  		hostset = defset = 0;
 -		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
 +		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset,
 +		    &numsecflavors, &secflavorsp) ||
  		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
 -		      chk_host(dp, saddr, &defset, &hostset)) ||
 +		      chk_host(dp, saddr, &defset, &hostset, &numsecflavors,
 +		       &secflavorsp)) ||
  		    (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
  		     scan_tree(ep->ex_dirl, saddr) == 0))) {
  			if (bad) {
 @@ -1012,10 +1020,15 @@ mntsrv(struct svc_req *rqstp, SVCXPRT *t
  				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
  				return;
  			}
 -			if (hostset & DP_HOSTSET)
 +			if (hostset & DP_HOSTSET) {
  				fhr.fhr_flag = hostset;
 -			else
 +				fhr.fhr_numsecflavors = numsecflavors;
 +				fhr.fhr_secflavors = secflavorsp;
 +			} else {
  				fhr.fhr_flag = defset;
 +				fhr.fhr_numsecflavors = ep->ex_defnumsecflavors;
 +				fhr.fhr_secflavors = ep->ex_defsecflavors;
 +			}
  			fhr.fhr_vers = rqstp->rq_vers;
  			/* Get the file handle */
  			memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
 @@ -1028,8 +1041,6 @@ mntsrv(struct svc_req *rqstp, SVCXPRT *t
  				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
  				return;
  			}
 -			fhr.fhr_numsecflavors = ep->ex_numsecflavors;
 -			fhr.fhr_secflavors = ep->ex_secflavors;
  			if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs,
  			    (caddr_t)&fhr))
  				syslog(LOG_ERR, "can't send reply");
 @@ -1881,11 +1892,21 @@ hang_dirp(struct dirlist *dp, struct gro
  			ep->ex_defdir = dp;
  		if (grp == (struct grouplist *)NULL) {
  			ep->ex_defdir->dp_flag |= DP_DEFSET;
 +			/* Save the default security flavors list. */
 +			ep->ex_defnumsecflavors = ep->ex_numsecflavors;
 +			if (ep->ex_numsecflavors > 0)
 +				memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
 +				    sizeof(ep->ex_secflavors));
  		} else while (grp) {
  			hp = get_ht();
  			hp->ht_grp = grp;
  			hp->ht_next = ep->ex_defdir->dp_hosts;
  			ep->ex_defdir->dp_hosts = hp;
 +			/* Save the security flavors list for this host set. */
 +			grp->gr_numsecflavors = ep->ex_numsecflavors;
 +			if (ep->ex_numsecflavors > 0)
 +				memcpy(grp->gr_secflavors, ep->ex_secflavors,
 +				    sizeof(ep->ex_secflavors));
  			grp = grp->gr_next;
  		}
  	} else {
 @@ -1895,7 +1916,7 @@ hang_dirp(struct dirlist *dp, struct gro
  		 */
  		while (dp) {
  			dp2 = dp->dp_left;
 -			add_dlist(&ep->ex_dirl, dp, grp, flags);
 +			add_dlist(&ep->ex_dirl, dp, grp, flags, ep);
  			dp = dp2;
  		}
  	}
 @@ -1907,7 +1928,7 @@ hang_dirp(struct dirlist *dp, struct gro
   */
  void
  add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
 -	int flags)
 +	int flags, struct exportlist *ep)
  {
  	struct dirlist *dp;
  	struct hostlist *hp;
 @@ -1917,10 +1938,10 @@ add_dlist(struct dirlist **dpp, struct d
  	if (dp) {
  		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
  		if (cmp > 0) {
 -			add_dlist(&dp->dp_left, newdp, grp, flags);
 +			add_dlist(&dp->dp_left, newdp, grp, flags, ep);
  			return;
  		} else if (cmp < 0) {
 -			add_dlist(&dp->dp_right, newdp, grp, flags);
 +			add_dlist(&dp->dp_right, newdp, grp, flags, ep);
  			return;
  		} else
  			free((caddr_t)newdp);
 @@ -1939,10 +1960,20 @@ add_dlist(struct dirlist **dpp, struct d
  			hp->ht_grp = grp;
  			hp->ht_next = dp->dp_hosts;
  			dp->dp_hosts = hp;
 +			/* Save the security flavors list for this host set. */
 +			grp->gr_numsecflavors = ep->ex_numsecflavors;
 +			if (ep->ex_numsecflavors > 0)
 +				memcpy(grp->gr_secflavors, ep->ex_secflavors,
 +				    sizeof(ep->ex_secflavors));
  			grp = grp->gr_next;
  		} while (grp);
  	} else {
  		dp->dp_flag |= DP_DEFSET;
 +		/* Save the default security flavors list. */
 +		ep->ex_defnumsecflavors = ep->ex_numsecflavors;
 +		if (ep->ex_numsecflavors > 0)
 +			memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
 +			    sizeof(ep->ex_secflavors));
  	}
  }
  
 @@ -1971,7 +2002,7 @@ dirp_search(struct dirlist *dp, char *di
   */
  int
  chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp,
 -	int *hostsetp)
 +	int *hostsetp, int *numsecflavors, int **secflavorsp)
  {
  	struct hostlist *hp;
  	struct grouplist *grp;
 @@ -1990,6 +2021,12 @@ chk_host(struct dirlist *dp, struct sock
  					if (!sacmp(ai->ai_addr, saddr, NULL)) {
  						*hostsetp =
  						    (hp->ht_flag | DP_HOSTSET);
 +						if (numsecflavors != NULL) {
 +							*numsecflavors =
 +							    grp->gr_numsecflavors;
 +							*secflavorsp =
 +							    grp->gr_secflavors;
 +						}
  						return (1);
  					}
  				}
 @@ -2000,6 +2037,12 @@ chk_host(struct dirlist *dp, struct sock
  				    (struct sockaddr *)
  				    &grp->gr_ptr.gt_net.nt_mask)) {
  					*hostsetp = (hp->ht_flag | DP_HOSTSET);
 +					if (numsecflavors != NULL) {
 +						*numsecflavors =
 +						    grp->gr_numsecflavors;
 +						*secflavorsp =
 +						    grp->gr_secflavors;
 +					}
  					return (1);
  				}
  				break;
 @@ -2021,7 +2064,7 @@ scan_tree(struct dirlist *dp, struct soc
  	if (dp) {
  		if (scan_tree(dp->dp_left, saddr))
  			return (1);
 -		if (chk_host(dp, saddr, &defset, &hostset))
 +		if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL))
  			return (1);
  		if (scan_tree(dp->dp_right, saddr))
  			return (1);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: rmacklem 
State-Changed-When: Sun Oct 14 13:05:12 UTC 2012 
State-Changed-Why:  

A patch based loosely on the one in this PR has been 
committed to head as r240902 and MFC'd to stable/9 
and stable/8. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=164933 
>Unformatted:
