autofs-5.1.9 - fix handling of ignored offsets

From: Ian Kent <raven@themaw.net>

If a map entry offset path already has a real mount mounted on it then
it's ignored as it has very likely been auto-mounted by the NFS client.

But we have seen a case were autofs incorrectly makes a function call
that attempts to mount the offset tree mounts again after successfully
mounting the real mount on the offset. This causes automount(8) to see
this as an NFS auto-mounted mount to be ignored and then incorrectly
invalidates these offsets.

Guard against this by flagging offset trigger mounts as mounted when
they are initially successfully mounted and clearing it upon umounting
them.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG           |    1 +
 daemon/direct.c     |    3 +++
 include/automount.h |    3 +++
 lib/mounts.c        |    7 ++++++-
 4 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG b/CHANGELOG
index 36751885a..4c3b075f0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -32,6 +32,7 @@
 - remove mounts_mutex macros.
 - fix lock not released on error in mnts_add_amdmount().
 - fix lock ordering deadlock in expire_cleanup().
+- fix handling of ignored offsets.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/direct.c b/daemon/direct.c
index 42baac8ab..596201e94 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -541,6 +541,7 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
 			debug(ap->logopt,
 			      "offset %s not mounted",
 			      me->key);
+			me->flags &= ~MOUNT_FLAG_OFFSET_MOUNTED;
 			return 0;
 		}
 		ioctlfd = open_ioctlfd(ap, me->key, me->dev);
@@ -629,6 +630,7 @@ force_umount:
 		rv = umount2(me->key, MNT_DETACH);
 	} else
 		info(ap->logopt, "umounted offset mount %s", me->key);
+	me->flags &= ~MOUNT_FLAG_OFFSET_MOUNTED;
 
 	return rv;
 }
@@ -783,6 +785,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
 	cache_set_ino_index(me->mc, me);
 	notify_mount_result(ap, me->key, timeout, str_offset);
 	ops->close(ap->logopt, ioctlfd);
+	me->flags |= MOUNT_FLAG_OFFSET_MOUNTED;
 
 	debug(ap->logopt, "mounted trigger %s", me->key);
 
diff --git a/include/automount.h b/include/automount.h
index 9f0aff772..79a375512 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -548,6 +548,9 @@ struct kernel_mod_version {
 /* Indicator for applications to ignore the mount entry */
 #define MOUNT_FLAG_IGNORE		0x1000
 
+/* Flag to show we have mounted the offset mount trigger */
+#define MOUNT_FLAG_OFFSET_MOUNTED	0x2000
+
 struct autofs_point {
 	pthread_t thid;
 	char *path;			/* Mount point name */
diff --git a/lib/mounts.c b/lib/mounts.c
index 6bd9cff27..ab16252c7 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -1867,7 +1867,12 @@ static int tree_mapent_mount_offset(struct mapent *oe, void *ptr)
 		if (ret != MOUNT_OFFSET_IGNORE) {
 			warn(ap->logopt, "failed to mount offset");
 			return 0;
-		} else {
+		}
+
+		/* Only invalidate the offset trigger if a real mount
+		 * is not covering it.
+		 */
+		if (!(oe->flags & MOUNT_FLAG_OFFSET_MOUNTED)) {
 			debug(ap->logopt,
 			      "ignoring \"nohide\" trigger %s", oe->key);
 			/*
