From cf8304cadf7008a086860e0abcbba03b969fcb20 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sat, 14 Apr 2018 14:22:02 +0200 Subject: [PATCH] sec-mod/main: eliminate mem leaks related to vhost transition Signed-off-by: Nikos Mavrogiannopoulos --- src/config.c | 29 ++++++++++++++++++++--------- src/main-sec-mod-cmd.c | 11 +++++++++++ src/main.c | 2 +- src/sec-mod.c | 5 +++-- src/sec-mod.h | 1 + src/tlslib.c | 5 ++++- src/vpn.h | 2 +- 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/config.c b/src/config.c index d6983c4b..a85f18f8 100644 --- a/src/config.c +++ b/src/config.c @@ -1048,9 +1048,13 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name, co return 0; } +enum { + CFG_FLAG_RELOAD = (1<<0), + CFG_FLAG_SECMOD = (1<<1) +}; static void parse_cfg_file(void *pool, const char *file, struct list_head *head, - unsigned reload) + unsigned flags) { int ret; struct cfg_st *config; @@ -1060,7 +1064,7 @@ static void parse_cfg_file(void *pool, const char *file, struct list_head *head, memset(&ctx, 0, sizeof(ctx)); ctx.file = file; - ctx.reload = reload; + ctx.reload = (flags&CFG_FLAG_RELOAD)?1:0; ctx.head = head; /* parse configuration @@ -1109,11 +1113,14 @@ static void parse_cfg_file(void *pool, const char *file, struct list_head *head, defvhost = NULL; /* this check copies mandatory fields from default vhost if needed */ - check_cfg(vhost, defvhost, reload); + check_cfg(vhost, defvhost, ctx.reload); - tls_load_files(NULL, vhost); - tls_load_prio(NULL, vhost); - tls_reload_crl(NULL, vhost, 1); + /* the following are only useful in main process */ + if (!(flags & CFG_FLAG_SECMOD)) { + tls_load_files(NULL, vhost); + tls_load_prio(NULL, vhost); + tls_reload_crl(NULL, vhost, 1); + } #ifdef HAVE_GSSAPI if (vhost->urlfw_size > 0) { @@ -1550,12 +1557,16 @@ static void print_version(void) } -void reload_cfg_file(void *pool, struct list_head *configs, unsigned archive) +void reload_cfg_file(void *pool, struct list_head *configs, unsigned sec_mod) { struct vhost_cfg_st* vhost = NULL; + unsigned flags = CFG_FLAG_RELOAD; + + if (sec_mod) + flags |= CFG_FLAG_SECMOD; /* Archive or clear any non-permanent configs */ - if (archive) + if (!sec_mod) archive_cfg(configs); else clear_cfg(configs); @@ -1567,7 +1578,7 @@ void reload_cfg_file(void *pool, struct list_head *configs, unsigned archive) } /* parse the config again */ - parse_cfg_file(pool, cfg_file, configs, 1); + parse_cfg_file(pool, cfg_file, configs, flags); return; } diff --git a/src/main-sec-mod-cmd.c b/src/main-sec-mod-cmd.c index aaeabf65..5eb2bc3d 100644 --- a/src/main-sec-mod-cmd.c +++ b/src/main-sec-mod-cmd.c @@ -675,6 +675,16 @@ void secmod_socket_file_name(struct perm_cfg_st *perm_config, char *name, unsign perm_config->socket_file_prefix, (unsigned)getpid()); } +static void clear_unneeded_mem(struct list_head *vconfig) +{ + vhost_cfg_st *vhost = NULL; + + /* deinitialize certificate credentials etc. */ + list_for_each_rev(vconfig, vhost, list) { + tls_vhost_deinit(vhost); + } +} + /* Returns two file descriptors to be used for communication with sec-mod. * The sync_fd is used by main to send synchronous commands- commands which * expect a reply immediately. @@ -728,6 +738,7 @@ int run_sec_mod(main_server_st *s, int *sync_fd) close(sfd[1]); set_cloexec_flag (fd[0], 1); set_cloexec_flag (sfd[0], 1); + clear_unneeded_mem(s->vconfig); sec_mod_server(s->main_pool, s->config_pool, s->vconfig, p, fd[0], sfd[0]); exit(0); } else if (pid > 0) { /* parent */ diff --git a/src/main.c b/src/main.c index 322bcda0..3f1a7735 100644 --- a/src/main.c +++ b/src/main.c @@ -1033,7 +1033,7 @@ static void reload_sig_watcher_cb(struct ev_loop *loop, ev_signal *w, int revent * That's because of a test that the certificate matches the * used key. */ ms_sleep(1500); - reload_cfg_file(s->config_pool, s->vconfig, 1); + reload_cfg_file(s->config_pool, s->vconfig, 0); } static void cmd_watcher_cb (EV_P_ ev_io *w, int revents) diff --git a/src/sec-mod.c b/src/sec-mod.c index bb6e6179..e7219b59 100644 --- a/src/sec-mod.c +++ b/src/sec-mod.c @@ -626,13 +626,13 @@ static void check_other_work(sec_mod_st *sec) sec_mod_client_db_deinit(sec); tls_cache_deinit(&sec->tls_db); talloc_free(sec->config_pool); - talloc_free(sec); + talloc_free(sec->sec_mod_pool); exit(0); } if (need_reload) { seclog(sec, LOG_DEBUG, "reloading configuration"); - reload_cfg_file(sec, sec->vconfig, 0); + reload_cfg_file(sec, sec->vconfig, 1); load_keys(sec, 0); list_for_each(sec->vconfig, vhost, list) { @@ -918,6 +918,7 @@ void sec_mod_server(void *main_pool, void *config_pool, struct list_head *vconfi sec->vconfig = vconfig; sec->config_pool = config_pool; + sec->sec_mod_pool = sec_mod_pool; tls_cache_init(sec, &sec->tls_db); sup_config_init(sec); diff --git a/src/sec-mod.h b/src/sec-mod.h index 18161bd9..e2c413c7 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -35,6 +35,7 @@ typedef struct sec_mod_st { struct list_head *vconfig; void *config_pool; + void *sec_mod_pool; struct htable *client_db; int cmd_fd; diff --git a/src/tlslib.c b/src/tlslib.c index 91b1e934..9603bec4 100644 --- a/src/tlslib.c +++ b/src/tlslib.c @@ -816,7 +816,7 @@ int load_cert_files(main_server_st *s, struct vhost_cfg_st *vhost) } pcert_list_size = 8; - pcert_list = gnutls_malloc(sizeof(pcert_list[0])*pcert_list_size); + pcert_list = talloc_size(vhost->pool, sizeof(pcert_list[0])*pcert_list_size); if (pcert_list == NULL) { mslog(s, NULL, LOG_ERR, "error allocating memory"); return -1; @@ -1038,6 +1038,9 @@ void tls_load_prio(main_server_st *s, struct vhost_cfg_st *vhost) int ret; const char* perr; + if (vhost->creds.cprio != NULL) + gnutls_priority_deinit(vhost->creds.cprio); + ret = gnutls_priority_init(&vhost->creds.cprio, vhost->perm_config.config->priorities, &perr); if (ret == GNUTLS_E_PARSING_ERROR) mslog(s, NULL, LOG_ERR, "error in TLS priority string: %s", perr); diff --git a/src/vpn.h b/src/vpn.h index 72d2bd0c..b66c683b 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -427,7 +427,7 @@ enum option_types { OPTION_NUMERIC, OPTION_STRING, OPTION_BOOLEAN, OPTION_MULTI_ #include -void reload_cfg_file(void *pool, struct list_head *configs, unsigned archive); +void reload_cfg_file(void *pool, struct list_head *configs, unsigned sec_mod); void clear_old_configs(struct list_head *configs); void write_pid_file(void); void remove_pid_file(void);