ref: f7882376011a2b22b1478f0c2163092888b70df8
parent: 62abdae9c3475f4fe5971c3fc172e7ad374c42a3
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Mar 28 03:36:50 EDT 2026
git: double check for overflows and sign extension in pack parsing
--- a/sys/src/cmd/git/pack.c
+++ b/sys/src/cmd/git/pack.c
@@ -401,8 +401,8 @@
return d.len;
}
-static vlong
-readvint(char *p, char **pp)
+static int
+readvint(char *p, char *ep, char **pp)
{int s, c;
vlong n;
@@ -410,12 +410,13 @@
s = 0;
n = 0;
do {+ if(p == ep)
+ return -1;
c = *p++;
- n |= (c & 0x7f) << s;
+ n |= (vlong)(c & 0x7f) << s;
s += 7;
} while (c & 0x80 && s < 63);
*pp = p;
-
return n;
}
@@ -423,20 +424,23 @@
applydelta(Object *dst, Object *base, char *d, int nd)
{char *r, *b, *ed, *er;
- int n, nr, c;
- vlong o, l;
+ vlong o, l, n, nr, c;
ed = d + nd;
b = base->data;
- n = readvint(d, &d);
- if(n != base->size){+ n = readvint(d, ed, &d);
+ if(n == -1 || n >= 1LL << 31 || n != base->size){ werrstr("mismatched source size");return -1;
}
- nr = readvint(d, &d);
+ nr = readvint(d, ed, &d);
+ if(nr == -1 || n >= 1LL << 31){+ werrstr("invalid pack: %r");+ return -1;
+ }
r = emalloc(nr + 64);
- n = snprint(r, 64, "%T %d", base->type, nr) + 1;
+ n = snprint(r, 64, "%T %lld", base->type, nr) + 1;
dst->all = r;
dst->type = base->type;
dst->data = r + n;
@@ -451,18 +455,18 @@
o = 0;
l = 0;
/* Offset in base */
- if(d != ed && (c & 0x01)) o |= (*d++ << 0) & 0x000000ff;
- if(d != ed && (c & 0x02)) o |= (*d++ << 8) & 0x0000ff00;
- if(d != ed && (c & 0x04)) o |= (*d++ << 16) & 0x00ff0000;
- if(d != ed && (c & 0x08)) o |= (*d++ << 24) & 0xff000000;
+ if(d != ed && (c & 0x01)) o |= (*d++ & 0xff) << 0;
+ if(d != ed && (c & 0x02)) o |= (*d++ & 0xff) << 8;
+ if(d != ed && (c & 0x04)) o |= (*d++ & 0xff) << 16;
+ if(d != ed && (c & 0x08)) o |= (*d++ & 0xff) << 24;
/* Length to copy */
- if(d != ed && (c & 0x10)) l |= (*d++ << 0) & 0x0000ff;
- if(d != ed && (c & 0x20)) l |= (*d++ << 8) & 0x00ff00;
- if(d != ed && (c & 0x40)) l |= (*d++ << 16) & 0xff0000;
+ if(d != ed && (c & 0x10)) l |= (*d++ & 0xff) << 0;
+ if(d != ed && (c & 0x20)) l |= (*d++ & 0xff) << 8;
+ if(d != ed && (c & 0x40)) l |= (*d++ & 0xff) << 16;
if(l == 0) l = 0x10000;
- if(o + l > base->size){+ if(o < 0 || l < 0 || o + l > base->size){ werrstr("garbled delta: out of bounds copy");return -1;
}
@@ -632,7 +636,7 @@
{"tag", GTag}, {nil},};
- char *d, *s, *e;
+ char *d, *s, *e, *ed;
vlong sz, n;
int l;
@@ -641,6 +645,7 @@
return -1;
s = d;
+ ed = d + n;
o->type = GNone;
for(p = types; p->tag; p++){l = strlen(p->tag);
@@ -647,7 +652,7 @@
if(strncmp(s, p->tag, l) == 0){s += l;
o->type = p->type;
- while(!isspace(*s))
+ while(s != ed && !isspace(*s))
s++;
break;
}
@@ -975,7 +980,7 @@
t->mode |= DMDIR;
t->name = p;
p = memchr(p, 0, ep - p);
- if(*p++ != 0 || ep - p < sizeof(t->h.h))
+ if(p == nil || *p++ != 0 || ep - p < sizeof(t->h.h))
sysfatal("malformed tree %H, remaining %d (%s)", o->hash, (int)(ep - p), p);memcpy(t->h.h, p, sizeof(t->h.h));
p += sizeof(t->h.h);
--
⑨