Blob
- Date:
- Message:
- libdraw: replace hand-rolled realloc, preventing buffer overflow. The original buffer is f->nsubf*sizeof *subf bytes (oldsize) large. Once it's full, a new buffer of (f->nsubf+DSUBF)*sizeof *subf (newsize) is mallocated. Unfortunately memmove() reads (newsize) bytes from the original (oldsize) buffer, causing a buffer overflow. By switching to realloc(), we don't need to do buffer size calculation, memmoving, and freeing of the original buffer. Change-Id: Ibf85bc06abe1c8275b11acb1d7d346a14291d2cd Reviewed-on: https://plan9port-review.googlesource.com/1520 Reviewed-by: Gleydson Soares <gsoares@gmail.com>
- Actions:
- History | Blame | Raw File
1 #include <u.h>2 #include <libc.h>3 #include <draw.h>5 static int fontresize(Font*, int, int, int);6 #if 07 static int freeup(Font*);8 #endif10 #define PJW 0 /* use NUL==pjw for invisible characters */12 static Rune empty[] = { 0 };13 int14 cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)15 {16 int i, th, sh, h, ld, w, rw, wid, nc;17 char *sp;18 Rune r, *rp, vr;19 ulong a;20 Cacheinfo *c, *tc, *ec;22 if(ss){23 sp = *ss;24 rp = empty;25 }else{26 sp = "";27 rp = *rr;28 }29 wid = 0;30 *subfontname = 0;31 for(i=0; i<max && (*sp || *rp); sp+=w, rp+=rw){32 if(ss){33 r = *(uchar*)sp;34 if(r < Runeself)35 w = 1;36 else{37 w = chartorune(&vr, sp);38 r = vr;39 }40 rw = 0;41 }else{42 r = *rp;43 w = 0;44 rw = 1;45 }47 sh = (17 * (uint)r) & (f->ncache-NFLOOK-1);48 c = &f->cache[sh];49 ec = c+NFLOOK;50 h = sh;51 while(c < ec){52 if(c->value==r && c->age)53 goto Found;54 c++;55 h++;56 }58 /*59 * Not found; toss out oldest entry60 */61 a = ~0;62 th = sh;63 tc = &f->cache[th];64 while(tc < ec){65 if(tc->age < a){66 a = tc->age;67 h = th;68 c = tc;69 }70 tc++;71 th++;72 }74 if(a && (f->age-a)<500){ /* kicking out too recent; resize */75 nc = 2*(f->ncache-NFLOOK) + NFLOOK;76 if(nc <= MAXFCACHE){77 if(i == 0)78 fontresize(f, f->width, nc, f->maxdepth);79 /* else flush first; retry will resize */80 break;81 }82 }84 if(c->age == f->age) /* flush pending string output */85 break;87 ld = loadchar(f, r, c, h, i, subfontname);88 if(ld <= 0){89 if(ld == 0)90 continue;91 break;92 }93 c = &f->cache[h]; /* may have reallocated f->cache */95 Found:96 wid += c->width;97 c->age = f->age;98 cp[i] = h;99 i++;100 }101 if(ss)102 *ss = sp;103 else104 *rr = rp;105 *wp = wid;106 return i;107 }109 void110 agefont(Font *f)111 {112 Cacheinfo *c, *ec;113 Cachesubf *s, *es;115 f->age++;116 if(f->age == 65536){117 /*118 * Renormalize ages119 */120 c = f->cache;121 ec = c+f->ncache;122 while(c < ec){123 if(c->age){124 c->age >>= 2;125 c->age++;126 }127 c++;128 }129 s = f->subf;130 es = s+f->nsubf;131 while(s < es){132 if(s->age){133 if(s->age<SUBFAGE && s->cf->name != nil){134 /* clean up */135 if(display==nil || s->f != display->defaultsubfont)136 freesubfont(s->f);137 s->cf = nil;138 s->f = nil;139 s->age = 0;140 }else{141 s->age >>= 2;142 s->age++;143 }144 }145 s++;146 }147 f->age = (65536>>2) + 1;148 }149 }151 static Subfont*152 cf2subfont(Cachefont *cf, Font *f)153 {154 int depth;155 char *name;156 Subfont *sf;158 name = cf->subfontname;159 if(name == nil){160 depth = 0;161 if(f->display){162 if(f->display->screenimage)163 depth = f->display->screenimage->depth;164 }else165 depth = 8;166 name = subfontname(cf->name, f->name, depth);167 if(name == nil)168 return nil;169 cf->subfontname = name;170 }171 sf = lookupsubfont(f->display, name);172 return sf;173 }175 /* return 1 if load succeeded, 0 if failed, -1 if must retry */176 int177 loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname)178 {179 int i, oi, wid, top, bottom;180 int pic; /* need >16 bits for adding offset below */181 Fontchar *fi;182 Cachefont *cf;183 Cachesubf *subf, *of;184 uchar *b;186 pic = r;187 Again:188 for(i=0; i<f->nsub; i++){189 cf = f->sub[i];190 if(cf->min<=pic && pic<=cf->max)191 goto Found;192 }193 TryPJW:194 if(pic != PJW){195 pic = PJW;196 goto Again;197 }198 return 0;200 Found:201 /*202 * Choose exact or oldest203 */204 oi = 0;205 subf = &f->subf[0];206 for(i=0; i<f->nsubf; i++){207 if(cf == subf->cf)208 goto Found2;209 if(subf->age < f->subf[oi].age)210 oi = i;211 subf++;212 }213 subf = &f->subf[oi];215 if(subf->f){216 if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){217 Toss:218 /* ancient data; toss */219 freesubfont(subf->f);220 subf->cf = nil;221 subf->f = nil;222 subf->age = 0;223 }else{ /* too recent; grow instead */224 of = f->subf;225 f->subf = realloc(of, (f->nsubf+DSUBF)*sizeof *subf);226 if(f->subf == nil){227 f->subf = of;228 goto Toss;229 }230 memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf);231 subf = &f->subf[f->nsubf];232 f->nsubf += DSUBF;233 }234 }235 subf->age = 0;236 subf->cf = nil;237 subf->f = cf2subfont(cf, f);238 if(subf->f == nil){239 if(cf->subfontname == nil)240 goto TryPJW;241 *subfontname = cf->subfontname;242 return -1;243 }245 subf->cf = cf;246 if(subf->f->ascent > f->ascent && f->display){247 /* should print something? this is a mistake in the font file */248 /* must prevent c->top from going negative when loading cache */249 Image *b;250 int d, t;251 d = subf->f->ascent - f->ascent;252 b = subf->f->bits;253 draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d)));254 draw(b, Rect(b->r.min.x, b->r.max.y-d, b->r.max.x, b->r.max.y), f->display->black, nil, b->r.min);255 for(i=0; i<subf->f->n; i++){256 t = subf->f->info[i].top-d;257 if(t < 0)258 t = 0;259 subf->f->info[i].top = t;260 t = subf->f->info[i].bottom-d;261 if(t < 0)262 t = 0;263 subf->f->info[i].bottom = t;264 }265 subf->f->ascent = f->ascent;266 }268 Found2:269 subf->age = f->age;271 /* possible overflow here, but works out okay */272 pic += cf->offset;273 pic -= cf->min;274 if(pic >= subf->f->n)275 goto TryPJW;276 fi = &subf->f->info[pic];277 if(fi->width == 0)278 goto TryPJW;279 wid = (fi+1)->x - fi->x;280 if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){281 /*282 * Flush, free, reload (easier than reformatting f->b)283 */284 if(noflush)285 return -1;286 if(f->width < wid)287 f->width = wid;288 if(f->maxdepth < subf->f->bits->depth)289 f->maxdepth = subf->f->bits->depth;290 i = fontresize(f, f->width, f->ncache, f->maxdepth);291 if(i <= 0)292 return i;293 /* c is still valid as didn't reallocate f->cache */294 }295 c->value = r;296 top = fi->top + (f->ascent-subf->f->ascent);297 bottom = fi->bottom + (f->ascent-subf->f->ascent);298 c->width = fi->width;299 c->x = h*f->width;300 c->left = fi->left;301 if(f->display == nil)302 return 1;303 flushimage(f->display, 0); /* flush any pending errors */304 b = bufimage(f->display, 37);305 if(b == 0)306 return 0;307 b[0] = 'l';308 BPLONG(b+1, f->cacheimage->id);309 BPLONG(b+5, subf->f->bits->id);310 BPSHORT(b+9, c-f->cache);311 BPLONG(b+11, c->x);312 BPLONG(b+15, top);313 BPLONG(b+19, c->x+((fi+1)->x-fi->x));314 BPLONG(b+23, bottom);315 BPLONG(b+27, fi->x);316 BPLONG(b+31, fi->top);317 b[35] = fi->left;318 b[36] = fi->width;319 return 1;320 }322 /* release all subfonts, return number freed */323 #if 0324 static325 int326 freeup(Font *f)327 {328 Cachesubf *s, *es;329 int nf;331 if(f->sub[0]->name == nil) /* font from mkfont; don't free */332 return 0;333 s = f->subf;334 es = s+f->nsubf;335 nf = 0;336 while(s < es){337 if(s->age){338 freesubfont(s->f);339 s->cf = nil;340 s->f = nil;341 s->age = 0;342 nf++;343 }344 s++;345 }346 return nf;347 }348 #endif350 /* return whether resize succeeded && f->cache is unchanged */351 static int352 fontresize(Font *f, int wid, int ncache, int depth)353 {354 Cacheinfo *i;355 int ret;356 Image *new;357 uchar *b;358 Display *d;360 ret = 0;361 if(depth <= 0)362 depth = 1;364 d = f->display;365 if(d == nil)366 goto Nodisplay;368 new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0);369 if(new == nil){370 fprint(2, "font cache resize failed: %r\n");371 abort();372 goto Return;373 }374 flushimage(d, 0); /* flush any pending errors */375 b = bufimage(d, 1+4+4+1);376 if(b == 0){377 freeimage(new);378 goto Return;379 }380 b[0] = 'i';381 BPLONG(b+1, new->id);382 BPLONG(b+5, ncache);383 b[9] = f->ascent;384 if(flushimage(d, 0) < 0){385 fprint(2, "resize: init failed: %r\n");386 freeimage(new);387 goto Return;388 }389 freeimage(f->cacheimage);390 f->cacheimage = new;391 Nodisplay:392 f->width = wid;393 f->maxdepth = depth;394 ret = 1;395 if(f->ncache != ncache){396 i = malloc(ncache*sizeof f->cache[0]);397 if(i != nil){398 ret = 0;399 free(f->cache);400 f->ncache = ncache;401 f->cache = i;402 }403 /* else just wipe the cache clean and things will be ok */404 }405 Return:406 memset(f->cache, 0, f->ncache*sizeof f->cache[0]);407 return ret;408 }