|
|
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 |
|