Blame 0064-mmap_cache-make-checks-independent-of-input-size.patch

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