Hello, Michal. Here's a patch for some memory leaks on reconfiguration.
Maybe you'd find it useful. There are still some leaks but now it seems to
work much better.
2014-11-19 14:04 GMT+03:00 Michal Trojnara <[email protected]>:
> Hi Alexander,
>
> This is a known issue. Fixing it is already on the TODO list.
> http://www.stunnel.org/sdf_todo.html
>
> Mike
>
> On November 19, 2014 9:19:16 AM CET, Alexander Paramonov <
> [email protected]> wrote:
> >Hello, colleagues!
> >
> >I suppose there is a memory leak on stunnel reconfiguration when it
> >receives the SIGHUP signal. Here is my experiment with stunnel 5.05 on
> >linux:
> >
> >~/busybox $ cat /home/posdebug/stunnel.cfg
> >debug=6
> >options=NO_SSLv2
> >pid=/tmp/stunnel.pid
> >[57797]
> >accept = 127.0.0.1:57797
> >connect = 80.90.125.219:64141
> >key = /usr/unsign/key.pem
> >cert = /usr/unsign/cert.pem
> >CAfile = /usr/unsign/cert.pem
> >verify = 2
> >ciphers =
>
> >AES128-SHA:AES256-SHA:DES-CBC3-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:EDH-RSA-DES-CBC3-SHA
> >sslVersion = all
> >TIMEOUTbusy = 100
> >TIMEOUTconnect = 100
> >client = yes
> >~/busybox $ /usr/postunnel/stunnel /home/posdebug/stunnel.cfg
> >~/busybox $ top | grep stunnel
> > 986 1 posdebug S *3592* 5.7 0 0.0 /usr/postunnel/stunnel
> >/home/posdebug/stunnel.cfg
> >~/busybox $ kill -1 986
> >~/busybox $ kill -1 986
> >~/busybox $ kill -1 986
> >~/busybox $ kill -1 986
> >~/busybox $ kill -1 986
> >~/busybox $ top | grep stunnel
> > 986 1 posdebug S *3720* 5.9 0 0.0 /usr/postunnel/stunnel
> >/home/posdebug/stunnel.cfg
> >~/busybox $ kill -1 986
> >~/busybox $ kill -1 986
> >~/busybox $ kill -1 986
> >~/busybox $ kill -1 986
> >~/busybox $ top | grep stunnel
> > 986 1 posdebug S *3848* 6.2 0 0.0 /usr/postunnel/stunnel
> >/home/posdebug/stunnel.cfg
> >
> >As i noticed, there are a lot of allocs on reconfiguration and only a
> >few
> >free() calls. Why? RAM is not unlimited, as far as i know.
> >Any comments would be highly appreciated.
>
> _______________________________________________
> stunnel-users mailing list
> [email protected]
> https://www.stunnel.org/cgi-bin/mailman/listinfo/stunnel-users
>
--
Best regards
Alexander Paramonov
Software Engineer
Terminal Technologies
--- src/ctx.c 2014-10-03 19:46:21.000000000 +0400
+++ src/ctx.c 2014-11-20 12:47:00.608199133 +0300
@@ -83,6 +83,16 @@
NOEXPORT void sslerror_queue(void);
NOEXPORT void sslerror_log(unsigned long, char *);
+/**************************************** free old ssl context */
+void context_free(SERVICE_OPTIONS *section) {
+ if (section->pkey)
+ EVP_PKEY_free(section->pkey);
+ if (section->ctx)
+ SSL_CTX_free(section->ctx);
+ if (section->revocation_store)
+ X509_STORE_free(section->revocation_store);
+}
+
/**************************************** initialize section->ctx */
int context_init(SERVICE_OPTIONS *section) { /* init SSL context */
@@ -465,9 +475,9 @@
/* ui_data.section=NULL; */
#endif /* USE_WIN32 */
for(i=1; i<=3; i++) {
- pkey=ENGINE_load_private_key(section->engine, section->key,
+ section->pkey=ENGINE_load_private_key(section->engine, section->key,
ui_method, &ui_data);
- if(!pkey) {
+ if(!section->pkey) {
reason=ERR_GET_REASON(ERR_peek_error());
if(i<=2 && (reason==7 || reason==160)) { /* wrong PIN */
sslerror_queue(); /* dump the error queue */
@@ -477,7 +487,7 @@
sslerror("ENGINE_load_private_key");
return 1; /* FAILED */
}
- if(SSL_CTX_use_PrivateKey(section->ctx, pkey))
+ if(SSL_CTX_use_PrivateKey(section->ctx, section->pkey))
break; /* success */
sslerror("SSL_CTX_use_PrivateKey");
return 1; /* FAILED */
--- src/prototypes.h 2014-10-30 09:19:38.000000000 +0300
+++ src/prototypes.h 2014-11-20 13:12:24.304120236 +0300
@@ -152,6 +152,7 @@
typedef struct service_options_struct {
struct service_options_struct *next; /* next node in the services list */
SSL_CTX *ctx; /* SSL context */
+ EVP_PKEY *pkey; /* private key */
char *servname; /* service name for logging & permission checking */
/* service-specific data for sthreads.c */
@@ -390,6 +391,7 @@
int options_cmdline(char *, char *);
int options_parse(CONF_TYPE);
+void options_init(void);
void options_defaults(void);
void options_apply(void);
@@ -401,6 +403,7 @@
} UI_DATA;
int context_init(SERVICE_OPTIONS *);
+void context_free(SERVICE_OPTIONS *);
void sslerror(char *);
/**************************************** prototypes for verify.c */
--- src/stunnel.c 2014-10-30 09:19:38.000000000 +0300
+++ src/stunnel.c 2014-11-20 13:24:55.116081358 +0300
@@ -110,6 +110,7 @@
fatal("SSL initialization failed");
if(sthreads_init()) /* initialize critical sections & SSL callbacks */
fatal("Threads initialization failed");
+ options_init();
options_defaults();
options_apply();
#ifndef USE_FORK
--- src/options.c 2014-11-01 16:47:18.000000000 +0300
+++ src/options.c 2014-11-20 11:51:07.867222923 +0300
@@ -372,18 +372,36 @@
return 0;
}
+void options_init() {
+ memset(&global_options, 0, sizeof(GLOBAL_OPTIONS)); /* reset global options */
+ memset(&service_options, 0, sizeof(SERVICE_OPTIONS)); /* reset local options */
+}
+
void options_defaults() {
/* initialize globals *before* opening the config file */
- memset(&new_global_options, 0, sizeof(GLOBAL_OPTIONS)); /* reset global options */
- memset(&new_service_options, 0, sizeof(SERVICE_OPTIONS)); /* reset local options */
+ memset(&new_global_options, 0, sizeof(GLOBAL_OPTIONS)); /* reset new global options */
+ memset(&new_service_options, 0, sizeof(SERVICE_OPTIONS)); /* reset new local options */
new_service_options.next=NULL;
parse_global_option(CMD_BEGIN, NULL, NULL);
parse_service_option(CMD_BEGIN, &new_service_options, NULL, NULL);
}
void options_apply() { /* apply default/validated configuration */
+ SERVICE_OPTIONS *tmp, *section;
+
+ parse_global_option(CMD_FREE, NULL, NULL);
+
/* FIXME: this operation may be unsafe, as client() threads use it */
memcpy(&global_options, &new_global_options, sizeof(GLOBAL_OPTIONS));
+
+ section=service_options.next;
+ while(section) {
+ parse_service_option(CMD_FREE, section, NULL, NULL);
+ tmp=section->next;
+ str_free(section);
+ section=tmp;
+ }
+
/* service_options are used for inetd mode and to enumerate services */
memcpy(&service_options, &new_service_options, sizeof(SERVICE_OPTIONS));
}
@@ -416,6 +436,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(global_options.chroot_dir);
break;
case CMD_DEFAULT:
break;
@@ -503,6 +524,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(global_options.egd_sock);
break;
case CMD_DEFAULT:
#ifdef EGD_SOCKET
@@ -761,6 +783,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(global_options.output_file);
break;
case CMD_DEFAULT:
break;
@@ -786,6 +809,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(global_options.pidfile);
break;
case CMD_DEFAULT:
break;
@@ -832,6 +856,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(global_options.rand_file);
break;
case CMD_DEFAULT:
#ifdef RANDOM_FILE
@@ -880,11 +905,13 @@
case CMD_EXEC:
if(strcasecmp(opt, "service"))
break;
+ str_free(new_service_options.servname);
new_service_options.servname=str_dup(arg);
return NULL; /* OK */
case CMD_END:
break;
case CMD_FREE:
+ str_free(service_options.servname);
break;
case CMD_DEFAULT:
break;
@@ -1106,6 +1133,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->ca_dir);
break;
case CMD_DEFAULT:
#if 0
@@ -1138,6 +1166,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->ca_file);
break;
case CMD_DEFAULT:
#if 0
@@ -1169,6 +1198,7 @@
return "SSL server needs a certificate";
break;
case CMD_FREE:
+ str_free(section->cert);
break;
case CMD_DEFAULT:
break; /* no default certificate */
@@ -1201,6 +1231,7 @@
break;
case CMD_FREE:
+ str_free(section->cipher_list);
break;
case CMD_DEFAULT:
#ifdef USE_FIPS
@@ -1273,6 +1304,10 @@
++endpoints;
break;
case CMD_FREE:
+ if(section->connect_list) {
+ str_free(section->connect_list->name); /* FIXME: works for single connect entry only */
+ str_free(section->connect_list);
+ }
break;
case CMD_DEFAULT:
break;
@@ -1298,6 +1333,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->crl_dir);
break;
case CMD_DEFAULT:
break;
@@ -1322,6 +1358,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->crl_file);
break;
case CMD_DEFAULT:
break;
@@ -1465,6 +1502,8 @@
++endpoints;
break;
case CMD_FREE:
+ str_free(section->execname);
+ str_free(section->execargs);
break;
case CMD_DEFAULT:
break;
@@ -1482,6 +1521,7 @@
case CMD_EXEC:
if(strcasecmp(opt, "execargs"))
break;
+ str_free(section->execargs);
#ifdef USE_WIN32
section->execargs=str_dup(arg);
#else
@@ -1540,6 +1580,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->username);
break;
case CMD_DEFAULT:
break;
@@ -1561,6 +1602,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->key);
break;
case CMD_DEFAULT:
break;
@@ -1726,6 +1768,7 @@
return tmpstr;
break;
case CMD_FREE:
+ str_free(section->protocol);
break;
case CMD_DEFAULT:
break;
@@ -1750,6 +1793,7 @@
case CMD_END:
break;
case CMD_FREE:
+ //str_free(section->protocol_authentication); /* FIXME: double free attempt? Why? */
break;
case CMD_DEFAULT:
break;
@@ -1772,6 +1816,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->protocol_host);
break;
case CMD_DEFAULT:
break;
@@ -1794,6 +1839,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->protocol_password);
break;
case CMD_DEFAULT:
break;
@@ -1816,6 +1862,7 @@
case CMD_END:
break;
case CMD_FREE:
+ str_free(section->protocol_username);
break;
case CMD_DEFAULT:
break;
@@ -1877,6 +1924,10 @@
}
break;
case CMD_FREE:
+ if(section->redirect_list) { /* FIXME: works for only one redirect entry */
+ str_free(section->redirect_list->name);
+ str_free(section->redirect_list);
+ }
break;
case CMD_DEFAULT:
break;
@@ -2061,6 +2112,7 @@
section->sni=str_dup(arg);
return NULL; /* OK */
case CMD_END:
+ str_free(section->sni);
tmpstr=init_sni(section);
if(tmpstr)
return tmpstr;
@@ -2068,6 +2120,7 @@
++endpoints;
break;
case CMD_FREE:
+ str_free(section->sni); /* FIXME: works for client mode only, see init_sni() implementation */
break;
case CMD_DEFAULT:
break;
@@ -2381,6 +2434,9 @@
return "Failed to initialize SSL context";
}
+ if(cmd==CMD_FREE)
+ context_free(section);
+
return NULL; /* OK */
}
@@ -2504,8 +2560,10 @@
break;
}
}
- if(new_global_options.facility==-1)
+ if(new_global_options.facility==-1) {
+ str_free(arg_copy);
return 1; /* FAILED */
+ }
string=strtok(NULL, "."); /* set to the remainder */
}
#endif /* USE_WIN32, __vms */
@@ -2513,6 +2571,7 @@
/* time to check the syslog level */
if(string && strlen(string)==1 && *string>='0' && *string<='7') {
new_global_options.debug_level=*string-'0';
+ str_free(arg_copy);
return 0; /* OK */
}
new_global_options.debug_level=8; /* illegal level */
@@ -2522,6 +2581,7 @@
break;
}
}
+ str_free(arg_copy);
if(new_global_options.debug_level==8)
return 1; /* FAILED */
return 0; /* OK */
_______________________________________________
stunnel-users mailing list
[email protected]
https://www.stunnel.org/cgi-bin/mailman/listinfo/stunnel-users