f8783c3
commit fe7dfb14c45262df3b15bda374b2ee390b43cfb4
c2434ec
Author: John Dennis <jdennis@redhat.com>
f8783c3
Date:   Tue Aug 14 18:08:56 2018 -0400
c2434ec
c2434ec
    test_proto_authorization_request() segfault due to uninitialized value
c2434ec
    
c2434ec
    Many thanks to Florian Weimer <fweimer@redhat.com> for his assistence
c2434ec
    in helping diagnose the problem.
c2434ec
    
c2434ec
    In test_proto_authorization_request() it creates a provider object but
c2434ec
    fails to fully initialize it. In particular it fails to initialize
c2434ec
    auth_request_method to OIDC_AUTH_REQUEST_METHOD_GET.
c2434ec
    
c2434ec
    The function oidc_proto_authorization_request() in the file
c2434ec
    src/proto.c has a weak test for provider->auth_request_method on line
c2434ec
    646.
c2434ec
    
c2434ec
    if (provider->auth_request_method == OIDC_AUTH_REQUEST_METHOD_POST) {
c2434ec
        /* construct a HTML POST auto-submit page with the authorization request parameters */
c2434ec
    } else {
c2434ec
        /* construct the full authorization request URL */
c2434ec
    }
c2434ec
    
c2434ec
    The assumption is provider->auth_request_method must be one of
c2434ec
    OIDC_AUTH_REQUEST_METHOD_GET or OIDC_AUTH_REQUEST_METHOD_POST but if
c2434ec
    the provider struct is not properly initialized it could be any random
c2434ec
    value. Therefore the fact provider->auth_request_method does not equal
c2434ec
    OIDC_AUTH_REQUEST_METHOD_POST does not imply it's
c2434ec
    OIDC_AUTH_REQUEST_METHOD_GET. The test would also be a problem if
c2434ec
    OIDC_AUTH_REQUEST_METHOD ever added a new enumerated value.
c2434ec
    
c2434ec
    The defined values for OIDC_AUTH_REQUEST_METHOD are:
f8783c3
    define OIDC_AUTH_REQUEST_METHOD_GET  0
f8783c3
    define OIDC_AUTH_REQUEST_METHOD_POST 1
c2434ec
    
c2434ec
    So what the test on line src/proto.c:646 is really saying is this:
c2434ec
    if provider->auth_request_method != 1 then use the GET method.
c2434ec
    
c2434ec
    The unit test works most of the time because it's unlikely the
c2434ec
    unitialized auth_request_method member will be exactly 1. Except on
c2434ec
    some architectures it is (e.g. s390x). Of course what's on the stack
c2434ec
    is influenced by a variety of factors (all unknown).
c2434ec
    
c2434ec
    The segfault occurs because oidc_proto_authorization_request() takes
c2434ec
    the OIDC_AUTH_REQUEST_METHOD_POST branch and calls
c2434ec
    oidc_proto_html_post() which then operates on more uninitialized
c2434ec
    data. Specfically request->connection->bucket_alloc is
c2434ec
    NULL. Fortunately the request object was intialized to zero via
c2434ec
    apr_pcalloc() so at least bucket_alloc will consistetnly be NULL.
c2434ec
    
c2434ec
    Here is the stack trace:
c2434ec
    
c2434ec
    Program received signal SIGSEGV, Segmentation fault.
c2434ec
    0x00007ffff6b9f67a in apr_bucket_alloc () from /lib64/libaprutil-1.so.0
c2434ec
    (gdb) bt
c2434ec
       from /lib64/libaprutil-1.so.0
c2434ec
        data=0x6adfe0 "\n<html>\n  <head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <title>Submitting"...,
c2434ec
        data_len=825, content_type=0x47311a "text/html", success_rvalue=-2)
c2434ec
        at src/util.c:1307
c2434ec
        title=0x46bf28 "Submitting...", html_head=0x0,
c2434ec
        on_load=0x46bf0d "document.forms[0].submit()",
c2434ec
        html_body=0x6add40 "    

Submitting Authentication Request...

\n <form method=\"post\" action=\"https://idp.example.com/authorize\">\n

\n <input type=\"hidden\" name=\"response_type\" value=\"code\">\n

c2434ec
        url=0x465758 "https://idp.example.com/authorize", params=0x6acf30)
c2434ec
        at src/proto.c:544
c2434ec
        provider=0x7fffffffd260, login_hint=0x0,
c2434ec
        redirect_uri=0x465790 "https://www.example.com/protected/",
c2434ec
        state=0x4657b3 "12345", proto_state=0x68e5f0, id_token_hint=0x0,
c2434ec
        nge=0x0, auth_request_params=0x0, path_scope=0x0) at src/proto.c:650
c2434ec
    
c2434ec
    This patch does the following:
c2434ec
    
c2434ec
    1) Initializes the provider struct created on the stack in
c2434ec
    test_proto_authorization_request to zero so it's at least
c2434ec
    initialized to known consistent values.
c2434ec
    
c2434ec
    2) Initializes provider.auth_request_method to
c2434ec
    OIDC_AUTH_REQUEST_METHOD_GET.
c2434ec
    
c2434ec
    3) Initializes request->connection->bucket_alloc via
c2434ec
    apr_bucket_alloc_create() so if one does enter that code it won't
c2434ec
    segfault.
c2434ec
    
c2434ec
    It's easy to verify the above observations.
c2434ec
    
c2434ec
    If you explicitly intialize provider.auth_request_method to
c2434ec
    OIDC_AUTH_REQUEST_METHOD_POST in test_proto_authorization_request()
c2434ec
    instead of allowing it to be a random stack value you will segfault
c2434ec
    every time. However if you initialize request->connection->bucket_alloc
c2434ec
    the segfault goes away and the unit test correctly reports the error,
c2434ec
    e.g.
c2434ec
    
c2434ec
    Failed:  # test_proto_authorization_request: error in oidc_proto_authorization_request (1): result "0" != expected "1"
c2434ec
    
c2434ec
    WARNING: This patch does not address the test in proto.c:646. That
c2434ec
    test should be augmented to assure only valid enumerated values are
c2434ec
    operated on and if the enumerated value is not valid it should return
c2434ec
    an error.
c2434ec
    
f8783c3
Note: The above was fixed in the following commit.
f8783c3
c2434ec
    Signed-off-by: John Dennis <jdennis@redhat.com>
c2434ec
c2434ec
diff --git a/test/test.c b/test/test.c
c2434ec
index 16f09b5..87d3700 100755
c2434ec
--- a/test/test.c
c2434ec
+++ b/test/test.c
c2434ec
@@ -1019,6 +1019,9 @@ static char *test_proto_validate_code(request_rec *r) {
c2434ec
 static char * test_proto_authorization_request(request_rec *r) {
c2434ec
 
c2434ec
 	oidc_provider_t provider;
c2434ec
+
c2434ec
+        memset(&provider, 0, sizeof(provider));
c2434ec
+
c2434ec
 	provider.issuer = "https://idp.example.com";
c2434ec
 	provider.authorization_endpoint_url = "https://idp.example.com/authorize";
c2434ec
 	provider.scope = "openid";
c2434ec
@@ -1028,6 +1031,8 @@ static char * test_proto_authorization_request(request_rec *r) {
c2434ec
 	provider.auth_request_params = NULL;
c2434ec
 	provider.request_object = NULL;
c2434ec
 	provider.token_binding_policy = OIDC_TOKEN_BINDING_POLICY_OPTIONAL;
c2434ec
+        provider.auth_request_method = OIDC_AUTH_REQUEST_METHOD_GET;
c2434ec
+
c2434ec
 	const char *redirect_uri = "https://www.example.com/protected/";
c2434ec
 	const char *state = "12345";
c2434ec
 
c2434ec
@@ -1260,6 +1265,7 @@ static request_rec * test_setup(apr_pool_t *pool) {
c2434ec
 			sizeof(struct process_rec));
c2434ec
 	request->server->process->pool = request->pool;
c2434ec
 	request->connection = apr_pcalloc(request->pool, sizeof(struct conn_rec));
c2434ec
+        request->connection->bucket_alloc = apr_bucket_alloc_create(request->pool);
c2434ec
 	request->connection->local_addr = apr_pcalloc(request->pool,
c2434ec
 			sizeof(apr_sockaddr_t));
c2434ec
 
f8783c3
commit aca77a82c1ce2f1ec8f363066ffbc480b3bd75c8
f8783c3
Author: Hans Zandbelt <hans.zandbelt@zmartzone.eu>
f8783c3
Date:   Wed Aug 15 07:47:57 2018 +0200
f8783c3
f8783c3
    add sanity check on provider->auth_request_method; closes #382
f8783c3
    
f8783c3
    thanks @jdennis; bump to 2.3.8rc4
f8783c3
    
f8783c3
    Signed-off-by: Hans Zandbelt <hans.zandbelt@zmartzone.eu>
f8783c3
f8783c3
diff --git a/src/proto.c b/src/proto.c
f8783c3
index e9dbc99..ac7696a 100644
f8783c3
--- a/src/proto.c
f8783c3
+++ b/src/proto.c
f8783c3
@@ -649,7 +649,7 @@ int oidc_proto_authorization_request(request_rec *r,
f8783c3
 		rv = oidc_proto_html_post(r, provider->authorization_endpoint_url,
f8783c3
 				params);
f8783c3
 
f8783c3
-	} else {
f8783c3
+	} else if (provider->auth_request_method == OIDC_AUTH_REQUEST_METHOD_GET) {
f8783c3
 
f8783c3
 		/* construct the full authorization request URL */
f8783c3
 		authorization_request = oidc_util_http_query_encoded_url(r,
f8783c3
@@ -666,6 +666,10 @@ int oidc_proto_authorization_request(request_rec *r,
f8783c3
 			/* and tell Apache to return an HTTP Redirect (302) message */
f8783c3
 			rv = HTTP_MOVED_TEMPORARILY;
f8783c3
 		}
f8783c3
+	} else {
f8783c3
+		oidc_error(r, "provider->auth_request_method set to wrong value: %d",
f8783c3
+				provider->auth_request_method);
f8783c3
+		return HTTP_INTERNAL_SERVER_ERROR;
f8783c3
 	}
f8783c3
 
f8783c3
 	/* add a referred token binding request for the provider if enabled */