summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormaxim <maxim@FreeBSD.org>2003-03-27 14:56:36 +0000
committermaxim <maxim@FreeBSD.org>2003-03-27 14:56:36 +0000
commit291fa269633b0a81036a3fc3ca80487f5835a320 (patch)
tree17e99cebc765c447b120002b2ebccc2bc7a9f4f6
parent2d56ed957aaef6ee5d66bcc7c86d7832b4658de5 (diff)
downloadFreeBSD-src-291fa269633b0a81036a3fc3ca80487f5835a320.zip
FreeBSD-src-291fa269633b0a81036a3fc3ca80487f5835a320.tar.gz
o Protect set_fs_param() by splimp(9).
Quote from kern/37573: There is an obvious race in netinet/ip_dummynet.c:config_pipe(). Interrupts are not blocked when changing the params of an existing pipe. The specific crash observed: ... -> config_pipe -> set_fs_parms -> config_red malloc a new w_q_lookup table but take an interrupt before intializing it, interrupt handler does: ... -> dummynet_io -> red_drops red_drops dereferences the uninitialized (zeroed) w_q_lookup table. o Flush accumulated credits for idle pipes. o Flush accumulated credits when change pipe characteristics. o Change dn_flow_queue.numbytes type to unsigned long. Overlapping dn_flow_queue->numbytes in ready_event() leads to numbytes becomes negative and SET_TICKS() macro returns a very big value. heap_insert() overlaps dn_key again and inserts a queue to a ready heap with a sched_time points to the past. That leads to an "infinity" loop. PR: kern/33234, kern/37573, misc/42459, kern/43133, kern/44045, kern/48099 Submitted by: Mike Hibler <mike@cs.utah.edu> (kern/37573) MFC after: 6 weeks
-rw-r--r--sys/netinet/ip_dummynet.c24
-rw-r--r--sys/netinet/ip_dummynet.h2
2 files changed, 18 insertions, 8 deletions
diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c
index 82b6f7b..63643fd 100644
--- a/sys/netinet/ip_dummynet.c
+++ b/sys/netinet/ip_dummynet.c
@@ -565,8 +565,10 @@ ready_event(struct dn_flow_queue *q)
/* XXX should check errors on heap_insert, and drain the whole
* queue on error hoping next time we are luckier.
*/
- } else /* RED needs to know when the queue becomes empty */
+ } else { /* RED needs to know when the queue becomes empty */
q->q_time = curr_time;
+ q->numbytes = 0;
+ }
/*
* If the delay line was empty call transmit_event(p) now.
* Otherwise, the scheduler will take care of it.
@@ -1509,8 +1511,9 @@ set_fs_parms(struct dn_flow_set *x, struct dn_flow_set *src)
static int
config_pipe(struct dn_pipe *p)
{
- int s ;
+ int i, s;
struct dn_flow_set *pfs = &(p->fs);
+ struct dn_flow_queue *q;
/*
* The config program passes parameters as follows:
@@ -1542,9 +1545,17 @@ config_pipe(struct dn_pipe *p)
*/
x->idle_heap.size = x->idle_heap.elements = 0 ;
x->idle_heap.offset=OFFSET_OF(struct dn_flow_queue, heap_pos);
- } else
+ } else {
x = b;
+ s = splimp();
+ /* Flush accumulated credit for all queues */
+ for (i = 0; i <= x->fs.rq_size; i++)
+ for (q = x->fs.rq[i]; q; q = q->next)
+ q->numbytes = 0;
+ splx(s);
+ }
+ s = splimp();
x->bandwidth = p->bandwidth ;
x->numbytes = 0; /* just in case... */
bcopy(p->if_name, x->if_name, sizeof(p->if_name) );
@@ -1559,14 +1570,13 @@ config_pipe(struct dn_pipe *p)
free(x, M_DUMMYNET);
return s ;
}
- s = splimp() ;
x->next = b ;
if (a == NULL)
all_pipes = x ;
else
a->next = x ;
- splx(s);
}
+ splx(s);
} else { /* config queue */
struct dn_flow_set *x, *a, *b ;
@@ -1595,6 +1605,7 @@ config_pipe(struct dn_pipe *p)
return EINVAL ;
x = b;
}
+ s = splimp();
set_fs_parms(x, pfs);
if ( x->rq == NULL ) { /* a new flow_set */
@@ -1603,14 +1614,13 @@ config_pipe(struct dn_pipe *p)
free(x, M_DUMMYNET);
return s ;
}
- s = splimp() ;
x->next = b;
if (a == NULL)
all_flow_sets = x;
else
a->next = x;
- splx(s);
}
+ splx(s);
}
return 0 ;
}
diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h
index 588461e..626d698 100644
--- a/sys/netinet/ip_dummynet.h
+++ b/sys/netinet/ip_dummynet.h
@@ -218,7 +218,7 @@ struct dn_flow_queue {
struct dn_pkt *head, *tail ; /* queue of packets */
u_int len ;
u_int len_bytes ;
- long numbytes ; /* credit for transmission (dynamic queues) */
+ u_long numbytes ; /* credit for transmission (dynamic queues) */
u_int64_t tot_pkts ; /* statistics counters */
u_int64_t tot_bytes ;
OpenPOWER on IntegriCloud