Blame SOURCES/autofs-5.1.7-fix-inconsistent-locking-in-parse_mount.patch

9a499a
autofs-5.1.7 - fix inconsistent locking in parse_mount()
9a499a
9a499a
From: Ian Kent <raven@themaw.net>
9a499a
9a499a
Some map entry cache locking inconsistencies have crept in.
9a499a
9a499a
In parse_mount() of the sun format parser the cache read lock is too
9a499a
heavily used and has too broad a scope. This has lead to some operations
9a499a
that should hold the write lock being called with only the read lock.
9a499a
9a499a
Signed-off-by: Ian Kent <raven@themaw.net>
9a499a
---
9a499a
 CHANGELOG           |    1 
9a499a
 lib/mounts.c        |    9 +++++++-
9a499a
 modules/parse_sun.c |   53 ++++++++++++++++++++++++++++++++--------------------
9a499a
 3 files changed, 42 insertions(+), 21 deletions(-)
9a499a
9a499a
--- autofs-5.1.4.orig/CHANGELOG
9a499a
+++ autofs-5.1.4/CHANGELOG
9a499a
@@ -17,6 +17,7 @@
9a499a
 - fix inconsistent locking in umount_subtree_mounts().
9a499a
 - fix return from umount_subtree_mounts() on offset list delete.
9a499a
 - pass mapent_cache to update_offset_entry().
9a499a
+- fix inconsistent locking in parse_mount().
9a499a
 
9a499a
 xx/xx/2018 autofs-5.1.5
9a499a
 - fix flag file permission.
9a499a
--- autofs-5.1.4.orig/lib/mounts.c
9a499a
+++ autofs-5.1.4/lib/mounts.c
9a499a
@@ -2485,6 +2485,12 @@ static int do_mount_autofs_offset(struct
9a499a
 		else {
9a499a
 			debug(ap->logopt, "ignoring \"nohide\" trigger %s",
9a499a
 			      oe->key);
9a499a
+			/*
9a499a
+			 * Ok, so we shouldn't modify the mapent but
9a499a
+			 * mount requests are blocked at a point above
9a499a
+			 * this and expire only uses the mapent key or
9a499a
+			 * holds the cache write lock.
9a499a
+			 */
9a499a
 			free(oe->mapent);
9a499a
 			oe->mapent = NULL;
9a499a
 		}
9a499a
@@ -2628,7 +2634,8 @@ static int do_umount_offset(struct autof
9a499a
 			/*
9a499a
 			 * Ok, so we shouldn't modify the mapent but
9a499a
 			 * mount requests are blocked at a point above
9a499a
-			 * this and expire only uses the mapent key.
9a499a
+			 * this and expire only uses the mapent key or
9a499a
+			 * holds the cache write lock.
9a499a
 			 */
9a499a
 			if (oe->mapent) {
9a499a
 				free(oe->mapent);
9a499a
--- autofs-5.1.4.orig/modules/parse_sun.c
9a499a
+++ autofs-5.1.4/modules/parse_sun.c
9a499a
@@ -853,10 +853,12 @@ update_offset_entry(struct autofs_point
9a499a
 			strcpy(m_mapent, loc);
9a499a
 	}
9a499a
 
9a499a
+	cache_writelock(mc);
9a499a
 	ret = cache_update_offset(mc, name, m_key, m_mapent, age);
9a499a
 
9a499a
 	if (!cache_set_offset_parent(mc, m_key))
9a499a
 		error(ap->logopt, "failed to set offset parent");
9a499a
+	cache_unlock(mc);
9a499a
 
9a499a
 	if (ret == CHE_DUPLICATE) {
9a499a
 		warn(ap->logopt, MODPREFIX
9a499a
@@ -1130,14 +1132,22 @@ static void cleanup_multi_triggers(struc
9a499a
 	return;
9a499a
 }
9a499a
 
9a499a
-static int mount_subtree(struct autofs_point *ap, struct mapent *me,
9a499a
+static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
9a499a
 			 const char *name, char *loc, char *options, void *ctxt)
9a499a
 {
9a499a
+	struct mapent *me;
9a499a
 	struct mapent *ro;
9a499a
 	char *mm_root, *mm_base, *mm_key;
9a499a
 	unsigned int mm_root_len;
9a499a
 	int start, ret = 0, rv;
9a499a
 
9a499a
+	cache_readlock(mc);
9a499a
+	me = cache_lookup_distinct(mc, name);
9a499a
+	if (!me) {
9a499a
+		cache_unlock(mc);
9a499a
+		return 0;
9a499a
+	}
9a499a
+
9a499a
 	rv = 0;
9a499a
 
9a499a
 	mm_key = me->multi->key;
9a499a
@@ -1182,9 +1192,12 @@ static int mount_subtree(struct autofs_p
9a499a
 			rv = parse_mapent(ro->mapent,
9a499a
 				options, &myoptions, &ro_loc, ap->logopt);
9a499a
 			if (!rv) {
9a499a
+				cache_unlock(mc);
9a499a
 				warn(ap->logopt,
9a499a
 				      MODPREFIX "failed to parse root offset");
9a499a
-				cache_delete_offset_list(me->mc, name);
9a499a
+				cache_writelock(mc);
9a499a
+				cache_delete_offset_list(mc, name);
9a499a
+				cache_unlock(mc);
9a499a
 				return 1;
9a499a
 			}
9a499a
 			ro_len = 0;
9a499a
@@ -1201,9 +1214,10 @@ static int mount_subtree(struct autofs_p
9a499a
 		if ((ro && rv == 0) || rv <= 0) {
9a499a
 			ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
9a499a
 			if (ret == -1) {
9a499a
+				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
9a499a
+				cache_unlock(mc);
9a499a
 				error(ap->logopt, MODPREFIX
9a499a
 					 "failed to mount offset triggers");
9a499a
-				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
9a499a
 				return 1;
9a499a
 			}
9a499a
 		}
9a499a
@@ -1219,9 +1233,10 @@ static int mount_subtree(struct autofs_p
9a499a
 		if (rv == 0) {
9a499a
 			ret = mount_multi_triggers(ap, me->multi, name, start, mm_base);
9a499a
 			if (ret == -1) {
9a499a
+				cleanup_multi_triggers(ap, me, name, start, mm_base);
9a499a
+				cache_unlock(mc);
9a499a
 				error(ap->logopt, MODPREFIX
9a499a
 					 "failed to mount offset triggers");
9a499a
-				cleanup_multi_triggers(ap, me, name, start, mm_base);
9a499a
 				return 1;
9a499a
 			}
9a499a
 		} else if (rv < 0) {
9a499a
@@ -1229,8 +1244,11 @@ static int mount_subtree(struct autofs_p
9a499a
 			unsigned int mm_root_base_len = mm_root_len + strlen(mm_base) + 1;
9a499a
 	
9a499a
 			if (mm_root_base_len > PATH_MAX) {
9a499a
+				cache_unlock(mc);
9a499a
 				warn(ap->logopt, MODPREFIX "path too long");
9a499a
-				cache_delete_offset_list(me->mc, name);
9a499a
+				cache_writelock(mc);
9a499a
+				cache_delete_offset_list(mc, name);
9a499a
+				cache_unlock(mc);
9a499a
 				return 1;
9a499a
 			}
9a499a
 
9a499a
@@ -1239,13 +1257,15 @@ static int mount_subtree(struct autofs_p
9a499a
 
9a499a
 			ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
9a499a
 			if (ret == -1) {
9a499a
+				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
9a499a
+				cache_unlock(mc);
9a499a
 				error(ap->logopt, MODPREFIX
9a499a
 					 "failed to mount offset triggers");
9a499a
-				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
9a499a
 				return 1;
9a499a
 			}
9a499a
 		}
9a499a
 	}
9a499a
+	cache_unlock(mc);
9a499a
 
9a499a
 	/* Mount for base of tree failed */
9a499a
 	if (rv > 0)
9a499a
@@ -1486,7 +1506,6 @@ dont_expand:
9a499a
 			return 1;
9a499a
 		}
9a499a
 
9a499a
-		cache_multi_writelock(me);
9a499a
 		/* So we know we're the multi-mount root */
9a499a
 		if (!me->multi)
9a499a
 			me->multi = me;
9a499a
@@ -1511,14 +1530,13 @@ dont_expand:
9a499a
 			if (source->flags & MAP_FLAG_FORMAT_AMD) {
9a499a
 				free(options);
9a499a
 				free(pmapent);
9a499a
-				cache_multi_unlock(me);
9a499a
 				cache_unlock(mc);
9a499a
 				pthread_setcancelstate(cur_state, NULL);
9a499a
 				return 0;
9a499a
 			}
9a499a
 		}
9a499a
-
9a499a
 		age = me->age;
9a499a
+		cache_unlock(mc);
9a499a
 
9a499a
 		/* It's a multi-mount; deal with it */
9a499a
 		do {
9a499a
@@ -1539,8 +1557,8 @@ dont_expand:
9a499a
 
9a499a
 			if (!path) {
9a499a
 				warn(ap->logopt, MODPREFIX "null path or out of memory");
9a499a
+				cache_writelock(mc);
9a499a
 				cache_delete_offset_list(mc, name);
9a499a
-				cache_multi_unlock(me);
9a499a
 				cache_unlock(mc);
9a499a
 				free(options);
9a499a
 				free(pmapent);
9a499a
@@ -1556,8 +1574,8 @@ dont_expand:
9a499a
 
9a499a
 			l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
9a499a
 			if (!l) {
9a499a
+				cache_writelock(mc);
9a499a
 				cache_delete_offset_list(mc, name);
9a499a
-				cache_multi_unlock(me);
9a499a
 				cache_unlock(mc);
9a499a
 				free(path);
9a499a
 				free(options);
9a499a
@@ -1575,8 +1593,8 @@ dont_expand:
9a499a
 
9a499a
 			if (status != CHE_OK) {
9a499a
 				warn(ap->logopt, MODPREFIX "error adding multi-mount");
9a499a
+				cache_writelock(mc);
9a499a
 				cache_delete_offset_list(mc, name);
9a499a
-				cache_multi_unlock(me);
9a499a
 				cache_unlock(mc);
9a499a
 				free(path);
9a499a
 				free(options);
9a499a
@@ -1594,10 +1612,7 @@ dont_expand:
9a499a
 			free(myoptions);
9a499a
 		} while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
9a499a
 
9a499a
-		rv = mount_subtree(ap, me, name, NULL, options, ctxt);
9a499a
-
9a499a
-		cache_multi_unlock(me);
9a499a
-		cache_unlock(mc);
9a499a
+		rv = mount_subtree(ap, mc, name, NULL, options, ctxt);
9a499a
 
9a499a
 		free(options);
9a499a
 		free(pmapent);
9a499a
@@ -1618,6 +1633,7 @@ dont_expand:
9a499a
 		cache_readlock(mc);
9a499a
 		if (*name == '/' &&
9a499a
 		   (me = cache_lookup_distinct(mc, name)) && me->multi) {
9a499a
+			cache_unlock(mc);
9a499a
 			loc = strdup(p);
9a499a
 			if (!loc) {
9a499a
 				free(options);
9a499a
@@ -1626,10 +1642,7 @@ dont_expand:
9a499a
 				warn(ap->logopt, MODPREFIX "out of memory");
9a499a
 				return 1;
9a499a
 			}
9a499a
-			cache_multi_writelock(me);
9a499a
-			rv = mount_subtree(ap, me, name, loc, options, ctxt);
9a499a
-			cache_multi_unlock(me);
9a499a
-			cache_unlock(mc);
9a499a
+			rv = mount_subtree(ap, mc, name, loc, options, ctxt);
9a499a
 			free(loc);
9a499a
 			free(options);
9a499a
 			free(pmapent);