On Sat, Apr 25, 2026 at 10:53:04AM +0200, [email protected] wrote:
> On Sat, Apr 25, 2026 at 10:39:52AM +0200, Willy Tarreau wrote:
> > Subject: Re: [PATCH] BUG/MINOR: ssl_ckch: fix memory leak on realloc failure
> > On Sat, Apr 25, 2026 at 07:14:47AM +0000, Egor Shestakov wrote:
> > > Hi Bianca!
> > > 
> > > On Fri, Apr 24, 2026 at 11:04:03PM +0000, Bianca Dogareci wrote:
> > > > Please find attached a patch fixing a memory leak when realloc() fails
> > > > in ssl_ckch.c.
> > > 
> > > > Fix three instances of the classic realloc() bug in ckchs_dup() and
> > > > ckch_conf_parse() where overwriting the original pointer with NULL
> > > > on allocation failure loses reference to the original memory block.
> > > > 
> > > > Use temporary pointers to check realloc() result before updating
> > > > the original pointer. This prevents memory leaks when realloc()
> > > > fails.
> > > 
> > > You're right about this, thanks!
> > > 
> > > HAProxy has a my_realloc2() function that does the same thing but also
> > > frees the original pointer on failure, to make the handling of failures of
> > > realloc() simpler.
> > > 
> > > Could please adjust your patch for my_realloc2?
> > 
> > Indeed. There's a Coccinelle test to find them:
> > 
> >     dev/coccinelle/realloc_leak.cocci
> > 
> > There are a few other instances of this issue. Most of them end up with an
> > exit() so they are technically false positives but a few are real leaks
> > (e.g. in Lua):
> > 
> > hlua_load_per_thread() (this one will exit):
> > src/hlua.c:13512:       per_thread_load = realloc(per_thread_load, (len + 
> > 2) * sizeof(*per_thread_load));
> > src/hlua.c-13513-       if (per_thread_load == NULL) {
> > src/hlua.c-13514-               memprintf(err, "out of memory error");
> > src/hlua.c-13515-               return -1;
> > src/hlua.c-13516-       }
> > 
> > hlua_alloc() (these ones are real leaks):
> > src/hlua.c:14158:                       ptr = realloc(ptr, nsize);
> > src/hlua.c-14159-               return ptr;
> > src/hlua.c-14160-       }
> > 
> > src/hlua.c:14177:               ptr = realloc(ptr, nsize);
> > src/hlua.c-14178-
> > src/hlua.c-14179-       if (unlikely(!ptr && nsize)) // failed
> > src/hlua.c-14180-               _HA_ATOMIC_SUB(&zone->allocated, nsize - 
> > osize);
> > 
> > qc_try_store_new_token() (real leak):
> > src/quic_rx.c:819:              stok_ptr = realloc(stok_ptr, len);
> > src/quic_rx.c-820-              if (stok_ptr)
> > src/quic_rx.c-821-                      
> > s->per_thr[tid].quic_retry_token.ptr = stok_ptr;
> > src/quic_rx.c-822-              else {
> > src/quic_rx.c-823-                      memset(istptr(*stok), 0, 
> > istlen(*stok));
> > src/quic_rx.c-824-                      istfree(stok);
> > 
> > ckchs_dup() (real leaks):
> > src/ssl_ckch.c:1101:                    r = realloc(r, sizeof(char *) * (n 
> > + 2));
> > src/ssl_ckch.c-1102-                    if (!r)
> > src/ssl_ckch.c-1103-                            goto error;
> > 
> > src/ssl_ckch.c:1122:                    r = realloc(r, sizeof(char *) * (n 
> > + 2));
> > src/ssl_ckch.c-1123-                    if (!r)
> > src/ssl_ckch.c-1124-                            goto error;
> > src/ssl_ckch.c-1125-
> > 
> > ckch_conf_parse() (real leak):
> > src/ssl_ckch.c:5200:                                    r = realloc(r, 
> > sizeof(char *) * (n + 2));
> > src/ssl_ckch.c-5201-                                    if (!r) {
> > src/ssl_ckch.c-5202-                                            
> > ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
> > src/ssl_ckch.c-5203-                                            err_code |= 
> > ERR_ALERT | ERR_ABORT;
> > src/ssl_ckch.c-5204-                                            goto 
> > array_err;
> > src/ssl_ckch.c-5205-                                    }
> > 
> > ssl_sock_resize_passphrase_cache() : real leaks
> > src/ssl_sock.c:3746:    passphrase_randoms = realloc(passphrase_randoms, 
> > sizeof(*passphrase_randoms) * (new_size));
> > src/ssl_sock.c-3747-    if (!passphrase_randoms) {
> > src/ssl_sock.c-3748-            ha_alert("ssl_sock_passwd_cb: passphrase 
> > randoms realloc failed");
> > src/ssl_sock.c-3749-            passphrase_idx = -1;
> > src/ssl_sock.c-3750-            passphrase_cache_size = 0;
> > src/ssl_sock.c-3751-    }
> > 
> > src/ssl_sock.c:3762:            passphrase_cache = 
> > realloc(passphrase_cache, sizeof(*passphrase_cache) * 
> > passphrase_cache_size);
> > src/ssl_sock.c-3763-            if (!passphrase_cache) {
> > src/ssl_sock.c-3764-                    ha_alert("ssl_sock_passwd_cb: 
> > passphrase cache realloc failed");
> > src/ssl_sock.c-3765-                    passphrase_idx = -1;
> > src/ssl_sock.c-3766-                    passphrase_cache_size = 0;
> > src/ssl_sock.c-3767-            }
> > 
> > ssl_sess_new_srv_cb(): real leak and even looks worse since it doesn't
> >                        reset the allocated size after the NULL pointer:
> > src/ssl_sock.c:4254:                    ptr = realloc(ptr, len);
> > src/ssl_sock.c-4255-                    if (!ptr)
> > src/ssl_sock.c-4256-                            
> > free(s->ssl_ctx.reused_sess[tid].ptr);
> > src/ssl_sock.c-4257-                    s->ssl_ctx.reused_sess[tid].ptr = 
> > ptr;
> > src/ssl_sock.c-4258-                    
> > s->ssl_ctx.reused_sess[tid].allocated_size = len;
> > 
> > It's important to fix them in separate patches (at least one per function)
> > because it's very likely that several of them will need to be backported.
> > 
> > Willy
> > 
> 
> Ilya provided some fixes for some of them some weeks ago,

ah, sorry for missing them.

> I thought we took them but the ckchs_dup() and
> ssl_sock_resize_passphrase_cache() are addressed there. I'm going to merge
> them.

OK thanks!

willy


Reply via email to