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

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