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

Reply via email to