summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/responder/nss/nsssrv_mmap_cache.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
index 95a7fe9d..fced018e 100644
--- a/src/responder/nss/nsssrv_mmap_cache.c
+++ b/src/responder/nss/nsssrv_mmap_cache.c
@@ -93,6 +93,68 @@ struct sss_mc_ctx {
else used = false; \
} while (0)
+/* This function will store corrupted memcache to disk for later
+ * analysis. */
+static void sss_mc_save_corrupted(struct sss_mc_ctx *mc_ctx)
+{
+ int err;
+ int fd = -1;
+ ssize_t written;
+ char *file = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ if (mc_ctx == NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Cannot store uninitialized cache. Nothing to do.\n"));
+ return;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory.\n"));
+ return;
+ }
+
+ file = talloc_asprintf(tmp_ctx, "%s_%s",
+ mc_ctx->file, "corrupted");
+ if (file == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory.\n"));
+ goto done;
+ }
+
+ /* We will always store only the last problematic cache state */
+ fd = creat(file, 0600);
+ if (fd == -1) {
+ err = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Failed to open file '%s' [%d]: %s\n",
+ file, err, strerror(err)));
+ goto done;
+ }
+
+ written = write(fd, mc_ctx->mmap_base, mc_ctx->mmap_size);
+ if (written != mc_ctx->mmap_size) {
+ if (written == -1) {
+ err = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("write() failed [%d]: %s\n", err, strerror(err)));
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("write() returned %zd (expected (%zd))\n",
+ written, mc_ctx->mmap_size));
+ }
+ goto done;
+ }
+
+ sss_log(SSS_LOG_NOTICE,
+ "Stored copy of corrupted mmap cache in file '%s\n'", file);
+done:
+ if (fd != -1) {
+ close(fd);
+ }
+ talloc_free(tmp_ctx);
+}
+
static uint32_t sss_mc_hash(struct sss_mc_ctx *mcc,
const char *key, size_t len)
{
@@ -421,6 +483,7 @@ static struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc,
if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
DEBUG(SSSDBG_FATAL_FAILURE,
("Corrupted fastcache. Slot number too big.\n"));
+ sss_mc_save_corrupted(mcc);
sss_mmap_cache_reset(mcc);
return NULL;
}
@@ -437,6 +500,7 @@ static struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc,
|| (uint8_t *)rec->data + strs_offset + strs_len > max_addr) {
DEBUG(SSSDBG_FATAL_FAILURE,
("Corrupted fastcache. name_ptr value is %u.\n", name_ptr));
+ sss_mc_save_corrupted(mcc);
sss_mmap_cache_reset(mcc);
return NULL;
}
@@ -675,6 +739,7 @@ errno_t sss_mmap_cache_pw_invalidate_uid(struct sss_mc_ctx *mcc, uid_t uid)
while (slot != MC_INVALID_VAL) {
if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
DEBUG(SSSDBG_FATAL_FAILURE, ("Corrupted fastcache.\n"));
+ sss_mc_save_corrupted(mcc);
sss_mmap_cache_reset(mcc);
ret = ENOENT;
goto done;
@@ -813,6 +878,7 @@ errno_t sss_mmap_cache_gr_invalidate_gid(struct sss_mc_ctx *mcc, gid_t gid)
while (slot != MC_INVALID_VAL) {
if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
DEBUG(SSSDBG_FATAL_FAILURE, ("Corrupted fastcache.\n"));
+ sss_mc_save_corrupted(mcc);
sss_mmap_cache_reset(mcc);
ret = ENOENT;
goto done;