]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
login-common: Heap allocate login source IPs array to avoid use-after-free
authorJosef 'Jeff' Sipek <jeff.sipek@open-xchange.com>
Thu, 17 Sep 2020 14:45:44 +0000 (10:45 -0400)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Wed, 7 Oct 2020 11:46:54 +0000 (11:46 +0000)
By default, the service init code runs with a temporary datastack frame that
gets freed at the end of initialization to get rid of any temporary
allocations made during init before the long-running part of the process
executes.

src/login-common/main.c

index 648e46f5ea15aa017848ebb0cf0c05a26db0e26a..a4e559738566c82aad6cac0fcde68333f2fc4ce7 100644 (file)
@@ -54,6 +54,7 @@ const struct login_settings *global_login_settings;
 const struct master_service_ssl_settings *global_ssl_settings;
 void **global_other_settings;
 
+static ARRAY(struct ip_addr) login_source_ips_array;
 const struct ip_addr *login_source_ips;
 unsigned int login_source_ips_idx, login_source_ips_count;
 
@@ -315,10 +316,9 @@ void login_anvil_init(void)
                i_fatal("Couldn't connect to anvil");
 }
 
-static const struct ip_addr *
-parse_login_source_ips(const char *ips_str, unsigned int *count_r)
+static void
+parse_login_source_ips(const char *ips_str)
 {
-       ARRAY(struct ip_addr) ips;
        const char *const *tmp;
        struct ip_addr *tmp_ips;
        bool skip_nonworking = FALSE;
@@ -332,7 +332,7 @@ parse_login_source_ips(const char *ips_str, unsigned int *count_r)
                skip_nonworking = TRUE;
                ips_str++;
        }
-       t_array_init(&ips, 4);
+       i_array_init(&login_source_ips_array, 4);
        for (tmp = t_strsplit_spaces(ips_str, ", "); *tmp != NULL; tmp++) {
                ret = net_gethostbyname(*tmp, &tmp_ips, &tmp_ips_count);
                if (ret != 0) {
@@ -343,10 +343,13 @@ parse_login_source_ips(const char *ips_str, unsigned int *count_r)
                for (i = 0; i < tmp_ips_count; i++) {
                        if (skip_nonworking && net_try_bind(&tmp_ips[i]) < 0)
                                continue;
-                       array_push_back(&ips, &tmp_ips[i]);
+                       array_push_back(&login_source_ips_array, &tmp_ips[i]);
                }
        }
-       return array_get(&ips, count_r);
+
+       /* make the array contents easily accessible */
+       login_source_ips = array_get(&login_source_ips_array,
+                                    &login_source_ips_count);
 }
 
 static void login_load_modules(void)
@@ -422,8 +425,7 @@ static void main_preinit(void)
 
        /* read the login_source_ips before chrooting so it can access
           /etc/hosts */
-       login_source_ips = parse_login_source_ips(global_login_settings->login_source_ips,
-                                                 &login_source_ips_count);
+       parse_login_source_ips(global_login_settings->login_source_ips);
        if (login_source_ips_count > 0) {
                /* randomize the initial index in case service_count=1
                   (although in that case it's unlikely this setting is
@@ -559,6 +561,7 @@ int login_binary_run(struct login_binary *binary,
        master_service_init_finish(master_service);
        master_service_run(master_service, client_connected);
        main_deinit();
+       array_free(&login_source_ips_array);
        pool_unref(&set_pool);
        master_service_deinit(&master_service);
         return 0;