ref: 4d211fdd4801bd6db06ae2c0a72b47de55f3194c
parent: 5639d1e5fc46c5f236cff7168a5800367368a6ec
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Mar 10 14:16:08 EDT 2015
kernel: fix integer overflow in syssegflush(), segment code cleanup mcountseg(), mfreeseg(): use Pte.first/last pointers when possible and avoid constructs like s->map[i]->pages[j]. freepte(): do not zero entries in freepte(), the segment is going away and here is no point in zeroing page pointers. hoist common code at the top avoiding duplication. segpage(), fixfault(): avoid load after store for Pte** pointer. fixfault(): return -1 in default case to avoid the "used but not set" warning for mmuphys and get rid of the useless initialization. syssegflush(): due to len being unsigned, the pe = PGROUND(pe) can make "chunk" bigger than len causing a overflow. rewrite the function and deal with page alignment and errors at the beginning. syssegflush(), segpage(), fixfault(), putseg(), relocateseg(), mcountseg(), mfreeseg(): keep naming consistent.
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -197,17 +197,16 @@
fixfault(Segment *s, uintptr addr, int read, int doputmmu)
{
int type;
- Pte **p, *etp;
- uintptr soff, mmuphys=0;
+ Pte **pte, *etp;
+ uintptr soff, mmuphys;
Page **pg, *old, *new;
addr &= ~(BY2PG-1);
soff = addr-s->base;
- p = &s->map[soff/PTEMAPMEM];
- if(*p == nil)
- *p = ptealloc();
+ pte = &s->map[soff/PTEMAPMEM];
+ if((etp = *pte) == nil)
+ *pte = etp = ptealloc();
- etp = *p;
pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
type = s->type&SG_TYPE;
@@ -219,7 +218,7 @@
switch(type) {
default:
panic("fault");
- break;
+ return -1;
case SG_TEXT: /* Demand load */
if(pagedout(*pg))
--- a/sys/src/9/port/page.c
+++ b/sys/src/9/port/page.c
@@ -148,7 +148,6 @@
KMap *k;
int color;
- color = getpgcolor(va);
lock(&palloc);
for(;;) {
if(palloc.freecount > swapalloc.highwater)
@@ -188,6 +187,7 @@
}
/* First try for our colour */
+ color = getpgcolor(va);
l = &palloc.head;
for(p = *l; p != nil; p = p->next){
if(p->color == color)
@@ -384,24 +384,24 @@
void
freepte(Segment *s, Pte *p)
{
- Page **pg;
+ Page **pg, **pe;
+ pg = p->first;
+ pe = p->last;
+
switch(s->type&SG_TYPE) {
case SG_PHYSICAL:
- for(pg = p->first; pg <= p->last; pg++) {
- if(*pg != nil) {
- if(decref(*pg) == 0)
- free(*pg);
- *pg = nil;
- }
+ while(pg <= pe){
+ if(*pg != nil && decref(*pg) == 0)
+ free(*pg);
+ pg++;
}
break;
default:
- for(pg = p->first; pg <= p->last; pg++) {
- if(*pg != nil) {
+ while(pg <= pe){
+ if(*pg != nil)
putpage(*pg);
- *pg = nil;
- }
+ pg++;
}
}
free(p);
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -86,7 +86,7 @@
void
putseg(Segment *s)
{
- Pte **pp, **emap;
+ Pte **pte, **emap;
Image *i;
if(s == nil)
@@ -107,9 +107,9 @@
return;
emap = &s->map[s->mapsize];
- for(pp = s->map; pp < emap; pp++)
- if(*pp != nil)
- freepte(s, *pp);
+ for(pte = s->map; pte < emap; pte++)
+ if(*pte != nil)
+ freepte(s, *pte);
if(s->map != s->ssegmap)
free(s->map);
@@ -122,16 +122,17 @@
void
relocateseg(Segment *s, uintptr offset)
{
- Page **pg, *x;
- Pte *pte, **p, **endpte;
+ Pte **pte, **emap;
+ Page **pg, **pe;
- endpte = &s->map[s->mapsize];
- for(p = s->map; p < endpte; p++) {
- if((pte = *p) == nil)
+ emap = &s->map[s->mapsize];
+ for(pte = s->map; pte < emap; pte++) {
+ if(*pte == nil)
continue;
- for(pg = pte->first; pg <= pte->last; pg++) {
- if((x = *pg) != nil)
- x->va += offset;
+ pe = (*pte)->last;
+ for(pg = (*pte)->first; pg <= pe; pg++) {
+ if(!pagedout(*pg))
+ (*pg)->va += offset;
}
}
}
@@ -207,24 +208,24 @@
void
segpage(Segment *s, Page *p)
{
- Pte **pte;
- uintptr off;
+ Pte **pte, *etp;
+ uintptr soff;
Page **pg;
if(p->va < s->base || p->va >= s->top)
panic("segpage");
- off = p->va - s->base;
- pte = &s->map[off/PTEMAPMEM];
- if(*pte == nil)
- *pte = ptealloc();
+ soff = p->va - s->base;
+ pte = &s->map[soff/PTEMAPMEM];
+ if((etp = *pte) == nil)
+ *pte = etp = ptealloc();
- pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
+ pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
*pg = p;
- if(pg < (*pte)->first)
- (*pte)->first = pg;
- if(pg > (*pte)->last)
- (*pte)->last = pg;
+ if(pg < etp->first)
+ etp->first = pg;
+ if(pg > etp->last)
+ etp->last = pg;
}
Image*
@@ -455,22 +456,22 @@
ulong
mcountseg(Segment *s)
{
+ Pte **pte, **emap;
+ Page **pg, **pe;
ulong pages;
- int i, j;
- Page *pg;
if((s->type&SG_TYPE) == SG_PHYSICAL)
return 0;
pages = 0;
- for(i = 0; i < s->mapsize; i++){
- if(s->map[i] == nil)
+ emap = &s->map[s->mapsize];
+ for(pte = s->map; pte < emap; pte++){
+ if(*pte == nil)
continue;
- for(j = 0; j < PTEPERTAB; j++){
- pg = s->map[i]->pages[j];
- if(!pagedout(pg))
+ pe = (*pte)->last;
+ for(pg = (*pte)->first; pg <= pe; pg++)
+ if(!pagedout(*pg))
pages++;
- }
}
return pages;
}
@@ -481,9 +482,9 @@
void
mfreeseg(Segment *s, uintptr start, ulong pages)
{
- int i, j, size;
- uintptr soff;
- Page *pg;
+ uintptr off;
+ Pte **pte, **emap;
+ Page **pg, **pe;
if(pages == 0)
return;
@@ -492,34 +493,31 @@
return;
/*
- * We want to zero s->map[i]->page[j] and putpage(pg),
- * but we have to make sure other processors flush the
+ * we have to make sure other processors flush the
* entry from their TLBs before the page is freed.
*/
if(s->ref > 1)
procflushseg(s);
- soff = start-s->base;
- j = (soff&(PTEMAPMEM-1))/BY2PG;
-
- size = s->mapsize;
- for(i = soff/PTEMAPMEM; i < size; i++, j = 0) {
- if(s->map[i] == nil) {
- j = PTEPERTAB - j;
- if(j >= pages)
+ off = start-s->base;
+ pte = &s->map[off/PTEMAPMEM];
+ off = (off&(PTEMAPMEM-1))/BY2PG;
+ for(emap = &s->map[s->mapsize]; pte < emap; pte++, off = 0) {
+ if(*pte == nil) {
+ off = PTEPERTAB - off;
+ if(off >= pages)
return;
- pages -= j;
+ pages -= off;
continue;
}
- while(j < PTEPERTAB) {
- pg = s->map[i]->pages[j];
- if(pg != nil){
- s->map[i]->pages[j] = nil;
- putpage(pg);
+ pg = &(*pte)->pages[off];
+ for(pe = &(*pte)->pages[PTEPERTAB]; pg < pe; pg++) {
+ if(*pg != nil){
+ putpage(*pg);
+ *pg = nil;
}
if(--pages == 0)
return;
- j++;
}
}
}
@@ -668,62 +666,49 @@
return va;
}
-void
-pteflush(Pte *pte, int s, int e)
-{
- Page *pg;
- int i;
-
- for(i = s; i < e; i++) {
- pg = pte->pages[i];
- if(!pagedout(pg))
- pg->txtflush = ~0;
- }
-}
-
uintptr
syssegflush(va_list list)
{
+ uintptr from, to, off, len;
Segment *s;
- ulong len, chunk, l;
Pte *pte;
- uintptr ps, pe, addr;
+ Page **pg, **pe;
- addr = va_arg(list, uintptr);
- len = va_arg(list, ulong);
+ from = va_arg(list, uintptr);
+ to = va_arg(list, ulong);
+ to += from;
- while(len > 0) {
- s = seg(up, addr, 1);
- if(s == 0)
+ to = PGROUND(to);
+ from &= ~(BY2PG-1);
+ if(to < from)
+ error(Ebadarg);
+
+ while(from < to) {
+ s = seg(up, from, 1);
+ if(s == nil)
error(Ebadarg);
s->flushme = 1;
more:
- l = len;
- if(addr+l > s->top)
- l = s->top - addr;
+ len = (s->top < to ? s->top : to) - from;
+ off = from-s->base;
+ pte = s->map[off/PTEMAPMEM];
+ off &= PTEMAPMEM-1;
+ if(off+len > PTEMAPMEM)
+ len = PTEMAPMEM-off;
- ps = addr-s->base;
- pte = s->map[ps/PTEMAPMEM];
- ps &= PTEMAPMEM-1;
- pe = PTEMAPMEM;
- if(pe-ps > l){
- pe = ps + l;
- pe = PGROUND(pe);
+ if(pte != nil) {
+ pg = &pte->pages[off/BY2PG];
+ pe = pg + len/BY2PG;
+ while(pg < pe) {
+ if(!pagedout(*pg))
+ (*pg)->txtflush = ~0;
+ pg++;
+ }
}
- if(pe == ps) {
- qunlock(s);
- error(Ebadarg);
- }
- if(pte)
- pteflush(pte, ps/BY2PG, pe/BY2PG);
-
- chunk = pe-ps;
- len -= chunk;
- addr += chunk;
-
- if(len > 0 && addr < s->top)
+ from += len;
+ if(from < to && from < s->top)
goto more;
qunlock(s);