autofs-5.0.3 - fix incorrect pthreads condition handling for expire requests. From: Ian Kent Occassionally, when starting an expire thread we can attempt to use the structure for parameter communication after it has been freed. This patch resolves this issue. --- daemon/direct.c | 40 +++++++++++++++++++++------------------- daemon/indirect.c | 28 +++++++++++++++------------- 2 files changed, 36 insertions(+), 32 deletions(-) --- autofs-5.0.3.orig/daemon/direct.c +++ autofs-5.0.3/daemon/direct.c @@ -1033,55 +1033,53 @@ static void expire_mutex_unlock(void *ar static void *do_expire_direct(void *arg) { - struct pending_args *mt; + struct pending_args *args, mt; struct autofs_point *ap; size_t len; int status, state; - mt = (struct pending_args *) arg; + args = (struct pending_args *) arg; status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); - ap = mt->ap; + memcpy(&mt, args, sizeof(struct pending_args)); + + ap = mt.ap; - mt->signaled = 1; - status = pthread_cond_signal(&mt->cond); + args->signaled = 1; + status = pthread_cond_signal(&args->cond); if (status) fatal(status); expire_mutex_unlock(NULL); - pthread_cleanup_push(free_pending_args, mt); - pthread_cleanup_push(pending_cond_destroy, mt); - pthread_cleanup_push(expire_send_fail, mt); + pthread_cleanup_push(expire_send_fail, &mt); - len = _strlen(mt->name, KEY_MAX_LEN); + len = _strlen(mt.name, KEY_MAX_LEN); if (!len) { - warn(ap->logopt, "direct key path too long %s", mt->name); + warn(ap->logopt, "direct key path too long %s", mt.name); /* TODO: force umount ?? */ pthread_exit(NULL); } - status = do_expire(ap, mt->name, len); + status = do_expire(ap, mt.name, len); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (status) - send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token); + send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token); else { struct mapent *me; - cache_readlock(mt->mc); - me = cache_lookup_distinct(mt->mc, mt->name); + cache_readlock(mt.mc); + me = cache_lookup_distinct(mt.mc, mt.name); me->ioctlfd = -1; - cache_unlock(mt->mc); - send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token); - close(mt->ioctlfd); + cache_unlock(mt.mc); + send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); + close(mt.ioctlfd); } pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); - pthread_cleanup_pop(1); - pthread_cleanup_pop(1); return NULL; } @@ -1198,6 +1196,8 @@ int handle_packet_expire_direct(struct a cache_unlock(mc); master_source_unlock(ap->entry); + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_cond_destroy, mt); pthread_cleanup_push(expire_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); @@ -1212,6 +1212,8 @@ int handle_packet_expire_direct(struct a } pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); return 0; } --- autofs-5.0.3.orig/daemon/indirect.c +++ autofs-5.0.3/daemon/indirect.c @@ -596,40 +596,38 @@ static void expire_mutex_unlock(void *ar static void *do_expire_indirect(void *arg) { - struct pending_args *mt; + struct pending_args *args, mt; struct autofs_point *ap; int status, state; - mt = (struct pending_args *) arg; + args = (struct pending_args *) arg; status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); - ap = mt->ap; + memcpy(&mt, args, sizeof(struct pending_args)); - mt->signaled = 1; - status = pthread_cond_signal(&mt->cond); + ap = mt.ap; + + args->signaled = 1; + status = pthread_cond_signal(&args->cond); if (status) fatal(status); expire_mutex_unlock(NULL); - pthread_cleanup_push(free_pending_args, mt); - pthread_cleanup_push(pending_cond_destroy, mt); - pthread_cleanup_push(expire_send_fail, mt); + pthread_cleanup_push(expire_send_fail, &mt); - status = do_expire(mt->ap, mt->name, mt->len); + status = do_expire(mt.ap, mt.name, mt.len); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (status) - send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token); + send_fail(ap->logopt, ap->ioctlfd, mt.wait_queue_token); else - send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token); + send_ready(ap->logopt, ap->ioctlfd, mt.wait_queue_token); pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); - pthread_cleanup_pop(1); - pthread_cleanup_pop(1); return NULL; } @@ -682,6 +680,8 @@ int handle_packet_expire_indirect(struct return 1; } + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_cond_destroy, mt); pthread_cleanup_push(expire_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); @@ -696,6 +696,8 @@ int handle_packet_expire_indirect(struct } pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); return 0; }