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