ref: f7bf0ab313d2c04d29262101cc251cd80a33558b
parent: 6e30d23ceb6a4f999a9c92784a95d27627e9df10
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Jan 11 19:50:34 EST 2026
jpg: add range checks where needed this fixes a number of crashes coming from AFL, mostly around missing verification for ranges in jpeg headers, duplicated jpeg structures, and similar bugs.
--- a/sys/src/cmd/jpg/readjpg.c
+++ b/sys/src/cmd/jpg/readjpg.c
@@ -24,11 +24,11 @@
APPn =0xE0, /* Reserved for application segments */
JPGn =0xF0, /* Reserved for JPEG extensions */
COM =0xFE, /* Comment */
-
- CLAMPOFF = 300,
- NCLAMP = CLAMPOFF+700
};
+/* clamp x to 0-255 */
+#define CLAMP(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x)))
+
typedef struct Framecomp Framecomp;
typedef struct Header Header;
typedef struct Huffman Huffman;
@@ -96,8 +96,6 @@
int Vmax;
};
-static uchar clamp[NCLAMP];
-
static Rawimage *readslave(Header*, int);
static int readsegment(Header*, int*);
static void quanttables(Header*, uchar*, int);
@@ -134,24 +132,7 @@
53, 60, 61, 54, 47, 55, 62, 63 /* 56-63 */
};
-static
-void
-jpginit(void)
-{- int k;
- static int inited;
- if(inited)
- return;
- inited = 1;
- for(k=0; k<CLAMPOFF; k++)
- clamp[k] = 0;
- for(; k<CLAMPOFF+256; k++)
- clamp[k] = k-CLAMPOFF;
- for(; k<NCLAMP; k++)
- clamp[k] = 255;
-}
-
static
void*
jpgmalloc(Header *h, int n, int clear)
@@ -245,7 +226,6 @@
werrstr("ReadJPG: unknown color space");return nil;
}
- jpginit();
h = malloc(sizeof(Header));
array = malloc(2*sizeof(Rawimage*));
if(h==nil || array==nil){@@ -320,9 +300,15 @@
case SOF:
case SOF2:
+ if(header->mode != 0)
+ jpgerror(header, "ReadJPG: duplicate SOF header");
header->Y = int2(b, 1);
header->X = int2(b, 3);
header->Nf = b[5];
+ if(header->X == 0 || header->Y == 0)
+ jpgerror(header, "ReadJPG: image must have 1 or 3 components");
+ if(header->Nf != 1 && header->Nf != 3)
+ jpgerror(header, "ReadJPG: image must have 1 or 3 components");
for(i=0; i<header->Nf; i++){header->comp[i].C = b[6+3*i+0];
nibbles(b[6+3*i+1], &H, &V);
@@ -334,6 +320,8 @@
header->comp[i].H = H;
header->comp[i].V = V;
header->comp[i].Tq = b[6+3*i+2];
+ if(header->comp[i].Tq > 3)
+ jpgerror(header, "ReadJPG: invalid quantization table index");
}
header->mode = m;
header->sf = b;
@@ -511,8 +499,11 @@
/* initialize HUFFVAL */
t->val = jpgmalloc(h, nsize*sizeof(int), 1);
- for(i=0; i<nsize; i++)
+ for(i=0; i<nsize; i++){t->val[i] = b[17+i];
+ if(Tc == 0 && t->val[i] > 15 || (t->val[i] & 0xF) > 14)
+ jpgerror(h, "ReadJPG: corrupt Huffman table");
+ }
/* flow chart C-3 */
t->code = jpgmalloc(h, (nsize+1)*sizeof(int), 1);
@@ -676,6 +667,8 @@
/* so if both have 3 we know scan is Y Cb Cr and there's no need to */
/* reorder */
nibbles(ss[2+2*comp], &Td[comp], &Ta[comp]);
+ if(Td[comp] > 3 || Ta[comp] > 3)
+ jpgerror(h, "ReadJPG: invalid Huffman table index");
H[comp] = h->comp[comp].H;
V[comp] = h->comp[comp].V;
nblock = H[comp]*V[comp];
@@ -849,7 +842,7 @@
ss = h->ss;
Ns = ss[0];
Nf = h->Nf;
- if(Ns!=3 && Ns!=1)
+ if(Ns!=3 && Ns!=1 || Nf != 3 && Nf != 1)
jpgerror(h, "ReadJPG: image must have 1 or 3 components");
image = jpgmalloc(h, sizeof(Rawimage), 1);
@@ -881,6 +874,8 @@
if(h->comp[comp].V > h->Vmax)
h->Vmax = h->comp[comp].V;
}
+ if(h->Hmax == 0 || h->Vmax == 0)
+ jpgerror(h, "ReadJPG: invalid sampling factors");
h->nacross = ((h->X+(8*h->Hmax-1))/(8*h->Hmax));
h->ndown = ((h->Y+(8*h->Vmax-1))/(8*h->Vmax));
nmcu = h->nacross*h->ndown;
@@ -916,6 +911,8 @@
for(i=0; i<Ns; i++){nibbles(ss[2+2*i], &Td[i], &z); /* z is ignored */
+ if(Td[i] > 3)
+ jpgerror(h, "ReadJPG: invalid Huffman table index");
DC[i] = 0;
for(j=0; j<h->Nf; j++)
if(h->comp[j].C == ss[1+2*i]){@@ -944,6 +941,8 @@
for(y=0; y<nver; y++){ for(x=0; x<nhor; x++){bn = (x/H + h->nacross*(y/V))*H*V + H*(y%V) + x%H;
+ if(bn < 0 || bn >= h->naccoeff[comp])
+ jpgerror(h, "ReadJPG: block number out of range");
if(Ah == 0){t = decode(h, dcht);
diff = receive(h, t);
@@ -1011,6 +1010,8 @@
jpgerror(h, "ReadJPG: illegal Ns>1 in progressive AC scan");
Ss = ss[1+2];
Se = ss[2+2];
+ if(Ss >= 64 || Se >= 64)
+ jpgerror(h, "ReadJPG: invalid coefficient range in progressive AC scan");
H = h->comp[comp].H;
V = h->comp[comp].V;
@@ -1026,6 +1027,8 @@
h->sr = 0;
h->peek = -1;
nibbles(ss[1+1], &z, &Ta); /* z is thrown away */
+ if(Ta > 3)
+ jpgerror(h, "ReadJPG: invalid Huffman table index");
ri = h->ri;
@@ -1045,6 +1048,8 @@
/* arrange blockno to be in same sequence as original scan calculation. */
tmcu = x/H + (nacross/H)*(y/V);
blockno = tmcu*H*V + H*(y%V) + x%H;
+ if(blockno < 0 || blockno >= h->naccoeff[comp])
+ jpgerror(h, "ReadJPG: block number out of range");
acc = h->accoeff[comp][blockno];
k = Ss;
do {@@ -1108,6 +1113,8 @@
jpgerror(h, "ReadJPG: illegal Ns>1 in progressive AC scan");
Ss = ss[1+2];
Se = ss[2+2];
+ if(Ss >= 64 || Se >= 64)
+ jpgerror(h, "ReadJPG: invalid coefficient range in progressive AC scan");
H = h->comp[comp].H;
V = h->comp[comp].V;
@@ -1123,6 +1130,8 @@
h->sr = 0;
h->peek = -1;
nibbles(ss[1+1], &z, &Ta); /* z is thrown away */
+ if(Ta > 3)
+ jpgerror(h, "ReadJPG: invalid Huffman table index");
ri = h->ri;
eobrun = 0;
@@ -1140,6 +1149,8 @@
/* arrange blockno to be in same sequence as original scan calculation. */
tmcu = x/H + (nacross/H)*(y/V);
blockno = tmcu*H*V + H*(y%V) + x%H;
+ if(blockno < 0 || blockno >= h->naccoeff[comp])
+ jpgerror(h, "ReadJPG: block number out of range");
acc = ac[blockno];
if(eobrun > 0){if(nzeros > 0)
@@ -1172,7 +1183,7 @@
}
break;
}
- for(i=0; i<16; k++){+ for(i=0; i<16 && k<=Se; k++){increment(h, acc, k, qt[k]<<Al);
if(acc[k] == 0)
i++;
@@ -1221,6 +1232,8 @@
jpgerror(h, "ReadJPG: bad component index in scan header");
if(Ss == 0){+ if(Al > 13)
+ jpgerror(h, "ReadJPG: invalid successive approximation for DC");
progressivedc(h, comp, Ah, Al);
return;
}
@@ -1260,7 +1273,7 @@
k = 0;
for(y=0; y<dy; y++){ for(x=0; x<dx; x++){- r = clamp[(data[k+x]+128)+CLAMPOFF];
+ r = CLAMP(data[k+x] + 128);
pic[pici+x] = r;
}
pici += h->X;
@@ -1302,9 +1315,9 @@
bp = bpic+pici;
if(colorspace == CYCbCr)
for(x=0; x<dx; x++){- *rp++ = clamp[*p0++ + 128 + CLAMPOFF];
- *gp++ = clamp[*p1++ + 128 + CLAMPOFF];
- *bp++ = clamp[*p2++ + 128 + CLAMPOFF];
+ *rp++ = CLAMP(*p0++ + 128);
+ *gp++ = CLAMP(*p1++ + 128);
+ *bp++ = CLAMP(*p2++ + 128);
}
else
for(x=0; x<dx; x++){@@ -1314,9 +1327,9 @@
r = Y+c1*Cr;
g = Y-c2*Cb-c3*Cr;
b = Y+c4*Cb;
- *rp++ = clamp[(r>>11)+CLAMPOFF];
- *gp++ = clamp[(g>>11)+CLAMPOFF];
- *bp++ = clamp[(b>>11)+CLAMPOFF];
+ *rp++ = CLAMP(r >> 11);
+ *gp++ = CLAMP(g >> 11);
+ *bp++ = CLAMP(b >> 11);
}
pici += h->X;
k += 8;
@@ -1366,9 +1379,9 @@
x2 = 0;
for(x=0; x<dx; x++){ if(colorspace == CYCbCr){- rpic[pici+x] = clamp[data0[b0][y0+x0++*H0/Hmax] + 128 + CLAMPOFF];
- gpic[pici+x] = clamp[data1[b1][y1+x1++*H1/Hmax] + 128 + CLAMPOFF];
- bpic[pici+x] = clamp[data2[b2][y2+x2++*H2/Hmax] + 128 + CLAMPOFF];
+ rpic[pici+x] = CLAMP(data0[b0][y0+x0++*H0/Hmax] + 128);
+ gpic[pici+x] = CLAMP(data1[b1][y1+x1++*H1/Hmax] + 128);
+ bpic[pici+x] = CLAMP(data2[b2][y2+x2++*H2/Hmax] + 128);
}else{Y = (data0[b0][y0+x0++*H0/Hmax]+128)<<11;
Cb = data1[b1][y1+x1++*H1/Hmax];
@@ -1376,9 +1389,9 @@
r = Y+c1*Cr;
g = Y-c2*Cb-c3*Cr;
b = Y+c4*Cb;
- rpic[pici+x] = clamp[(r>>11)+CLAMPOFF];
- gpic[pici+x] = clamp[(g>>11)+CLAMPOFF];
- bpic[pici+x] = clamp[(b>>11)+CLAMPOFF];
+ rpic[pici+x] = CLAMP(r >> 11);
+ gpic[pici+x] = CLAMP(g >> 11);
+ bpic[pici+x] = CLAMP(b >> 11);
}
if(x0*H0/Hmax >= 8){x0 = 0;
@@ -1407,6 +1420,8 @@
int code, v, cnt, sr, i;
int *maxcode;
+ if(t->val == nil)
+ jpgerror(h, "ReadJPG: undefined Huffman table");
maxcode = t->maxcode;
if(h->cnt < 8)
nextbyte(h, 0);
--
⑨