From 8a8869994745429b3f5535a5d0b91f1d0b2fa723 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 29 Mar 2023 12:58:37 +0200
Subject: [PATCH] fail_over: protect against a segmentation fault
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

A missing server name in struct fo_server will cause a segmentation
fault. Currently it is unclear why the server name is missing at this
point. To avoid the segmentation fault it is checked before if the
server name is missing. Additionally the state of some internal
structures is added to the debug logs to help debugging why the server
name is missing.

Resolves: https://github.com/SSSD/sssd/issues/6659

Reviewed-by: Alejandro López <allopez@redhat.com>
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>

Reference: https://github.com/SSSD/sssd/commit/8a8869994745429b3f5535a5d0b91f1d0b2fa723
Conflict: data_provider_fo.c
---
 src/providers/data_provider_fo.c | 14 +++++++++
 src/providers/fail_over.c        | 53 ++++++++++++++++++++++++++++++++
 src/providers/fail_over.h        |  3 ++
 3 files changed, 70 insertions(+)

diff --git a/src/external/sizes.m4 b/src/external/sizes.m4
index c4f00d66ff..0b6b630026 100644
--- a/src/external/sizes.m4
+++ b/src/external/sizes.m4
@@ -9,6 +9,7 @@ AC_CHECK_SIZEOF(long long)
 AC_CHECK_SIZEOF(uid_t)
 AC_CHECK_SIZEOF(gid_t)
 AC_CHECK_SIZEOF(id_t)
+AC_CHECK_SIZEOF(time_t)
 
 if test $ac_cv_sizeof_long_long -lt 8 ; then
 AC_MSG_ERROR([SSSD requires long long of 64-bits])
 
diff --git a/src/util/sss_format.h b/src/util/sss_format.h
index 9a30417..a9f3770 100644
--- a/src/util/sss_format.h
+++ b/src/util/sss_format.h
@@ -64,5 +64,12 @@
 # error Unexpected sizeof gid_t
 #endif /* SIZEOF_GID_T */
 
+#if SIZEOF_TIME_T == 8
+# define SPRItime PRId64
+#elif SIZEOF_TIME_T == 4
+# define SPRItime PRId32
+#else
+# error Unexpected sizeof time_t
+#endif /*SIZEOF_TIME_T*/
 
 #endif /* __SSS_FORMAT_H__ */
 
diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index eca5f2f8e..b0aed54e9 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -594,6 +594,14 @@ fail:
     tevent_req_error(req, ret);
 }
 
+static void dump_be_svc_data(const struct be_svc_data *svc)
+{
+    DEBUG(SSSDBG_OP_FAILURE, "be_svc_data: name=[%s] last_good_srv=[%s] "
+                             "last_good_port=[%d] last_status_change=[%"SPRItime"]\n",
+                             svc->name, svc->last_good_srv, svc->last_good_port,
+                             svc->last_status_change);
+}
+
 errno_t be_resolve_server_process(struct tevent_req *subreq,
                                   struct be_resolve_server_state *state,
                                   struct tevent_req **new_subreq)
@@ -681,6 +689,12 @@ errno_t be_resolve_server_process(struct tevent_req *subreq,
         DEBUG(SSSDBG_FUNC_DATA, "Found address for server %s: [%s] TTL %d\n",
               fo_get_server_str_name(state->srv), ipaddr,
               srvaddr->addr_list[0]->ttl);
+    } else {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing server name.\n");
+        dump_be_svc_data(state->svc);
+        dump_fo_server(state->srv);
+        dump_fo_server_list(state->srv);
+        return ENOENT;
     }
 
     srv_status_change = fo_get_server_hostname_last_change(state->srv);
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index 9cb26838c..7cb642448 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -200,6 +200,59 @@ str_srv_data_status(enum srv_lookup_status status)
     return "unknown SRV lookup status";
 }
 
+static void dump_srv_data(const struct srv_data *srv_data)
+{
+    if (srv_data == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "srv_data is NULL\n");
+        return;
+    }
+
+    DEBUG(SSSDBG_OP_FAILURE, "srv_data: dns_domain [%s] discovery_domain [%s] "
+                             "sssd_domain [%s] proto [%s] srv [%s] "
+                             "srv_lookup_status [%s] ttl [%d] "
+                             "last_status_change [%"SPRItime"]\n",
+                             srv_data->dns_domain == NULL ? "dns_domain is NULL"
+                                                          : srv_data->dns_domain,
+                             srv_data->discovery_domain == NULL ? "discovery_domain is NULL"
+                                                                : srv_data->discovery_domain,
+                             srv_data->sssd_domain == NULL ? "sssd_domain is NULL"
+                                                           : srv_data->sssd_domain,
+                             srv_data->proto == NULL ? "proto is NULL"
+                                                     : srv_data->proto,
+                             srv_data->srv == NULL ? "srv is NULL"
+                                                   : srv_data->srv,
+                             str_srv_data_status(srv_data->srv_lookup_status),
+                             srv_data->ttl, srv_data->last_status_change.tv_sec);
+}
+
+void dump_fo_server(const struct fo_server *srv)
+{
+    DEBUG(SSSDBG_OP_FAILURE, "fo_server: primary [%s] port [%d] "
+                             "port_status [%s] common->name [%s].\n",
+                             srv->primary ? "true" : "false", srv->port,
+                             str_port_status(srv->port_status),
+                             srv->common == NULL ? "common is NULL"
+                                                 : (srv->common->name == NULL
+                                                        ? "common->name is NULL"
+                                                        : srv->common->name));
+    dump_srv_data(srv->srv_data);
+}
+
+void dump_fo_server_list(const struct fo_server *srv)
+{
+    const struct fo_server *s;
+
+    s = srv;
+    while (s->prev != NULL) {
+        s = s->prev;
+    }
+
+    while (s != NULL) {
+        dump_fo_server(s);
+        s = s->next;
+    }
+}
+
 static const char *
 str_server_status(enum server_status status)
 {
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
index 92a0456b5..36021ad6f 100644
--- a/src/providers/fail_over.h
+++ b/src/providers/fail_over.h
@@ -88,6 +88,9 @@ struct fo_options {
     enum restrict_family family_order;
 };
 
+void dump_fo_server(const struct fo_server *srv);
+void dump_fo_server_list(const struct fo_server *srv);
+
 /*
  * Create a new fail over context based on options passed in the
  * opts parameter
-- 
2.27.0

