mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
tcp: fix limbo entry leaks from hell
In limbo() function, once tpriv->nlimbo reaches Maxlimbo, we'd try to re-use Limbo entries from the head of the hash chain. However, theres a special case where our current chain contains only a single entry. Then Limbo **l; points to its next pointer, and writing: *l = lp; would just yield in the entry being linked to itself, leaking it. The for(;;) loop in limborexmit() was wrong, as the "continue" case would not advance the lp pointer at all, (such as when tpriv->nlimbo reaches > 100), we'd stop cleaning out entries. Handle Fsnewcall() returning nil case, have to free Limbo *lp as we just removed it from the hash table. Add tpriv->nlimbo as "InLimbo" at the end of /net/tcp/stats.
This commit is contained in:
parent
b43c416083
commit
0298949dd2
1 changed files with 24 additions and 43 deletions
|
@ -1537,8 +1537,7 @@ limbo(Conv *s, uchar *source, uchar *dest, Tcp *seg, int version)
|
|||
tpriv = s->p->priv;
|
||||
h = hashipa(source, seg->source);
|
||||
|
||||
for(l = &tpriv->lht[h]; *l != nil; l = &lp->next){
|
||||
lp = *l;
|
||||
for(l = &tpriv->lht[h]; (lp = *l) != nil; l = &lp->next){
|
||||
if(lp->lport != seg->dest || lp->rport != seg->source || lp->version != version)
|
||||
continue;
|
||||
if(ipcmp(lp->raddr, source) != 0)
|
||||
|
@ -1550,19 +1549,16 @@ limbo(Conv *s, uchar *source, uchar *dest, Tcp *seg, int version)
|
|||
lp->irs = seg->seq;
|
||||
break;
|
||||
}
|
||||
lp = *l;
|
||||
if(lp == nil){
|
||||
if(tpriv->nlimbo >= Maxlimbo && tpriv->lht[h]){
|
||||
lp = tpriv->lht[h];
|
||||
tpriv->lht[h] = lp->next;
|
||||
lp->next = nil;
|
||||
if((lp = *l) == nil){
|
||||
if(tpriv->nlimbo >= Maxlimbo && (lp = tpriv->lht[h]) != nil){
|
||||
if((tpriv->lht[h] = lp->next) == nil)
|
||||
l = &tpriv->lht[h];
|
||||
} else {
|
||||
lp = malloc(sizeof(*lp));
|
||||
if(lp == nil)
|
||||
if((lp = malloc(sizeof(*lp))) == nil)
|
||||
return;
|
||||
tpriv->nlimbo++;
|
||||
}
|
||||
*l = lp;
|
||||
lp->next = nil;
|
||||
lp->version = version;
|
||||
ipmove(lp->laddr, dest);
|
||||
ipmove(lp->raddr, source);
|
||||
|
@ -1572,11 +1568,11 @@ limbo(Conv *s, uchar *source, uchar *dest, Tcp *seg, int version)
|
|||
lp->rcvscale = seg->ws;
|
||||
lp->irs = seg->seq;
|
||||
lp->iss = (nrand(1<<16)<<16)|nrand(1<<16);
|
||||
*l = lp;
|
||||
}
|
||||
|
||||
if(sndsynack(s->p, lp) < 0){
|
||||
*l = lp->next;
|
||||
tpriv->nlimbo--;
|
||||
*l = lp->next;
|
||||
free(lp);
|
||||
}
|
||||
}
|
||||
|
@ -1589,9 +1585,8 @@ limborexmit(Proto *tcp)
|
|||
{
|
||||
Tcppriv *tpriv;
|
||||
Limbo **l, *lp;
|
||||
int h;
|
||||
int seen;
|
||||
ulong now;
|
||||
int h;
|
||||
|
||||
tpriv = tcp->priv;
|
||||
|
||||
|
@ -1601,34 +1596,17 @@ limborexmit(Proto *tcp)
|
|||
qunlock(tcp);
|
||||
return;
|
||||
}
|
||||
seen = 0;
|
||||
now = NOW;
|
||||
for(h = 0; h < NLHT && seen < tpriv->nlimbo; h++){
|
||||
for(l = &tpriv->lht[h]; *l != nil && seen < tpriv->nlimbo; ){
|
||||
lp = *l;
|
||||
seen++;
|
||||
if(now - lp->lastsend < (lp->rexmits+1)*SYNACK_RXTIMER)
|
||||
continue;
|
||||
|
||||
/* time it out after 1 second */
|
||||
if(++(lp->rexmits) > 5){
|
||||
tpriv->nlimbo--;
|
||||
*l = lp->next;
|
||||
free(lp);
|
||||
continue;
|
||||
for(h = 0; h < NLHT; h++){
|
||||
for(l = &tpriv->lht[h]; (lp = *l) != nil; ){
|
||||
if(now - lp->lastsend >= (lp->rexmits+1)*SYNACK_RXTIMER){
|
||||
if(++(lp->rexmits) > 5 || sndsynack(tcp, lp) < 0){
|
||||
tpriv->nlimbo--;
|
||||
*l = lp->next;
|
||||
free(lp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we're being attacked, don't bother resending SYN ACK's */
|
||||
if(tpriv->nlimbo > 100)
|
||||
continue;
|
||||
|
||||
if(sndsynack(tcp, lp) < 0){
|
||||
*l = lp->next;
|
||||
tpriv->nlimbo--;
|
||||
free(lp);
|
||||
continue;
|
||||
}
|
||||
|
||||
l = &lp->next;
|
||||
}
|
||||
}
|
||||
|
@ -1645,8 +1623,8 @@ static void
|
|||
limborst(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
|
||||
{
|
||||
Limbo *lp, **l;
|
||||
int h;
|
||||
Tcppriv *tpriv;
|
||||
int h;
|
||||
|
||||
tpriv = s->p->priv;
|
||||
|
||||
|
@ -1737,8 +1715,10 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
|
|||
return nil;
|
||||
|
||||
new = Fsnewcall(s, src, segp->source, dst, segp->dest, version);
|
||||
if(new == nil)
|
||||
if(new == nil){
|
||||
free(lp);
|
||||
return nil;
|
||||
}
|
||||
|
||||
memmove(new->ptcl, s->ptcl, sizeof(Tcpctl));
|
||||
tcb = (Tcpctl*)new->ptcl;
|
||||
|
@ -3415,6 +3395,7 @@ tcpstats(Proto *tcp, char *buf, int len)
|
|||
e = p+len;
|
||||
for(i = 0; i < Nstats; i++)
|
||||
p = seprint(p, e, "%s: %llud\n", statnames[i], priv->stats[i]);
|
||||
p = seprint(p, e, "InLimbo: %d\n", priv->nlimbo);
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue