mirror of
https://github.com/3proxy/3proxy.git
synced 2026-11-05 01:15:48 +08:00
pcre: a match data of the connection's own, not of the rule's
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
Every connection matching a pcre rule matched on the one match data block of the rule, which pcre2_match() writes into: two connections matching at the same time wrote the same block, a race that corrupts memory and brings the process down after a while under load. A connection that passes the rule's ACL now makes a match data block of its own when it starts and frees it when it ends; the match context is kept, as it is only read while matching.
This commit is contained in:
parent
629a978c00
commit
14e87dbd78
47
src/pcre.c
47
src/pcre.c
@ -220,6 +220,14 @@ struct pcre_filter_data {
|
|||||||
struct ace *acl;
|
struct ace *acl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* What a connection matches with: pcre2_match() writes into its match
|
||||||
|
data, so a thread matching on the rule's own one would race every
|
||||||
|
other thread doing the same. */
|
||||||
|
struct pcre_client_data {
|
||||||
|
struct pcre_filter_data *pcrefd;
|
||||||
|
pcre2_match_data * match_data;
|
||||||
|
};
|
||||||
|
|
||||||
static void pcre_data_free(struct pcre_filter_data *pcrefd){
|
static void pcre_data_free(struct pcre_filter_data *pcrefd){
|
||||||
_3proxy_mutex_lock(&pcre_mutex);
|
_3proxy_mutex_lock(&pcre_mutex);
|
||||||
pcrefd->users--;
|
pcrefd->users--;
|
||||||
@ -253,16 +261,30 @@ static void* pcre_filter_open(void * idata, struct srvparam * param){
|
|||||||
static FILTER_ACTION pcre_filter_client(void *fo, struct clientparam * param, void** fc){
|
static FILTER_ACTION pcre_filter_client(void *fo, struct clientparam * param, void** fc){
|
||||||
int res;
|
int res;
|
||||||
struct ace tmpace;
|
struct ace tmpace;
|
||||||
|
struct pcre_filter_data *rule = (struct pcre_filter_data *)fo;
|
||||||
|
struct pcre_client_data *pcd;
|
||||||
|
|
||||||
*fc = fo;
|
*fc = fo;
|
||||||
if(!fo) return PASS;
|
if(!fo) return PASS;
|
||||||
#define pcrefd ((struct pcre_filter_data *)fo)
|
if(!rule->acl) return CONTINUE;
|
||||||
if(!pcrefd->acl) return CONTINUE;
|
|
||||||
memset (&tmpace, 0, sizeof(struct ace));
|
memset (&tmpace, 0, sizeof(struct ace));
|
||||||
tmpace.src = pcrefd->acl->src;
|
tmpace.src = rule->acl->src;
|
||||||
res = pl->ACLMatches(&tmpace, param);
|
res = pl->ACLMatches(&tmpace, param);
|
||||||
#undef pcrefd
|
if(!res) return PASS;
|
||||||
return (res)? CONTINUE:PASS;
|
/* the connection goes on with a match data of its own */
|
||||||
|
if(!(pcd = pl->mallocfunc(sizeof(struct pcre_client_data)))){
|
||||||
|
*fc = NULL;
|
||||||
|
return rule->action;
|
||||||
|
}
|
||||||
|
pcd->pcrefd = rule;
|
||||||
|
pcd->match_data = NULL;
|
||||||
|
if(rule->re && !(pcd->match_data = pcre2_match_data_create_from_pattern(rule->re, NULL))){
|
||||||
|
pl->freefunc(pcd);
|
||||||
|
*fc = NULL;
|
||||||
|
return rule->action;
|
||||||
|
}
|
||||||
|
*fc = pcd;
|
||||||
|
return CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* What a rewritten buffer keeps free for its caller to append to. */
|
/* What a rewritten buffer keeps free for its caller to append to. */
|
||||||
@ -277,7 +299,8 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
|||||||
char * replace;
|
char * replace;
|
||||||
char * tmpbuf, *target, *newbuf;
|
char * tmpbuf, *target, *newbuf;
|
||||||
int nreplaces=0;
|
int nreplaces=0;
|
||||||
#define pcrefd ((struct pcre_filter_data *)fc)
|
struct pcre_client_data *pcd = (struct pcre_client_data *)fc;
|
||||||
|
#define pcrefd (pcd->pcrefd)
|
||||||
|
|
||||||
for(acl = pcrefd->acl; acl; acl=acl->next){
|
for(acl = pcrefd->acl; acl; acl=acl->next){
|
||||||
if(pl->ACLMatches(acl, param)){
|
if(pl->ACLMatches(acl, param)){
|
||||||
@ -290,9 +313,9 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
|||||||
for(; offset < *length_p; nreplaces++){
|
for(; offset < *length_p; nreplaces++){
|
||||||
int repsz;
|
int repsz;
|
||||||
|
|
||||||
count = pcre2_match(pcrefd->re, (PCRE2_SPTR)*buf_p, *length_p, offset, 0, pcrefd->match_data, pcrefd->match_context);
|
count = pcre2_match(pcrefd->re, (PCRE2_SPTR)*buf_p, *length_p, offset, 0, pcd->match_data, pcrefd->match_context);
|
||||||
if(count <= 0) break;
|
if(count <= 0) break;
|
||||||
ovector = pcre2_get_ovector_pointer(pcrefd->match_data);
|
ovector = pcre2_get_ovector_pointer(pcd->match_data);
|
||||||
if(ovector[0] > (PCRE2_SIZE)*length_p || ovector[1] > (PCRE2_SIZE)*length_p || ovector[1] < ovector[0]) break;
|
if(ovector[0] > (PCRE2_SIZE)*length_p || ovector[1] > (PCRE2_SIZE)*length_p || ovector[1] < ovector[0]) break;
|
||||||
if(!(replace = pcrefd->replace) || param->nooverwritefilter) return pcrefd->action;
|
if(!(replace = pcrefd->replace) || param->nooverwritefilter) return pcrefd->action;
|
||||||
|
|
||||||
@ -376,7 +399,13 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
|||||||
#undef pcrefd
|
#undef pcrefd
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pcre_filter_clear(void *fo){
|
static void pcre_filter_clear(void *fc){
|
||||||
|
struct pcre_client_data *pcd = (struct pcre_client_data *)fc;
|
||||||
|
|
||||||
|
if(pcd){
|
||||||
|
if(pcd->match_data) pcre2_match_data_free(pcd->match_data);
|
||||||
|
pl->freefunc(pcd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pcre_filter_close(void *fo){
|
static void pcre_filter_close(void *fo){
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user