URL: https://github.com/SSSD/sssd/pull/126
Author: lslebodn
 Title: #126: ldap_child: Fix use after free
Action: opened

PR body:
"""
In case on any krb5 related error, we tried to send string
interpretation of krb5 error tb parrent in prepare_response.

However, we cannot use global krb5 context (krb5_error_ctx)
because the context is every time released in done section of
ldap_child_get_tgt_sync.

This patch rather return duplicated string to prevent use after free.

Backtrace:
```
 #0  __strchr_sse42 () at ../sysdeps/x86_64/multiarch/strchr.S:100
 100     ../sysdeps/x86_64/multiarch/strchr.S: No such file or directory.

 Thread 1 (Thread 0x7fc96cad5880 (LWP 11201)):
 #0  __strchr_sse42 () at ../sysdeps/x86_64/multiarch/strchr.S:100
 No locals.
 #1  0x00007fc96be43725 in err_fmt_fmt (msg=0x7fc96d1cf8d0 "Cannot find KDC for 
requested realm",
                                        code=-1765328230,
                                        err_fmt=<optimized out>) at kerrs.c:152
        buf = {buftype = K5BUF_DYNAMIC, data = 0x7fc96d1cdb10,
               space = 128, len = 0}
        p = <optimized out>
        s = 0xdededededededede <Address 0xdededededededede out of bounds>
 #2  krb5_get_error_message (ctx=<optimized out>,
                             code=code@entry=-1765328230) at kerrs.c:184
        std = 0x7fc96d1cf8d0 "Cannot find KDC for requested realm"
 #3  0x00007fc96cb224e5 in sss_krb5_get_error_message (ctx=<optimized out>,
                                                       ec=ec@entry=-1765328230) 
at src/util/sss_krb5.c:424
 No locals.
 #4  0x00007fc96cb1fbb0 in prepare_response (rsp=<synthetic pointer>,
                                             kerr=-1765328230, expire_time=0,
                                             ccname=0x0,
                                             mem_ctx=0x7fc96d1cb390) at 
src/providers/ldap/ldap_child.c:553
        ret = <optimized out>
        r = 0x7fc96d1cd8b0
        krb5_msg = 0x0
```


Related parts of logs:
```
[System Logs]:
Jan 17 06:20:08 fserver-1658118.example.com [sssd[ldap_child[15788]]][15788]: 
Failed to initialize credentials using keytab [MEMORY:/etc/krb5.keytab]: Client 
'FSERVER-1658118$@EXAMPLE.COM' not found in Kerberos database. Unable to create 
GSSAPI-encrypted LDAP connection.
Jan 17 06:20:08 fserver-1658118.example.com [sssd[ldap_child[15788]]][15788]: 
Client 'FSERVER-1658118$@EXAMPLE.COM' not found in Kerberos database
Jan 17 06:20:08 fserver-1658118.example.com kernel: traps: ldap_child[15788] 
general protection ip:7f7faf2e505a sp:7ffd3f768478 error:0 in 
libc-2.17.so[7f7faf260000+1b6000]
Jan 17 06:20:08 fserver-1658118.example.com abrt-hook-ccpp[15793]: Process 
15788 (ldap_child) of user 0 killed by SIGSEGV - dumping core
[User Logs]:
Jan 17 06:20:08 fserver-1658118.example.com [sssd[ldap_child[15788]]][15788]: 
Failed to initialize credentials using keytab [MEMORY:/etc/krb5.keytab]: Client 
'FSERVER-1658118$@EXAMPLE.COM' not found in Kerberos database. Unable to create 
GSSAPI-encrypted LDAP connection.
Jan 17 06:20:08 fserver-1658118.example.com [sssd[ldap_child[15788]]][15788]: 
Client 'FSERVER-1658118$@EXAMPLE.COM' not found in Kerberos database
Jan 17 06:20:08 fserver-1658118.example.com abrt-hook-ccpp[15793]: Process 
15788 (ldap_child) of user 0 killed by SIGSEGV - dumping core
```
"""

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/126/head:pr126
git checkout pr126
From 864b23bae7225e39317523cd7325efadda4b87b6 Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lsleb...@redhat.com>
Date: Tue, 17 Jan 2017 10:17:24 +0100
Subject: [PATCH] ldap_child: Fix use after free

In case on any krb5 related error, we tried to send string
interpretation of krb5 error tb parrent in prepare_response.

However, we cannot use global krb5 context (krb5_error_ctx)
because the context is every time released in done section of
ldap_child_get_tgt_sync.

This patch rather return duplicated string to prevent use after free.

Backtrace:
 #0  __strchr_sse42 () at ../sysdeps/x86_64/multiarch/strchr.S:100
 100     ../sysdeps/x86_64/multiarch/strchr.S: No such file or directory.

 Thread 1 (Thread 0x7fc96cad5880 (LWP 11201)):
 #0  __strchr_sse42 () at ../sysdeps/x86_64/multiarch/strchr.S:100
 No locals.
 #1  0x00007fc96be43725 in err_fmt_fmt (msg=0x7fc96d1cf8d0 "Cannot find KDC for requested realm",
                                        code=-1765328230,
                                        err_fmt=<optimized out>) at kerrs.c:152
        buf = {buftype = K5BUF_DYNAMIC, data = 0x7fc96d1cdb10,
               space = 128, len = 0}
        p = <optimized out>
        s = 0xdededededededede <Address 0xdededededededede out of bounds>
 #2  krb5_get_error_message (ctx=<optimized out>,
                             code=code@entry=-1765328230) at kerrs.c:184
        std = 0x7fc96d1cf8d0 "Cannot find KDC for requested realm"
 #3  0x00007fc96cb224e5 in sss_krb5_get_error_message (ctx=<optimized out>,
                                                       ec=ec@entry=-1765328230) at src/util/sss_krb5.c:424
 No locals.
 #4  0x00007fc96cb1fbb0 in prepare_response (rsp=<synthetic pointer>,
                                             kerr=-1765328230, expire_time=0,
                                             ccname=0x0,
                                             mem_ctx=0x7fc96d1cb390) at src/providers/ldap/ldap_child.c:553
        ret = <optimized out>
        r = 0x7fc96d1cd8b0
        krb5_msg = 0x0
---
 src/providers/ldap/ldap_child.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c
index ffcbc39..3f88a28 100644
--- a/src/providers/ldap/ldap_child.c
+++ b/src/providers/ldap/ldap_child.c
@@ -276,7 +276,8 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
                                                const char *keytab_name,
                                                const krb5_deltat lifetime,
                                                const char **ccname_out,
-                                               time_t *expire_time_out)
+                                               time_t *expire_time_out,
+                                               char **_krb5_msg)
 {
     char *ccname;
     char *ccname_dummy;
@@ -522,7 +523,14 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
     *expire_time_out = my_creds.times.endtime - kdc_time_offset;
 
 done:
-    if (krberr != 0) KRB5_SYSLOG(krberr);
+    if (krberr != 0) {
+        const char *krb5_msg;
+
+        KRB5_SYSLOG(krberr);
+        krb5_msg = sss_krb5_get_error_message(context, krberr);
+        *_krb5_msg = talloc_strdup(memctx, krb5_msg);
+        sss_krb5_free_error_message(context, krb5_msg);
+    }
     if (keytab) krb5_kt_close(context, keytab);
     if (context) krb5_free_context(context);
     talloc_free(tmp_ctx);
@@ -533,11 +541,11 @@ static int prepare_response(TALLOC_CTX *mem_ctx,
                             const char *ccname,
                             time_t expire_time,
                             krb5_error_code kerr,
+                            char *krb5_msg,
                             struct response **rsp)
 {
     int ret;
     struct response *r = NULL;
-    const char *krb5_msg = NULL;
 
     r = talloc_zero(mem_ctx, struct response);
     if (!r) return ENOMEM;
@@ -550,15 +558,13 @@ static int prepare_response(TALLOC_CTX *mem_ctx,
     if (kerr == 0) {
         ret = pack_buffer(r, EOK, kerr, ccname, expire_time);
     } else {
-        krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr);
         if (krb5_msg == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE,
-                    "sss_krb5_get_error_message failed.\n");
+                  "Empty krb5 error message for non-zero kerr: %"PRIi32"\n",
+                  kerr);
             return ENOMEM;
         }
-
         ret = pack_buffer(r, EFAULT, kerr, krb5_msg, 0);
-        sss_krb5_free_error_message(krb5_error_ctx, krb5_msg);
     }
 
     if (ret != EOK) {
@@ -605,6 +611,7 @@ int main(int argc, const char *argv[])
     uint8_t *buf = NULL;
     ssize_t len = 0;
     const char *ccname = NULL;
+    char *krb5_msg = NULL;
     time_t expire_time = 0;
     struct input_buffer *ibuf = NULL;
     struct response *resp = NULL;
@@ -721,13 +728,14 @@ int main(int argc, const char *argv[])
     kerr = ldap_child_get_tgt_sync(main_ctx, ibuf->context,
                                    ibuf->realm_str, ibuf->princ_str,
                                    ibuf->keytab_name, ibuf->lifetime,
-                                   &ccname, &expire_time);
+                                   &ccname, &expire_time, &krb5_msg);
     if (kerr != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child_get_tgt_sync failed.\n");
         /* Do not return, must report failure */
     }
 
-    ret = prepare_response(main_ctx, ccname, expire_time, kerr, &resp);
+    ret = prepare_response(main_ctx, ccname, expire_time, kerr, krb5_msg,
+                           &resp);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "prepare_response failed. [%d][%s].\n",
                     ret, strerror(ret));
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org

Reply via email to