|
|
96dc52 |
autofs-5.1.7 - fix inconsistent locking in parse_mount()
|
|
|
96dc52 |
|
|
|
96dc52 |
From: Ian Kent <raven@themaw.net>
|
|
|
96dc52 |
|
|
|
96dc52 |
Some map entry cache locking inconsistencies have crept in.
|
|
|
96dc52 |
|
|
|
96dc52 |
In parse_mount() of the sun format parser the cache read lock is too
|
|
|
96dc52 |
heavily used and has too broad a scope. This has lead to some operations
|
|
|
96dc52 |
that should hold the write lock being called with only the read lock.
|
|
|
96dc52 |
|
|
|
96dc52 |
Signed-off-by: Ian Kent <raven@themaw.net>
|
|
|
96dc52 |
---
|
|
|
96dc52 |
CHANGELOG | 1 +
|
|
|
96dc52 |
lib/mounts.c | 9 ++++++++-
|
|
|
96dc52 |
modules/parse_sun.c | 53 ++++++++++++++++++++++++++++++++-------------------
|
|
|
96dc52 |
3 files changed, 42 insertions(+), 21 deletions(-)
|
|
|
96dc52 |
|
|
|
96dc52 |
diff --git a/CHANGELOG b/CHANGELOG
|
|
|
96dc52 |
index c60a9ed3..d25b19c8 100644
|
|
|
96dc52 |
--- a/CHANGELOG
|
|
|
96dc52 |
+++ b/CHANGELOG
|
|
|
96dc52 |
@@ -18,6 +18,7 @@
|
|
|
96dc52 |
- fix inconsistent locking in umount_subtree_mounts().
|
|
|
96dc52 |
- fix return from umount_subtree_mounts() on offset list delete.
|
|
|
96dc52 |
- pass mapent_cache to update_offset_entry().
|
|
|
96dc52 |
+- fix inconsistent locking in parse_mount().
|
|
|
96dc52 |
|
|
|
96dc52 |
25/01/2021 autofs-5.1.7
|
|
|
96dc52 |
- make bind mounts propagation slave by default.
|
|
|
96dc52 |
diff --git a/lib/mounts.c b/lib/mounts.c
|
|
|
96dc52 |
index 5ebfe5fd..0fcd4087 100644
|
|
|
96dc52 |
--- a/lib/mounts.c
|
|
|
96dc52 |
+++ b/lib/mounts.c
|
|
|
96dc52 |
@@ -2491,6 +2491,12 @@ static int do_mount_autofs_offset(struct autofs_point *ap,
|
|
|
96dc52 |
else {
|
|
|
96dc52 |
debug(ap->logopt, "ignoring \"nohide\" trigger %s",
|
|
|
96dc52 |
oe->key);
|
|
|
96dc52 |
+ /*
|
|
|
96dc52 |
+ * Ok, so we shouldn't modify the mapent but
|
|
|
96dc52 |
+ * mount requests are blocked at a point above
|
|
|
96dc52 |
+ * this and expire only uses the mapent key or
|
|
|
96dc52 |
+ * holds the cache write lock.
|
|
|
96dc52 |
+ */
|
|
|
96dc52 |
free(oe->mapent);
|
|
|
96dc52 |
oe->mapent = NULL;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
@@ -2634,7 +2640,8 @@ static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const ch
|
|
|
96dc52 |
/*
|
|
|
96dc52 |
* Ok, so we shouldn't modify the mapent but
|
|
|
96dc52 |
* mount requests are blocked at a point above
|
|
|
96dc52 |
- * this and expire only uses the mapent key.
|
|
|
96dc52 |
+ * this and expire only uses the mapent key or
|
|
|
96dc52 |
+ * holds the cache write lock.
|
|
|
96dc52 |
*/
|
|
|
96dc52 |
if (oe->mapent) {
|
|
|
96dc52 |
free(oe->mapent);
|
|
|
96dc52 |
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
|
|
|
96dc52 |
index 95251bee..a6630a76 100644
|
|
|
96dc52 |
--- a/modules/parse_sun.c
|
|
|
96dc52 |
+++ b/modules/parse_sun.c
|
|
|
96dc52 |
@@ -851,10 +851,12 @@ update_offset_entry(struct autofs_point *ap,
|
|
|
96dc52 |
strcpy(m_mapent, loc);
|
|
|
96dc52 |
}
|
|
|
96dc52 |
|
|
|
96dc52 |
+ cache_writelock(mc);
|
|
|
96dc52 |
ret = cache_update_offset(mc, name, m_key, m_mapent, age);
|
|
|
96dc52 |
|
|
|
96dc52 |
if (!cache_set_offset_parent(mc, m_key))
|
|
|
96dc52 |
error(ap->logopt, "failed to set offset parent");
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
|
|
|
96dc52 |
if (ret == CHE_DUPLICATE) {
|
|
|
96dc52 |
warn(ap->logopt, MODPREFIX
|
|
|
96dc52 |
@@ -1128,14 +1130,22 @@ static void cleanup_multi_triggers(struct autofs_point *ap,
|
|
|
96dc52 |
return;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
|
|
|
96dc52 |
-static int mount_subtree(struct autofs_point *ap, struct mapent *me,
|
|
|
96dc52 |
+static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
|
|
|
96dc52 |
const char *name, char *loc, char *options, void *ctxt)
|
|
|
96dc52 |
{
|
|
|
96dc52 |
+ struct mapent *me;
|
|
|
96dc52 |
struct mapent *ro;
|
|
|
96dc52 |
char *mm_root, *mm_base, *mm_key;
|
|
|
96dc52 |
unsigned int mm_root_len;
|
|
|
96dc52 |
int start, ret = 0, rv;
|
|
|
96dc52 |
|
|
|
96dc52 |
+ cache_readlock(mc);
|
|
|
96dc52 |
+ me = cache_lookup_distinct(mc, name);
|
|
|
96dc52 |
+ if (!me) {
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
+ return 0;
|
|
|
96dc52 |
+ }
|
|
|
96dc52 |
+
|
|
|
96dc52 |
rv = 0;
|
|
|
96dc52 |
|
|
|
96dc52 |
mm_key = me->multi->key;
|
|
|
96dc52 |
@@ -1180,9 +1190,12 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
|
|
|
96dc52 |
rv = parse_mapent(ro->mapent,
|
|
|
96dc52 |
options, &myoptions, &ro_loc, ap->logopt);
|
|
|
96dc52 |
if (!rv) {
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
warn(ap->logopt,
|
|
|
96dc52 |
MODPREFIX "failed to parse root offset");
|
|
|
96dc52 |
- cache_delete_offset_list(me->mc, name);
|
|
|
96dc52 |
+ cache_writelock(mc);
|
|
|
96dc52 |
+ cache_delete_offset_list(mc, name);
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
return 1;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
ro_len = 0;
|
|
|
96dc52 |
@@ -1199,9 +1212,10 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
|
|
|
96dc52 |
if ((ro && rv == 0) || rv <= 0) {
|
|
|
96dc52 |
ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
|
|
|
96dc52 |
if (ret == -1) {
|
|
|
96dc52 |
+ cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
error(ap->logopt, MODPREFIX
|
|
|
96dc52 |
"failed to mount offset triggers");
|
|
|
96dc52 |
- cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
|
|
|
96dc52 |
return 1;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
}
|
|
|
96dc52 |
@@ -1217,9 +1231,10 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
|
|
|
96dc52 |
if (rv == 0) {
|
|
|
96dc52 |
ret = mount_multi_triggers(ap, me->multi, name, start, mm_base);
|
|
|
96dc52 |
if (ret == -1) {
|
|
|
96dc52 |
+ cleanup_multi_triggers(ap, me, name, start, mm_base);
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
error(ap->logopt, MODPREFIX
|
|
|
96dc52 |
"failed to mount offset triggers");
|
|
|
96dc52 |
- cleanup_multi_triggers(ap, me, name, start, mm_base);
|
|
|
96dc52 |
return 1;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
} else if (rv < 0) {
|
|
|
96dc52 |
@@ -1227,8 +1242,11 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
|
|
|
96dc52 |
unsigned int mm_root_base_len = mm_root_len + strlen(mm_base) + 1;
|
|
|
96dc52 |
|
|
|
96dc52 |
if (mm_root_base_len > PATH_MAX) {
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
warn(ap->logopt, MODPREFIX "path too long");
|
|
|
96dc52 |
- cache_delete_offset_list(me->mc, name);
|
|
|
96dc52 |
+ cache_writelock(mc);
|
|
|
96dc52 |
+ cache_delete_offset_list(mc, name);
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
return 1;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
|
|
|
96dc52 |
@@ -1237,13 +1255,15 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
|
|
|
96dc52 |
|
|
|
96dc52 |
ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
|
|
|
96dc52 |
if (ret == -1) {
|
|
|
96dc52 |
+ cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
error(ap->logopt, MODPREFIX
|
|
|
96dc52 |
"failed to mount offset triggers");
|
|
|
96dc52 |
- cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
|
|
|
96dc52 |
return 1;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
}
|
|
|
96dc52 |
}
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
|
|
|
96dc52 |
/* Mount for base of tree failed */
|
|
|
96dc52 |
if (rv > 0)
|
|
|
96dc52 |
@@ -1484,7 +1504,6 @@ dont_expand:
|
|
|
96dc52 |
return 1;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
|
|
|
96dc52 |
- cache_multi_writelock(me);
|
|
|
96dc52 |
/* So we know we're the multi-mount root */
|
|
|
96dc52 |
if (!me->multi)
|
|
|
96dc52 |
me->multi = me;
|
|
|
96dc52 |
@@ -1509,14 +1528,13 @@ dont_expand:
|
|
|
96dc52 |
if (source->flags & MAP_FLAG_FORMAT_AMD) {
|
|
|
96dc52 |
free(options);
|
|
|
96dc52 |
free(pmapent);
|
|
|
96dc52 |
- cache_multi_unlock(me);
|
|
|
96dc52 |
cache_unlock(mc);
|
|
|
96dc52 |
pthread_setcancelstate(cur_state, NULL);
|
|
|
96dc52 |
return 0;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
}
|
|
|
96dc52 |
-
|
|
|
96dc52 |
age = me->age;
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
|
|
|
96dc52 |
/* It's a multi-mount; deal with it */
|
|
|
96dc52 |
do {
|
|
|
96dc52 |
@@ -1537,8 +1555,8 @@ dont_expand:
|
|
|
96dc52 |
|
|
|
96dc52 |
if (!path) {
|
|
|
96dc52 |
warn(ap->logopt, MODPREFIX "null path or out of memory");
|
|
|
96dc52 |
+ cache_writelock(mc);
|
|
|
96dc52 |
cache_delete_offset_list(mc, name);
|
|
|
96dc52 |
- cache_multi_unlock(me);
|
|
|
96dc52 |
cache_unlock(mc);
|
|
|
96dc52 |
free(options);
|
|
|
96dc52 |
free(pmapent);
|
|
|
96dc52 |
@@ -1554,8 +1572,8 @@ dont_expand:
|
|
|
96dc52 |
|
|
|
96dc52 |
l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
|
|
|
96dc52 |
if (!l) {
|
|
|
96dc52 |
+ cache_writelock(mc);
|
|
|
96dc52 |
cache_delete_offset_list(mc, name);
|
|
|
96dc52 |
- cache_multi_unlock(me);
|
|
|
96dc52 |
cache_unlock(mc);
|
|
|
96dc52 |
free(path);
|
|
|
96dc52 |
free(options);
|
|
|
96dc52 |
@@ -1573,8 +1591,8 @@ dont_expand:
|
|
|
96dc52 |
|
|
|
96dc52 |
if (status != CHE_OK) {
|
|
|
96dc52 |
warn(ap->logopt, MODPREFIX "error adding multi-mount");
|
|
|
96dc52 |
+ cache_writelock(mc);
|
|
|
96dc52 |
cache_delete_offset_list(mc, name);
|
|
|
96dc52 |
- cache_multi_unlock(me);
|
|
|
96dc52 |
cache_unlock(mc);
|
|
|
96dc52 |
free(path);
|
|
|
96dc52 |
free(options);
|
|
|
96dc52 |
@@ -1592,10 +1610,7 @@ dont_expand:
|
|
|
96dc52 |
free(myoptions);
|
|
|
96dc52 |
} while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
|
|
|
96dc52 |
|
|
|
96dc52 |
- rv = mount_subtree(ap, me, name, NULL, options, ctxt);
|
|
|
96dc52 |
-
|
|
|
96dc52 |
- cache_multi_unlock(me);
|
|
|
96dc52 |
- cache_unlock(mc);
|
|
|
96dc52 |
+ rv = mount_subtree(ap, mc, name, NULL, options, ctxt);
|
|
|
96dc52 |
|
|
|
96dc52 |
free(options);
|
|
|
96dc52 |
free(pmapent);
|
|
|
96dc52 |
@@ -1616,6 +1631,7 @@ dont_expand:
|
|
|
96dc52 |
cache_readlock(mc);
|
|
|
96dc52 |
if (*name == '/' &&
|
|
|
96dc52 |
(me = cache_lookup_distinct(mc, name)) && me->multi) {
|
|
|
96dc52 |
+ cache_unlock(mc);
|
|
|
96dc52 |
loc = strdup(p);
|
|
|
96dc52 |
if (!loc) {
|
|
|
96dc52 |
free(options);
|
|
|
96dc52 |
@@ -1624,10 +1640,7 @@ dont_expand:
|
|
|
96dc52 |
warn(ap->logopt, MODPREFIX "out of memory");
|
|
|
96dc52 |
return 1;
|
|
|
96dc52 |
}
|
|
|
96dc52 |
- cache_multi_writelock(me);
|
|
|
96dc52 |
- rv = mount_subtree(ap, me, name, loc, options, ctxt);
|
|
|
96dc52 |
- cache_multi_unlock(me);
|
|
|
96dc52 |
- cache_unlock(mc);
|
|
|
96dc52 |
+ rv = mount_subtree(ap, mc, name, loc, options, ctxt);
|
|
|
96dc52 |
free(loc);
|
|
|
96dc52 |
free(options);
|
|
|
96dc52 |
free(pmapent);
|