Blame SOURCES/0058-mmap_cache-make-checks-independent-of-input-size.patch

9f2ebf
From 531c0ad3e13ddc1f5c31a620aa1f8b91aa8a4053 Mon Sep 17 00:00:00 2001
9f2ebf
From: Sumit Bose <sbose@redhat.com>
9f2ebf
Date: Fri, 17 Nov 2017 10:51:44 +0100
9f2ebf
Subject: [PATCH 58/59] mmap_cache: make checks independent of input size
9f2ebf
MIME-Version: 1.0
9f2ebf
Content-Type: text/plain; charset=UTF-8
9f2ebf
Content-Transfer-Encoding: 8bit
9f2ebf
9f2ebf
Currently the consistency checks for the mmap_cache payload data on the
9f2ebf
client and the responder side include the length of the input string of
9f2ebf
the current request. Since there might be hash collisions which other
9f2ebf
much longer or much shorter names those checks might fail although there
9f2ebf
is no data corruption.
9f2ebf
9f2ebf
This patch removes the checks using the length of the input and adds a
9f2ebf
check if the name found in the payload is zero-terminated inside of the
9f2ebf
payload data.
9f2ebf
9f2ebf
Resolves https://pagure.io/SSSD/sssd/issue/3571
9f2ebf
9f2ebf
Reviewed-by: Michal Židek <mzidek@redhat.com>
9f2ebf
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
9f2ebf
(cherry picked from commit 4382047490dd4f80b407cc1e618da048f13e5f8f)
9f2ebf
---
9f2ebf
 src/responder/nss/nsssrv_mmap_cache.c | 34 ++++++++++++++++++++++++----------
9f2ebf
 src/sss_client/nss_mc_group.c         | 14 ++++++++------
9f2ebf
 src/sss_client/nss_mc_initgr.c        | 14 +++++++++-----
9f2ebf
 src/sss_client/nss_mc_passwd.c        | 14 ++++++++------
9f2ebf
 4 files changed, 49 insertions(+), 27 deletions(-)
9f2ebf
9f2ebf
diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
9f2ebf
index a87ad646f9b741db3eb18680678697032fc420ba..ad5adbce15e50c065d4d16e626be97fd23d06643 100644
9f2ebf
--- a/src/responder/nss/nsssrv_mmap_cache.c
9f2ebf
+++ b/src/responder/nss/nsssrv_mmap_cache.c
9f2ebf
@@ -547,18 +547,32 @@ static struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc,
9f2ebf
             return NULL;
9f2ebf
         }
9f2ebf
 
9f2ebf
+        if (key->len > strs_len) {
9f2ebf
+            /* The string cannot be in current record */
9f2ebf
+            slot = sss_mc_next_slot_with_hash(rec, hash);
9f2ebf
+            continue;
9f2ebf
+        }
9f2ebf
+
9f2ebf
         safealign_memcpy(&name_ptr, rec->data, sizeof(rel_ptr_t), NULL);
9f2ebf
-        if (key->len > strs_len
9f2ebf
-            || (name_ptr + key->len) > (strs_offset + strs_len)
9f2ebf
-            || (uint8_t *)rec->data + strs_offset + strs_len > max_addr) {
9f2ebf
-            DEBUG(SSSDBG_FATAL_FAILURE,
9f2ebf
-                  "Corrupted fastcache. name_ptr value is %u.\n", name_ptr);
9f2ebf
-            sss_mc_save_corrupted(mcc);
9f2ebf
-            sss_mmap_cache_reset(mcc);
9f2ebf
-            return NULL;
9f2ebf
-        }
9f2ebf
-
9f2ebf
         t_key = (char *)rec->data + name_ptr;
9f2ebf
+        /* name_ptr must point to some data in the strs/gids area of the data
9f2ebf
+         * payload. Since it is a pointer relative to rec->data it must larger
9f2ebf
+         * equal strs_offset and must be smaller then strs_offset + strs_len.
9f2ebf
+         * Additionally the area must not end outside of the data table and
9f2ebf
+         * t_key must be a zero-terminates string. */
9f2ebf
+        if (name_ptr < strs_offset
9f2ebf
+                || name_ptr >= strs_offset + strs_len
9f2ebf
+                || (uint8_t *)rec->data > max_addr
9f2ebf
+                || strs_offset > max_addr - (uint8_t *)rec->data
9f2ebf
+                || strs_len > max_addr - (uint8_t *)rec->data - strs_offset) {
9f2ebf
+            DEBUG(SSSDBG_FATAL_FAILURE,
9f2ebf
+                  "Corrupted fastcache entry at slot %u. "
9f2ebf
+                  "name_ptr value is %u.\n", slot, name_ptr);
9f2ebf
+            sss_mc_save_corrupted(mcc);
9f2ebf
+            sss_mmap_cache_reset(mcc);
9f2ebf
+            return NULL;
9f2ebf
+        }
9f2ebf
+
9f2ebf
         if (strcmp(key->str, t_key) == 0) {
9f2ebf
             break;
9f2ebf
         }
9f2ebf
diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c
9f2ebf
index ce88d42fdaf4f19e78fc43e187bc28651cdc3c4e..4b1601a171a3af700b6f0d2bfedb3a6198e6df6d 100644
9f2ebf
--- a/src/sss_client/nss_mc_group.c
9f2ebf
+++ b/src/sss_client/nss_mc_group.c
9f2ebf
@@ -148,20 +148,22 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
9f2ebf
         }
9f2ebf
 
9f2ebf
         data = (struct sss_mc_grp_data *)rec->data;
9f2ebf
+        rec_name = (char *)data + data->name;
9f2ebf
         /* Integrity check
9f2ebf
-         * - name_len cannot be longer than all strings
9f2ebf
          * - data->name cannot point outside strings
9f2ebf
          * - all strings must be within copy of record
9f2ebf
-         * - size of record must be lower that data table size */
9f2ebf
-        if (name_len > data->strs_len
9f2ebf
-            || (data->name + name_len) > (strs_offset + data->strs_len)
9f2ebf
+         * - record must not end outside data table
9f2ebf
+         * - rec_name is a zero-terminated string */
9f2ebf
+        if (data->name < strs_offset
9f2ebf
+            || data->name >= strs_offset + data->strs_len
9f2ebf
             || data->strs_len > rec->len
9f2ebf
-            || rec->len > data_size) {
9f2ebf
+            || (uint8_t *) rec + rec->len > gr_mc_ctx.data_table + data_size
9f2ebf
+            || memchr(rec_name, '\0',
9f2ebf
+                      (strs_offset + data->strs_len) - data->name) == NULL) {
9f2ebf
             ret = ENOENT;
9f2ebf
             goto done;
9f2ebf
         }
9f2ebf
 
9f2ebf
-        rec_name = (char *)data + data->name;
9f2ebf
         if (strcmp(name, rec_name) == 0) {
9f2ebf
             break;
9f2ebf
         }
9f2ebf
diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c
9f2ebf
index a77088d849ad3601cb3edb55fc5ea4ae4c52fe38..d8c01f52ea2d23515d0b462541657dc9416b0915 100644
9f2ebf
--- a/src/sss_client/nss_mc_initgr.c
9f2ebf
+++ b/src/sss_client/nss_mc_initgr.c
9f2ebf
@@ -131,15 +131,19 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
9f2ebf
         data = (struct sss_mc_initgr_data *)rec->data;
9f2ebf
         rec_name = (char *)data + data->name;
9f2ebf
         /* Integrity check
9f2ebf
-         * - name_len cannot be longer than all strings or data
9f2ebf
+         * - data->name cannot point outside all strings or data
9f2ebf
          * - all data must be within copy of record
9f2ebf
          * - size of record must be lower that data table size
9f2ebf
-         * - data->strs cannot point outside strings */
9f2ebf
-        if (name_len > data->strs_len
9f2ebf
+         * - data->strs cannot point outside strings
9f2ebf
+         * - rec_name is a zero-terminated string */
9f2ebf
+        if (data->name < data_offset
9f2ebf
+            || data->name >= data_offset + data->data_len
9f2ebf
             || data->strs_len > data->data_len
9f2ebf
             || data->data_len > rec->len
9f2ebf
-            || rec->len > data_size
9f2ebf
-            || (data->strs + name_len) > (data_offset + data->data_len)) {
9f2ebf
+            || (uint8_t *) rec + rec->len
9f2ebf
+                                       > initgr_mc_ctx.data_table + data_size
9f2ebf
+            || memchr(rec_name, '\0',
9f2ebf
+                      (data_offset + data->data_len) - data->name) == NULL) {
9f2ebf
             ret = ENOENT;
9f2ebf
             goto done;
9f2ebf
         }
9f2ebf
diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c
9f2ebf
index 0da7ad0aeece7d38ca34bb3fde64adc898eaf0ae..868427f03a7ec0c8bd7401c8547a6f6bead7af28 100644
9f2ebf
--- a/src/sss_client/nss_mc_passwd.c
9f2ebf
+++ b/src/sss_client/nss_mc_passwd.c
9f2ebf
@@ -141,20 +141,22 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
9f2ebf
         }
9f2ebf
 
9f2ebf
         data = (struct sss_mc_pwd_data *)rec->data;
9f2ebf
+        rec_name = (char *)data + data->name;
9f2ebf
         /* Integrity check
9f2ebf
-         * - name_len cannot be longer than all strings
9f2ebf
          * - data->name cannot point outside strings
9f2ebf
          * - all strings must be within copy of record
9f2ebf
-         * - size of record must be lower that data table size */
9f2ebf
-        if (name_len > data->strs_len
9f2ebf
-            || (data->name + name_len) > (strs_offset + data->strs_len)
9f2ebf
+         * - record must not end outside data table
9f2ebf
+         * - rec_name is a zero-terminated string */
9f2ebf
+        if (data->name < strs_offset
9f2ebf
+            || data->name >= strs_offset + data->strs_len
9f2ebf
             || data->strs_len > rec->len
9f2ebf
-            || rec->len > data_size) {
9f2ebf
+            || (uint8_t *) rec + rec->len > pw_mc_ctx.data_table + data_size
9f2ebf
+            || memchr(rec_name, '\0',
9f2ebf
+                      (strs_offset + data->strs_len) - data->name) == NULL ) {
9f2ebf
             ret = ENOENT;
9f2ebf
             goto done;
9f2ebf
         }
9f2ebf
 
9f2ebf
-        rec_name = (char *)data + data->name;
9f2ebf
         if (strcmp(name, rec_name) == 0) {
9f2ebf
             break;
9f2ebf
         }
9f2ebf
-- 
9f2ebf
2.14.3
9f2ebf