mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-16 00:25:48 +08:00
Fix memory leaks found under AddressSanitizer
- readconfig() kept its line buffer and argument array on every error
return, so each refused reload leaked them.
- A filter refusing a connection in filter_client (TLS: a failed
handshake) was not kept, so its filter_clear never ran and the state
it made was lost. makefilters() now clears it, and empties the slot
first: a pooled worker's slot may hold the previous connection's.
- ssl_filter_close() freed the client CA paths but not the server ones,
for every TLS service set up.
- Compiled patterns were never freed: an ACL's (pcre: and regex: host
names), an httpsrv rule's. copyacl() shared them between the
configuration's ACL and each service's copy; each copy now compiles
its own, and freeacl() and freehttprules() free them.
What LeakSanitizer still reports is OpenSSL's per-thread random
generator state of pooled threads, released only by OpenSSL at exit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 796e9f8156)
This commit is contained in:
parent
9651848bf1
commit
292a855f34
17
src/conf.c
17
src/conf.c
@ -2294,6 +2294,7 @@ int readconfig(FILE * fp){
|
||||
|
||||
if( !(buf = malloc(bufsize)) || ! (argv = malloc((NPARAMS + 1) * sizeof(unsigned char *))) ) {
|
||||
fprintf(stderr, "No memory for configuration");
|
||||
if(buf) free(buf);
|
||||
return(10);
|
||||
}
|
||||
for (linenum = 1; fgets((char *)buf, STRINGBUF, fp); linenum++){
|
||||
@ -2303,7 +2304,8 @@ int readconfig(FILE * fp){
|
||||
argc = parsestr (buf, argv, NPARAMS-1, &buf, &inbuf, &bufsize);
|
||||
if(argc < 1) {
|
||||
fprintf(stderr, "Parse error line %d\n", linenum);
|
||||
return(11);
|
||||
res = 11;
|
||||
goto DONE;
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
if(!strcmp((char *)argv[0], "end") && argc == 1) {
|
||||
@ -2315,23 +2317,28 @@ int readconfig(FILE * fp){
|
||||
if(!strcmp((char *)argv[0], (char *)cm->command)){
|
||||
if(argc < cm->minargs || (cm->maxargs && argc > cm->maxargs)){
|
||||
fprintf(stderr, "Command: '%s' wrong number of arguments , line %d\n", argv[0], linenum);
|
||||
return(linenum);
|
||||
res = linenum;
|
||||
goto DONE;
|
||||
}
|
||||
res = (*cm->handler)(argc, argv);
|
||||
if(res > 0){
|
||||
fprintf(stderr, "Command: '%s' failed with code %d, line %d\n", argv[0], res, linenum);
|
||||
return(linenum);
|
||||
res = linenum;
|
||||
goto DONE;
|
||||
}
|
||||
if(!res) break;
|
||||
}
|
||||
}
|
||||
if(res != 1)continue;
|
||||
fprintf(stderr, "Unknown command: '%s' line %d\n", argv[0], linenum);
|
||||
return(linenum);
|
||||
res = linenum;
|
||||
goto DONE;
|
||||
}
|
||||
res = 0;
|
||||
DONE:
|
||||
free(buf);
|
||||
free(argv);
|
||||
return 0;
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1124,6 +1124,10 @@ void freehttprules(struct httprule *rule)
|
||||
next = rule->next;
|
||||
if(rule->host.name) free(rule->host.name);
|
||||
if(rule->url.name) free(rule->url.name);
|
||||
#ifdef WITH_PCRE
|
||||
if(rule->host.re) pcre_pattern_free(rule->host.re);
|
||||
if(rule->url.re) pcre_pattern_free(rule->url.re);
|
||||
#endif
|
||||
if(rule->params) free(rule->params);
|
||||
if(rule->ctype) free(rule->ctype);
|
||||
if(rule->hdrs) free(rule->hdrs);
|
||||
|
||||
@ -1745,6 +1745,21 @@ struct ace * copyacl (struct ace *ac){
|
||||
if(hst->name) {
|
||||
hst->name = (unsigned char*)strdup((char *)hst->name);
|
||||
if(!hst->name) {
|
||||
hst->re = NULL;
|
||||
hst->next = NULL;
|
||||
goto ERRORDSTNAMES;
|
||||
}
|
||||
}
|
||||
/* each copy compiles its own pattern, freed with it */
|
||||
if(hst->re){
|
||||
#ifdef WITH_PCRE
|
||||
char err[256];
|
||||
|
||||
hst->re = pcre_pattern_compile(hst->name, err, sizeof(err));
|
||||
#else
|
||||
hst->re = NULL;
|
||||
#endif
|
||||
if(!hst->re) {
|
||||
hst->next = NULL;
|
||||
goto ERRORDSTNAMES;
|
||||
}
|
||||
@ -1868,9 +1883,17 @@ FILTER_ACTION makefilters (struct srvparam *srv, struct clientparam *param){
|
||||
|
||||
for(i=0; i<srv->nfilters; i++){
|
||||
if(!srv->filter[i].filter_client)continue;
|
||||
/* the slot may hold what the connection before left in it */
|
||||
param->filters[param->nfilters].data = NULL;
|
||||
action = (*srv->filter[i].filter_client)(srv->filter[i].data, param, ¶m->filters[param->nfilters].data);
|
||||
if(action == PASS) continue;
|
||||
if(action > CONTINUE) return action;
|
||||
if(action > CONTINUE) {
|
||||
/* a filter refusing the connection is not kept, but it may
|
||||
have made a state for it */
|
||||
if(srv->filter[i].filter_clear && param->filters[param->nfilters].data)
|
||||
(*srv->filter[i].filter_clear)(param->filters[param->nfilters].data);
|
||||
return action;
|
||||
}
|
||||
param->filters[param->nfilters].filter = srv->filter + i;
|
||||
if(srv->filter[i].filter_request)param->reqfilters[param->nreqfilters++] = param->filters + param->nfilters;
|
||||
if(srv->filter[i].filter_connect)param->connectfilters[param->nconnectfilters++] = param->filters + param->nfilters;
|
||||
@ -1911,6 +1934,9 @@ void freeacl(struct ace *ac){
|
||||
}
|
||||
for(hst = ac->dstnames; hst; hst = (struct hostname *)itfree(hst, hst->next)){
|
||||
if(hst->name)free(hst->name);
|
||||
#ifdef WITH_PCRE
|
||||
if(hst->re)pcre_pattern_free(hst->re);
|
||||
#endif
|
||||
}
|
||||
for(ch = ac->chains; ch; ch = (struct chain *) itfree(ch, ch->next)){
|
||||
if(ch->extuser) free(ch->extuser);
|
||||
|
||||
@ -867,6 +867,9 @@ static void ssl_filter_close(void *fo){
|
||||
free(CONFIG->client_ca_file);
|
||||
free(CONFIG->client_ca_dir);
|
||||
free(CONFIG->client_ca_store);
|
||||
free(CONFIG->server_ca_file);
|
||||
free(CONFIG->server_ca_dir);
|
||||
free(CONFIG->server_ca_store);
|
||||
free(CONFIG->client_sni);
|
||||
if(CONFIG->client_alpn_protos.protos_len){
|
||||
free(CONFIG->client_alpn_protos.protos);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user