sssd/SOURCES/mc-recover-from-invalid-mem...

221 lines
6.0 KiB
Diff

From 641e5f73d3bd5b3d32cafd551013d3bfd2a52732 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 4 Aug 2023 12:19:49 +0200
Subject: [PATCH] mc: recover from invalid memory cache size
If we access the mmap file outside its boundaries a SIGBUS is raised.
We can now safely recover if the file has unexpected size.
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/responder/nss/nsssrv_mmap_cache.c | 86 +++++++++++++++++----
src/sss_client/nss_mc_common.c | 42 +++++++---
2 files changed, 135 insertions(+), 29 deletions(-)
diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
index 12c2996596..bd814f3bc7 100644
--- a/src/responder/nss/nsssrv_mmap_cache.c
+++ b/src/responder/nss/nsssrv_mmap_cache.c
@@ -722,6 +722,57 @@ static errno_t sss_mmap_cache_invalidate(struct sss_mc_ctx *mcc,
return EOK;
}
+static errno_t sss_mmap_cache_validate_or_reinit(struct sss_mc_ctx **_mcc)
+{
+ struct sss_mc_ctx *mcc = *_mcc;
+ struct stat fdstat;
+ bool reinit = false;
+ errno_t ret;
+
+ /* No mcc initialized? Memory cache may be disabled. */
+ if (mcc == NULL || mcc->fd < 0) {
+ ret = EINVAL;
+ reinit = false;
+ goto done;
+ }
+
+ if (fstat(mcc->fd, &fdstat) == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to stat memory cache [file=%s, fd=%d] [%d]: %s\n",
+ mcc->file, mcc->fd, ret, sss_strerror(ret));
+ reinit = true;
+ goto done;
+ }
+
+ if (fdstat.st_nlink == 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Memory cache file was removed\n");
+ ret = ENOENT;
+ reinit = true;
+ goto done;
+ }
+
+ if (fdstat.st_size != mcc->mmap_size) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Memory cache is corrupted, invalid size [file=%s, fd=%d, "
+ "expected_size=%zu, real_size=%zu]\n",
+ mcc->file, mcc->fd, mcc->mmap_size, fdstat.st_size);
+ ret = EINVAL;
+ reinit = true;
+ goto done;
+ }
+
+ ret = EOK;
+ reinit = false;
+
+done:
+ if (reinit) {
+ return sss_mmap_cache_reinit(talloc_parent(mcc), -1, -1, -1, -1, _mcc);
+ }
+
+ return ret;
+}
+
/***************************************************************************
* passwd map
***************************************************************************/
@@ -744,9 +795,9 @@ errno_t sss_mmap_cache_pw_store(struct sss_mc_ctx **_mcc,
size_t pos;
int ret;
- if (mcc == NULL) {
- /* cache not initialized? */
- return EINVAL;
+ ret = sss_mmap_cache_validate_or_reinit(&mcc);
+ if (ret != EOK) {
+ return ret;
}
ret = snprintf(uidstr, 11, "%ld", (long)uid);
@@ -815,9 +866,9 @@ errno_t sss_mmap_cache_pw_invalidate_uid(struct sss_mc_ctx *mcc, uid_t uid)
char *uidstr;
errno_t ret;
- if (mcc == NULL) {
- /* cache not initialized? */
- return EINVAL;
+ ret = sss_mmap_cache_validate_or_reinit(&mcc);
+ if (ret != EOK) {
+ return ret;
}
uidstr = talloc_asprintf(NULL, "%ld", (long)uid);
@@ -886,9 +937,9 @@ int sss_mmap_cache_gr_store(struct sss_mc_ctx **_mcc,
size_t pos;
int ret;
- if (mcc == NULL) {
- /* cache not initialized? */
- return EINVAL;
+ ret = sss_mmap_cache_validate_or_reinit(&mcc);
+ if (ret != EOK) {
+ return ret;
}
ret = snprintf(gidstr, 11, "%ld", (long)gid);
@@ -953,9 +1004,9 @@ errno_t sss_mmap_cache_gr_invalidate_gid(struct sss_mc_ctx *mcc, gid_t gid)
char *gidstr;
errno_t ret;
- if (mcc == NULL) {
- /* cache not initialized? */
- return EINVAL;
+ ret = sss_mmap_cache_validate_or_reinit(&mcc);
+ if (ret != EOK) {
+ return ret;
}
gidstr = talloc_asprintf(NULL, "%ld", (long)gid);
@@ -1018,9 +1069,9 @@ errno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
size_t pos;
int ret;
- if (mcc == NULL) {
- /* cache not initialized? */
- return EINVAL;
+ ret = sss_mmap_cache_validate_or_reinit(&mcc);
+ if (ret != EOK) {
+ return ret;
}
/* array of gids + name + unique_name */
@@ -1087,8 +1138,9 @@ errno_t sss_mmap_cache_sid_store(struct sss_mc_ctx **_mcc,
size_t rec_len;
int ret;
- if (mcc == NULL) {
- return EINVAL;
+ ret = sss_mmap_cache_validate_or_reinit(&mcc);
+ if (ret != EOK) {
+ return ret;
}
ret = snprintf(idkey, sizeof(idkey), "%d-%ld",
diff --git a/src/sss_client/nss_mc_common.c b/src/sss_client/nss_mc_common.c
index 3128861bf3..e227c0bae3 100644
--- a/src/sss_client/nss_mc_common.c
+++ b/src/sss_client/nss_mc_common.c
@@ -69,13 +69,43 @@ static void sss_mt_unlock(struct sss_cli_mc_ctx *ctx)
#endif
}
+static errno_t sss_nss_mc_validate(struct sss_cli_mc_ctx *ctx)
+{
+ struct stat fdstat;
+
+ /* No mc ctx initialized?*/
+ if (ctx == NULL || ctx->fd < 0) {
+ return EINVAL;
+ }
+
+ if (fstat(ctx->fd, &fdstat) == -1) {
+ return errno;
+ }
+
+ /* Memcache was removed. */
+ if (fdstat.st_nlink == 0) {
+ return ENOENT;
+ }
+
+ /* Invalid size. */
+ if (fdstat.st_size != ctx->mmap_size) {
+ return ERANGE;
+ }
+
+ return EOK;
+}
+
errno_t sss_nss_check_header(struct sss_cli_mc_ctx *ctx)
{
struct sss_mc_header h;
bool copy_ok;
int count;
int ret;
- struct stat fdstat;
+
+ ret = sss_nss_mc_validate(ctx);
+ if (ret != EOK) {
+ return ret;
+ }
/* retry barrier protected reading max 5 times then give up */
for (count = 5; count > 0; count--) {
@@ -115,16 +145,6 @@ errno_t sss_nss_check_header(struct sss_cli_mc_ctx *ctx)
}
}
- ret = fstat(ctx->fd, &fdstat);
- if (ret == -1) {
- return EIO;
- }
-
- if (fdstat.st_nlink == 0) {
- /* memory cache was removed; we need to reinitialize it. */
- return EINVAL;
- }
-
return 0;
}