Blame SOURCES/0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch

bb7cd1
From 088be07a9e5aae54379a7f98e9e4615cd4451501 Mon Sep 17 00:00:00 2001
bb7cd1
From: Jakub Hrozek <jhrozek@redhat.com>
bb7cd1
Date: Wed, 29 Mar 2017 22:49:09 +0200
bb7cd1
Subject: [PATCH 73/90] KCM: Fix off-by-one error in secrets key parsing
bb7cd1
MIME-Version: 1.0
bb7cd1
Content-Type: text/plain; charset=UTF-8
bb7cd1
Content-Transfer-Encoding: 8bit
bb7cd1
bb7cd1
When parsing the secrets key, the code tried to protect against malformed keys
bb7cd1
or keys that are too short, but it did an error - the UUID stringified
bb7cd1
form is 36 bytes long, so the UUID_STR_SIZE is 37 because UUID_STR_SIZE
bb7cd1
accounts for the null terminator.
bb7cd1
bb7cd1
But the code, that was trying to assert that there are two characters after
bb7cd1
the UUID string (separator and at least a single character for the name)
bb7cd1
didn't take the NULL terminator (which strlen() doesn't return) into
bb7cd1
account and ended up rejecting all ccaches whose name is only a single
bb7cd1
character.
bb7cd1
bb7cd1
Reviewed-by: Fabiano FidĂȘncio <fidencio@redhat.com>
bb7cd1
(cherry picked from commit 7d73049884e3a96ca3b00b5bd4104f4edd6287ab)
bb7cd1
---
bb7cd1
 src/responder/kcm/kcmsrv_ccache_json.c       | 43 +++++++++-------
bb7cd1
 src/tests/cmocka/test_kcm_json_marshalling.c | 75 ++++++++++++++++++++++++++++
bb7cd1
 2 files changed, 101 insertions(+), 17 deletions(-)
bb7cd1
bb7cd1
diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
bb7cd1
index 40b64861c209206d6f60ccd0843857edee24a844..8199bc613e4204859438e1cd820f3f4b2123dd7e 100644
bb7cd1
--- a/src/responder/kcm/kcmsrv_ccache_json.c
bb7cd1
+++ b/src/responder/kcm/kcmsrv_ccache_json.c
bb7cd1
@@ -109,6 +109,28 @@ static const char *sec_key_create(TALLOC_CTX *mem_ctx,
bb7cd1
                            "%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name);
bb7cd1
 }
bb7cd1
 
bb7cd1
+static bool sec_key_valid(const char *sec_key)
bb7cd1
+{
bb7cd1
+    if (sec_key == NULL) {
bb7cd1
+        return false;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (strlen(sec_key) < UUID_STR_SIZE + 1) {
bb7cd1
+        /* One char for separator (at UUID_STR_SIZE, because strlen doesn't
bb7cd1
+         * include the '\0', but UUID_STR_SIZE does) and at least one for
bb7cd1
+         * the name */
bb7cd1
+        DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
bb7cd1
+        return false;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) {
bb7cd1
+        DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
bb7cd1
+        return false;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    return true;
bb7cd1
+}
bb7cd1
+
bb7cd1
 static errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
bb7cd1
                              const char *sec_key,
bb7cd1
                              const char **_name,
bb7cd1
@@ -116,9 +138,7 @@ static errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
bb7cd1
 {
bb7cd1
     char uuid_str[UUID_STR_SIZE];
bb7cd1
 
bb7cd1
-    if (strlen(sec_key) < UUID_STR_SIZE + 2) {
bb7cd1
-        /* One char for separator and at least one for the name */
bb7cd1
-        DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
bb7cd1
+    if (!sec_key_valid(sec_key)) {
bb7cd1
         return EINVAL;
bb7cd1
     }
bb7cd1
 
bb7cd1
@@ -143,14 +163,7 @@ errno_t sec_key_get_uuid(const char *sec_key,
bb7cd1
 {
bb7cd1
     char uuid_str[UUID_STR_SIZE];
bb7cd1
 
bb7cd1
-    if (strlen(sec_key) < UUID_STR_SIZE + 2) {
bb7cd1
-        /* One char for separator and at least one for the name */
bb7cd1
-        DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
bb7cd1
-        return EINVAL;
bb7cd1
-    }
bb7cd1
-
bb7cd1
-    if (sec_key[UUID_STR_SIZE-1] != SEC_KEY_SEPARATOR) {
bb7cd1
-        DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
bb7cd1
+    if (!sec_key_valid(sec_key)) {
bb7cd1
         return EINVAL;
bb7cd1
     }
bb7cd1
 
bb7cd1
@@ -162,9 +175,7 @@ errno_t sec_key_get_uuid(const char *sec_key,
bb7cd1
 
bb7cd1
 const char *sec_key_get_name(const char *sec_key)
bb7cd1
 {
bb7cd1
-    if (strlen(sec_key) < UUID_STR_SIZE + 2) {
bb7cd1
-        /* One char for separator and at least one for the name */
bb7cd1
-        DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
bb7cd1
+    if (!sec_key_valid(sec_key)) {
bb7cd1
         return NULL;
bb7cd1
     }
bb7cd1
 
bb7cd1
@@ -174,9 +185,7 @@ const char *sec_key_get_name(const char *sec_key)
bb7cd1
 bool sec_key_match_name(const char *sec_key,
bb7cd1
                         const char *name)
bb7cd1
 {
bb7cd1
-    if (strlen(sec_key) < UUID_STR_SIZE + 2) {
bb7cd1
-        /* One char for separator and at least one for the name */
bb7cd1
-        DEBUG(SSSDBG_MINOR_FAILURE, "Key %s is too short\n", sec_key);
bb7cd1
+    if (!sec_key_valid(sec_key) || name == NULL) {
bb7cd1
         return false;
bb7cd1
     }
bb7cd1
 
bb7cd1
diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c
bb7cd1
index 8eff2f501066c70a8730cd3d4dc41b92d7a03e4c..108eaf55628029a6de8c23cd6486bdccc42c0364 100644
bb7cd1
--- a/src/tests/cmocka/test_kcm_json_marshalling.c
bb7cd1
+++ b/src/tests/cmocka/test_kcm_json_marshalling.c
bb7cd1
@@ -32,6 +32,12 @@
bb7cd1
 
bb7cd1
 #define TEST_CREDS                "TESTCREDS"
bb7cd1
 
bb7cd1
+#define TEST_UUID_STR             "5f8f296b-02be-4e86-9235-500e82354186"
bb7cd1
+#define TEST_SEC_KEY_ONEDIGIT     TEST_UUID_STR"-0"
bb7cd1
+#define TEST_SEC_KEY_MULTIDIGITS  TEST_UUID_STR"-123456"
bb7cd1
+
bb7cd1
+#define TEST_SEC_KEY_NOSEP        TEST_UUID_STR"+0"
bb7cd1
+
bb7cd1
 const struct kcm_ccdb_ops ccdb_mem_ops;
bb7cd1
 const struct kcm_ccdb_ops ccdb_sec_ops;
bb7cd1
 
bb7cd1
@@ -188,6 +194,72 @@ static void test_kcm_ccache_marshall_unmarshall(void **state)
bb7cd1
     assert_int_equal(ret, EOK);
bb7cd1
 
bb7cd1
     assert_cc_equal(cc, cc2);
bb7cd1
+
bb7cd1
+    /* This key is exactly one byte shorter than it should be */
bb7cd1
+    ret = sec_kv_to_ccache(test_ctx,
bb7cd1
+                           TEST_UUID_STR"-",
bb7cd1
+                           (const char *) data,
bb7cd1
+                           &owner,
bb7cd1
+                           &cc2;;
bb7cd1
+    assert_int_equal(ret, EINVAL);
bb7cd1
+}
bb7cd1
+
bb7cd1
+void test_sec_key_get_uuid(void **state)
bb7cd1
+{
bb7cd1
+    errno_t ret;
bb7cd1
+    uuid_t uuid;
bb7cd1
+    char str_uuid[UUID_STR_SIZE];
bb7cd1
+
bb7cd1
+    uuid_clear(uuid);
bb7cd1
+    ret = sec_key_get_uuid(TEST_SEC_KEY_ONEDIGIT, uuid);
bb7cd1
+    assert_int_equal(ret, EOK);
bb7cd1
+    uuid_unparse(uuid, str_uuid);
bb7cd1
+    assert_string_equal(TEST_UUID_STR, str_uuid);
bb7cd1
+
bb7cd1
+    ret = sec_key_get_uuid(TEST_SEC_KEY_NOSEP, uuid);
bb7cd1
+    assert_int_equal(ret, EINVAL);
bb7cd1
+
bb7cd1
+    ret = sec_key_get_uuid(TEST_UUID_STR, uuid);
bb7cd1
+    assert_int_equal(ret, EINVAL);
bb7cd1
+
bb7cd1
+    ret = sec_key_get_uuid(NULL, uuid);
bb7cd1
+    assert_int_equal(ret, EINVAL);
bb7cd1
+}
bb7cd1
+
bb7cd1
+void test_sec_key_get_name(void **state)
bb7cd1
+{
bb7cd1
+    const char *name;
bb7cd1
+
bb7cd1
+    name = sec_key_get_name(TEST_SEC_KEY_ONEDIGIT);
bb7cd1
+    assert_non_null(name);
bb7cd1
+    assert_string_equal(name, "0");
bb7cd1
+
bb7cd1
+    name = sec_key_get_name(TEST_SEC_KEY_MULTIDIGITS);
bb7cd1
+    assert_non_null(name);
bb7cd1
+    assert_string_equal(name, "123456");
bb7cd1
+
bb7cd1
+    name = sec_key_get_name(TEST_UUID_STR);
bb7cd1
+    assert_null(name);
bb7cd1
+
bb7cd1
+    name = sec_key_get_name(TEST_SEC_KEY_NOSEP);
bb7cd1
+    assert_null(name);
bb7cd1
+
bb7cd1
+    name = sec_key_get_name(NULL);
bb7cd1
+    assert_null(name);
bb7cd1
+}
bb7cd1
+
bb7cd1
+void test_sec_key_match_name(void **state)
bb7cd1
+{
bb7cd1
+    assert_true(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "0"));
bb7cd1
+    assert_true(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "123456"));
bb7cd1
+
bb7cd1
+    assert_false(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "0"));
bb7cd1
+    assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "123456"));
bb7cd1
+
bb7cd1
+    assert_false(sec_key_match_name(TEST_UUID_STR, "0"));
bb7cd1
+    assert_false(sec_key_match_name(TEST_SEC_KEY_NOSEP, "0"));
bb7cd1
+    assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, NULL));
bb7cd1
+    assert_false(sec_key_match_name(NULL, "0"));
bb7cd1
 }
bb7cd1
 
bb7cd1
 int main(int argc, const char *argv[])
bb7cd1
@@ -205,6 +277,9 @@ int main(int argc, const char *argv[])
bb7cd1
         cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall,
bb7cd1
                                         setup_kcm_marshalling,
bb7cd1
                                         teardown_kcm_marshalling),
bb7cd1
+        cmocka_unit_test(test_sec_key_get_uuid),
bb7cd1
+        cmocka_unit_test(test_sec_key_get_name),
bb7cd1
+        cmocka_unit_test(test_sec_key_match_name),
bb7cd1
     };
bb7cd1
 
bb7cd1
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
bb7cd1
-- 
bb7cd1
2.9.3
bb7cd1