git: 07cd69e272da - main - mountd.c: Define a new -a command line option

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Sat, 28 Dec 2024 21:26:07 UTC
The branch main has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=07cd69e272da2f116950f2bde6dfcc404f869f0c

commit 07cd69e272da2f116950f2bde6dfcc404f869f0c
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-12-28 21:24:51 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-12-28 21:24:51 +0000

    mountd.c: Define a new -a command line option
    
    Bugzilla PR#282995 reported that, when a file system was
    exported with the "-alldirs" flag, the export succeeded even
    if the directory path was not a server file system mount point.
    
    This behaviour for "-alldirs" was only documented in the
    Example section of exports(5) and had not been enforced
    since FreeBSD2. (A patch applied between FreeBSD1 and
    FreeBSD2 broke the check for file system mount point.)
    
    Since the behaviour of allowing the export has existed since
    FreeBSD2, the concensus on a mailing list was that it would
    be a POLA violation to change it now.
    Therefore, this patch adds a new "-a" mountd command line
    option to enforce a check for the exported directory being a
    server file system mount point.
    
    PR:     282995
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D48137
---
 usr.sbin/mountd/mountd.c | 51 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
index cb87535f6c3b..4457a925c2ed 100644
--- a/usr.sbin/mountd/mountd.c
+++ b/usr.sbin/mountd/mountd.c
@@ -215,7 +215,8 @@ static int	do_export_mount(struct exportlist *, struct statfs *);
 static int	do_mount(struct exportlist *, struct grouplist *, uint64_t,
 		    struct expcred *, char *, int, struct statfs *, int, int *);
 static int	do_opt(char **, char **, struct exportlist *,
-		    struct grouplist *, int *, uint64_t *, struct expcred *);
+		    struct grouplist *, int *, uint64_t *, struct expcred *,
+		    char *);
 static struct exportlist	*ex_search(fsid_t *, struct exportlisthead *);
 static struct exportlist	*get_exp(void);
 static void	free_dir(struct dirlist *);
@@ -292,6 +293,7 @@ static int sock_fdpos;
 static int suspend_nfsd = 0;
 static int nofork = 0;
 static int skiplocalhost = 0;
+static int alldirs_fail = 0;
 
 static int opt_flags;
 static int have_v6 = 1;
@@ -320,6 +322,7 @@ static gid_t *tmp_groups = NULL;
 #define OP_MASKLEN	0x200
 #define OP_SEC		0x400
 #define OP_CLASSMASK	0x800	/* mask not specified, is Class A/B/C default */
+#define	OP_NOTROOT	0x1000	/* Mark the the mount path is not a fs root */
 
 #ifdef DEBUG
 static int debug = 1;
@@ -458,7 +461,7 @@ main(int argc, char **argv)
 	else
 		close(s);
 
-	while ((c = getopt(argc, argv, "2Adeh:lNnp:RrSs")) != -1)
+	while ((c = getopt(argc, argv, "2Aadeh:lNnp:RrSs")) != -1)
 		switch (c) {
 		case '2':
 			force_v2 = 1;
@@ -466,6 +469,9 @@ main(int argc, char **argv)
 		case 'A':
 			warn_admin = 0;
 			break;
+		case 'a':
+			alldirs_fail = 1;
+			break;
 		case 'e':
 			/* now a no-op, since this is the default */
 			break;
@@ -1590,6 +1596,7 @@ get_exportlist_one(int passno)
 	v4root_phase = 0;
 	dirhead = (struct dirlist *)NULL;
 	unvis_dir[0] = '\0';
+	fsb.f_mntonname[0] = '\0';
 
 	while (get_line()) {
 		if (debug)
@@ -1650,7 +1657,7 @@ get_exportlist_one(int passno)
 				warnx("doing opt %s", cp);
 			    got_nondir = 1;
 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
-				&exflags, &anon)) {
+				&exflags, &anon, unvis_dir)) {
 				getexp_err(ep, tgrp, NULL);
 				goto nextline;
 			    }
@@ -1731,19 +1738,9 @@ get_exportlist_one(int passno)
 						fsb.f_fsid.val[1]);
 				    }
 
-				    if (warn_admin != 0 &&
-					(ep->ex_flag & EX_ADMINWARN) == 0 &&
-					strcmp(unvis_dir, fsb.f_mntonname) !=
-					0) {
-					if (debug)
-					    warnx("exporting %s exports entire "
-						"%s file system", unvis_dir,
-						    fsb.f_mntonname);
-					syslog(LOG_ERR, "Warning: exporting %s "
-					    "exports entire %s file system",
-					    unvis_dir, fsb.f_mntonname);
-					ep->ex_flag |= EX_ADMINWARN;
-				    }
+				    if (strcmp(unvis_dir, fsb.f_mntonname) !=
+					0)
+					opt_flags |= OP_NOTROOT;
 
 				    /*
 				     * Add dirpath to export mount point.
@@ -1813,6 +1810,17 @@ get_exportlist_one(int passno)
 			    "WARNING: No mask specified for %s, "
 			    "using out-of-date default",
 			    (&grp->gr_ptr.gt_net)->nt_name);
+		if ((opt_flags & OP_NOTROOT) != 0 && warn_admin != 0 &&
+		    (ep->ex_flag & EX_ADMINWARN) == 0 && unvis_dir[0] != '\0' &&
+		    fsb.f_mntonname[0] != '\0') {
+			if (debug)
+				warnx("exporting %s exports entire %s file "
+				    "system", unvis_dir, fsb.f_mntonname);
+			syslog(LOG_ERR, "Warning: exporting %s exports "
+			    "entire %s file system", unvis_dir,
+			    fsb.f_mntonname);
+			ep->ex_flag |= EX_ADMINWARN;
+		}
 		if (check_options(dirhead)) {
 			getexp_err(ep, tgrp, NULL);
 			goto nextline;
@@ -2836,7 +2844,7 @@ parsesec(char *seclist, struct exportlist *ep)
  */
 static int
 do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp,
-	int *has_hostp, uint64_t *exflagsp, struct expcred *cr)
+	int *has_hostp, uint64_t *exflagsp, struct expcred *cr, char *unvis_dir)
 {
 	char *cpoptarg, *cpoptend;
 	char *cp, *endcp, *cpopt, savedc, savedc2;
@@ -2921,6 +2929,12 @@ do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp,
 				syslog(LOG_ERR, "= after op: %s", cpopt);
 				return (1);
 			}
+			if ((opt_flags & OP_NOTROOT) != 0) {
+				syslog(LOG_ERR, "%s: path %s not mount point",
+				    cpopt, unvis_dir);
+				if (alldirs_fail != 0)
+					return (1);
+			}
 			opt_flags |= OP_ALLDIRS;
 		} else if (!strcmp(cpopt, "public")) {
 			if (fnd_equal == 1) {
@@ -3317,7 +3331,8 @@ do_mount(struct exportlist *ep, struct grouplist *grp, uint64_t exflags,
 					ret = 1;
 					goto error_exit;
 				}
-				if (opt_flags & OP_ALLDIRS) {
+				if ((opt_flags & OP_ALLDIRS) &&
+				    alldirs_fail != 0) {
 					if (errno == EINVAL)
 						syslog(LOG_ERR,
 		"-alldirs requested but %s is not a filesystem mountpoint",