ebb3a9f2b4
- https://fedorahosted.org/sssd/ticket/{id} - Regressions: #2471, #2475, #2483, #2487, #2529, #2535 - Bugs: #2287, #2445
244 lines
7.9 KiB
Diff
244 lines
7.9 KiB
Diff
From d1d01b99e0388e5c2fadb10db8e73917669a3383 Mon Sep 17 00:00:00 2001
|
|
From: Lukas Slebodnik <lslebodn@redhat.com>
|
|
Date: Fri, 21 Nov 2014 11:28:36 +0100
|
|
Subject: [PATCH 16/26] sss_client: Fix race condition in memory cache
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Thread safe initialisation was fixed in ticket #2380, but there is
|
|
still race condition in reinitialisation.
|
|
|
|
If caches is invalidated with command sss_cache -U (-G or -E) then
|
|
client code will need to reinitialize fast memory cache.
|
|
Let say we have two threads. The 1st thread find out that memory cache
|
|
should be reinitialized; therefore the fast memory cached is unmapped
|
|
and context destroyed. In the same time, 2nd thread tried to check
|
|
header of memory cache whether it is initialized and valid. As a result
|
|
of previously unmapped memory the 2nd thread access
|
|
out of bound memory (SEGFAULT).
|
|
|
|
The destroying of fast memory cache cannot be done any time. We need
|
|
to be sure that there isn't any other thread which uses mmaped memory.
|
|
The new counter of active threads was added for this purpose. The state
|
|
of fast memory cache was converted from boolean to three value state
|
|
(UNINITIALIZED, INITIALIZED, RECYCLED)
|
|
UNINITIALIZED
|
|
- the fast memory cache need to be initialized.
|
|
- if there is a problem with initialisation the state will not change
|
|
- after successful initialisation, the state will change to INITIALIZED
|
|
INITIALIZED
|
|
- if the cahe was invalidated or there is any other problem was
|
|
detected in memory cache header the state will change to RECYCLED
|
|
and memory cache IS NOT destroyed.
|
|
RECYCLED
|
|
- nothing will be done is there are any active threads which may use
|
|
the data from mmaped memory
|
|
- if there aren't active threads the fast memory cahe is destroyed and
|
|
state is changed to UNINITIALIZED.
|
|
|
|
https://fedorahosted.org/sssd/ticket/2445
|
|
|
|
Reviewed-by: Michal Židek <mzidek@redhat.com>
|
|
---
|
|
src/sss_client/nss_mc.h | 10 ++++++++-
|
|
src/sss_client/nss_mc_common.c | 46 ++++++++++++++++++++++++++++++++++--------
|
|
src/sss_client/nss_mc_group.c | 8 ++++++--
|
|
src/sss_client/nss_mc_passwd.c | 8 ++++++--
|
|
4 files changed, 59 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/src/sss_client/nss_mc.h b/src/sss_client/nss_mc.h
|
|
index 685cc41c0530750d890050f0917dc88be14d96ea..050bd4100dec091cb096a7d97bfe6615b12654da 100644
|
|
--- a/src/sss_client/nss_mc.h
|
|
+++ b/src/sss_client/nss_mc.h
|
|
@@ -33,9 +33,15 @@
|
|
typedef int errno_t;
|
|
#endif
|
|
|
|
+enum sss_mc_state {
|
|
+ UNINITIALIZED = 0,
|
|
+ INITIALIZED,
|
|
+ RECYCLED,
|
|
+};
|
|
+
|
|
/* common stuff */
|
|
struct sss_cli_mc_ctx {
|
|
- bool initialized;
|
|
+ enum sss_mc_state initialized;
|
|
int fd;
|
|
|
|
uint32_t seed; /* seed from the tables header */
|
|
@@ -48,6 +54,8 @@ struct sss_cli_mc_ctx {
|
|
|
|
uint32_t *hash_table; /* hash table address (in mmap) */
|
|
uint32_t ht_size; /* size of hash table */
|
|
+
|
|
+ uint32_t active_threads; /* count of threads which use memory cache */
|
|
};
|
|
|
|
errno_t sss_nss_mc_get_ctx(const char *name, struct sss_cli_mc_ctx *ctx);
|
|
diff --git a/src/sss_client/nss_mc_common.c b/src/sss_client/nss_mc_common.c
|
|
index 9c6e1af1642275fc7738b51d7ca80d712d49b2ac..89ff6b46e2abee03039cfd632ef50231eab92eec 100644
|
|
--- a/src/sss_client/nss_mc_common.c
|
|
+++ b/src/sss_client/nss_mc_common.c
|
|
@@ -123,7 +123,7 @@ static errno_t sss_nss_mc_init_ctx(const char *name,
|
|
|
|
sss_nss_lock();
|
|
/* check if ctx is initialised by previous thread. */
|
|
- if (ctx->initialized) {
|
|
+ if (ctx->initialized != UNINITIALIZED) {
|
|
ret = sss_nss_check_header(ctx);
|
|
goto done;
|
|
}
|
|
@@ -163,7 +163,7 @@ static errno_t sss_nss_mc_init_ctx(const char *name,
|
|
goto done;
|
|
}
|
|
|
|
- ctx->initialized = true;
|
|
+ ctx->initialized = INITIALIZED;
|
|
|
|
ret = 0;
|
|
|
|
@@ -181,22 +181,52 @@ errno_t sss_nss_mc_get_ctx(const char *name, struct sss_cli_mc_ctx *ctx)
|
|
{
|
|
char *envval;
|
|
int ret;
|
|
+ bool need_decrement = false;
|
|
|
|
envval = getenv("SSS_NSS_USE_MEMCACHE");
|
|
if (envval && strcasecmp(envval, "NO") == 0) {
|
|
return EPERM;
|
|
}
|
|
|
|
- if (ctx->initialized) {
|
|
+ switch (ctx->initialized) {
|
|
+ case UNINITIALIZED:
|
|
+ __sync_add_and_fetch(&ctx->active_threads, 1);
|
|
+ ret = sss_nss_mc_init_ctx(name, ctx);
|
|
+ if (ret) {
|
|
+ need_decrement = true;
|
|
+ }
|
|
+ break;
|
|
+ case INITIALIZED:
|
|
+ __sync_add_and_fetch(&ctx->active_threads, 1);
|
|
ret = sss_nss_check_header(ctx);
|
|
- goto done;
|
|
+ if (ret) {
|
|
+ need_decrement = true;
|
|
+ }
|
|
+ break;
|
|
+ case RECYCLED:
|
|
+ /* we need to safely destroy memory cache */
|
|
+ ret = EAGAIN;
|
|
+ break;
|
|
+ default:
|
|
+ ret = EFAULT;
|
|
}
|
|
|
|
- ret = sss_nss_mc_init_ctx(name, ctx);
|
|
-
|
|
-done:
|
|
if (ret) {
|
|
- sss_nss_mc_destroy_ctx(ctx);
|
|
+ if (ctx->initialized == INITIALIZED) {
|
|
+ ctx->initialized = RECYCLED;
|
|
+ }
|
|
+ if (ctx->initialized == RECYCLED && ctx->active_threads == 0) {
|
|
+ /* just one thread should call munmap */
|
|
+ sss_nss_lock();
|
|
+ if (ctx->initialized == RECYCLED) {
|
|
+ sss_nss_mc_destroy_ctx(ctx);
|
|
+ }
|
|
+ sss_nss_unlock();
|
|
+ }
|
|
+ if (need_decrement) {
|
|
+ /* In case of error, we will not touch mmapped area => decrement */
|
|
+ __sync_sub_and_fetch(&ctx->active_threads, 1);
|
|
+ }
|
|
}
|
|
return ret;
|
|
}
|
|
diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c
|
|
index 268b40ef02f2a621c4f61755ce4dfe2c3786bfa6..e0fdb97f628ac19741409be29566e4af5a391f74 100644
|
|
--- a/src/sss_client/nss_mc_group.c
|
|
+++ b/src/sss_client/nss_mc_group.c
|
|
@@ -29,7 +29,8 @@
|
|
#include "nss_mc.h"
|
|
#include "util/util_safealign.h"
|
|
|
|
-struct sss_cli_mc_ctx gr_mc_ctx = { false, -1, 0, NULL, 0, NULL, 0, NULL, 0 };
|
|
+struct sss_cli_mc_ctx gr_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0,
|
|
+ NULL, 0, 0 };
|
|
|
|
static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
|
|
struct group *result,
|
|
@@ -176,6 +177,7 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
|
|
|
|
done:
|
|
free(rec);
|
|
+ __sync_sub_and_fetch(&gr_mc_ctx.active_threads, 1);
|
|
return ret;
|
|
}
|
|
|
|
@@ -198,7 +200,8 @@ errno_t sss_nss_mc_getgrgid(gid_t gid,
|
|
|
|
len = snprintf(gidstr, 11, "%ld", (long)gid);
|
|
if (len > 10) {
|
|
- return EINVAL;
|
|
+ ret = EINVAL;
|
|
+ goto done;
|
|
}
|
|
|
|
/* hashes are calculated including the NULL terminator */
|
|
@@ -242,6 +245,7 @@ errno_t sss_nss_mc_getgrgid(gid_t gid,
|
|
|
|
done:
|
|
free(rec);
|
|
+ __sync_sub_and_fetch(&gr_mc_ctx.active_threads, 1);
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c
|
|
index fa19afc3c0e468430183ed3f13b80e086251ee01..10e43e2af43c5e7f1738e281b3ed260d89f3a004 100644
|
|
--- a/src/sss_client/nss_mc_passwd.c
|
|
+++ b/src/sss_client/nss_mc_passwd.c
|
|
@@ -28,7 +28,8 @@
|
|
#include <time.h>
|
|
#include "nss_mc.h"
|
|
|
|
-struct sss_cli_mc_ctx pw_mc_ctx = { false, -1, 0, NULL, 0, NULL, 0, NULL, 0 };
|
|
+struct sss_cli_mc_ctx pw_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0,
|
|
+ NULL, 0, 0 };
|
|
|
|
static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec,
|
|
struct passwd *result,
|
|
@@ -170,6 +171,7 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
|
|
|
|
done:
|
|
free(rec);
|
|
+ __sync_sub_and_fetch(&pw_mc_ctx.active_threads, 1);
|
|
return ret;
|
|
}
|
|
|
|
@@ -192,7 +194,8 @@ errno_t sss_nss_mc_getpwuid(uid_t uid,
|
|
|
|
len = snprintf(uidstr, 11, "%ld", (long)uid);
|
|
if (len > 10) {
|
|
- return EINVAL;
|
|
+ ret = EINVAL;
|
|
+ goto done;
|
|
}
|
|
|
|
/* hashes are calculated including the NULL terminator */
|
|
@@ -236,6 +239,7 @@ errno_t sss_nss_mc_getpwuid(uid_t uid,
|
|
|
|
done:
|
|
free(rec);
|
|
+ __sync_sub_and_fetch(&pw_mc_ctx.active_threads, 1);
|
|
return ret;
|
|
}
|
|
|
|
--
|
|
2.1.0
|
|
|